# Archives

Archives / 2008
• ## Powershell output capturing and text wrapping: strange quirks... solved!

### Summary

To capture (transcript) all output of a Powershell script, and control the way textwrapping is done, use the following approach from for exmaple a batch file or your Powershell code:

PowerShell -Command  "$host.UI.RawUI.BufferSize = new-object System.Management.Automation.Host.Size(512,50);"c:\temp\testoutputandcapture.ps1&quot; -argument"A value&quot;&quot; &gt;c:\temp\out.txt 2&gt;&amp;1 </strong></p> <p>Note the '' (backtick characters). ### The problem: output capture and text wrap Powershell is a great language, but I have been fighting and fighting with Powershell on two topics: • to capture the output • to get it output text in the max width that I want without unexpected wrapping After reading the manuals you would think that the PowerShell transcripting possibilities are your stairways to heaven. You just start capturing output as follows: • start-transcript "c:\temp\transcript.txt" • do your thing • stop-transcript Try this with the following sample file c:\temp\testoutputandcapture.ps1: Start-Transcript "c:\temp\transcript.txt" function Output { Write-Host "Write-Host" Write-Output "Write-Output" cmd.exe /c "echo Long long long long long long long long yes very long output from external command" PowerShell -Command "Write-Error 'error string'" } Output Stop-Transcript When you execute this script you get the following output:  PS C:\temp> C:\temp\testoutputandcapture.ps1 Transcript started, output file is c:\temp\transcript.txt Write-Host Write-Output Long long long long long long long long yes very long output from external commandWrite-Error 'error string' : error string Transcript stopped, output file is C:\temp\transcript.txt If we now look at the generated transcript file c:\temp\transcript.txt:  ********************** Windows PowerShell Transcript Start Start time: 20081209001108 Username : VS-D-SVDOMOSS-1\Administrator Machine : VS-D-SVDOMOSS-1 (Microsoft Windows NT 5.2.3790 Service Pack 2) ********************** Transcript started, output file is c:\temp\transcript.txt Write-Host Write-Output ********************** Windows PowerShell Transcript End End time: 20081209001108 ********************** The output from the external command (the texts Long long long long long long long long yes very long output from external command and Write-Error 'error string' : error string) is not captured!!! ### Step one: piping output of external commands This can be solved by appending | Write-Output to external commands: Start-Transcript 'c:\temp\transcript.txt' function Output { Write-Host "Write-Host" Write-Output "Write-Output" cmd.exe /c "echo Long long long long long long long long yes very long output from external command" | Write-Output PowerShell -Command "Write-Error 'error string'" | Write-Output } Output Stop-Transcript This will result in the following output:  PS C:\temp> C:\temp\testoutputandcapture.ps1 Transcript started, output file is c:\temp\transcript.txt Write-Host Write-Output Long long long long long long long long yes very long output from external commandWrite-Error 'error string' : error string Transcript stopped, output file is C:\temp\transcript.txt Note that the error string Write-Error 'error string' : error string is not in red anymore. The resulting transcript file c:\temp\transcript.txt now looks like:  ********************** Windows PowerShell Transcript Start Start time: 20081209220137 Username : VS-D-SVDOMOSS-1\Administrator Machine : VS-D-SVDOMOSS-1 (Microsoft Windows NT 5.2.3790 Service Pack 2) ********************** Transcript started, output file is c:\temp\transcript.txt Write-Host Write-Output Long long long long long long long long yes very long output from external commandWrite-Error 'error string' : error string ********************** Windows PowerShell Transcript End End time: 20081209220139 ********************** This is what we want in the transcript file, everything is captured, but we need to put | Write-Output after every external command. This is way to cumbersome if you have large scripts. For example in our situation there is a BuildAndPackageAll.ps1 script that includes a lot of files and cosists in totla of thousands of lines of Powershell code. There must be a better way... ### Transcripting sucks, redirection? Ok, so transcript just does not do the job of capturing all output. Lets look at another method: good old redirection. We go back to our initial version of the script, and do c:\temp\testoutputandcapture.ps1 > c:\temp\out.txt. This results in a c:\temp\out.txt file with the following contents:  Transcript started, output file is c:\temp\transcript.txt Write-Output Long long long long long long long long yes very long output from external commandWrite-Error 'error string' : error string Transcript stopped, output file is C:\temp\transcript.txt We are missing the Write-Host output! Actually, the Write-Host is the only line ending up in the transcript file;-) This is not good enough, so another try, but now using the Powershell command-line host on the little modified script c:\temp\testoutputandcapture.ps1 that will showcase our next problem: function Output { Write-Host "Write-Host" Write-Output "Write-Output Long long long long long long long long yes very long output from Write-Output" cmd.exe /c "echo Long long long long long long long long yes very long output from external command" PowerShell -Command "Write-Error 'error string'" } Output  We now do: Powershell -Command "c:\temp\testoutputandcapture.ps1" > c:\temp\out.txt 2>&1 (2>&1 means: redirect stderr to stdout). We capture stderr as well, you never know where it is good for. This results in:  Write-Host Write-Output Long long long long long long long l ong yes very long output from Write-Output Long long long long long long long long yes very long output from external commandWrite-Error 'error string' : error string ### I hate automatic text wrapping As you may notice some strange things happen here: • A long output line generated by PowerShell code is wrapped (at 50 characters in the above case) • A long line generated by an external command, called from Powershell is not truncated The reason the Powershell output is wrapped at 50 characters is because the dos box I started the command from is set to 50 characters wide. I did this on purpose to proof a case. Ok, so you can set your console window really wide, so no truncation is done? True. But you are not always in control of that. For example if you call your Powershell script from a batch file which is executed through Windows Explorer or through an external application like in my case CruiseControl.Net where I may provide an external command. ### Powershell -PSConfigFile?... no way! I hoped the solution would be in an extra parameter to the Powershell command-line host: -PSConfigFile. You can specify a Powershell console configuration XML file here that you can generate with the command Export-Console ConsoleConfiguration. This results in the ConsoleConfiguration.psc1 XML file:   1.0  I searched and searched for documentation on extra configuration like console width or something, but documentation on this is really sparse. So I fired up good old Reflector. After some drilling I ended up with the following code for the Export-Console command:  internal static void WriteToFile(MshConsoleInfo consoleInfo, string path) { using (tracer.TraceMethod()) { _mshsnapinTracer.WriteLine("Saving console info to file {0}.", new object[] { path }); XmlWriterSettings settings = new XmlWriterSettings(); settings.Indent = true; settings.Encoding = Encoding.UTF8; using (XmlWriter writer = XmlWriter.Create(path, settings)) { writer.WriteStartDocument(); writer.WriteStartElement("PSConsoleFile"); writer.WriteAttributeString("ConsoleSchemaVersion", "1.0"); writer.WriteStartElement("PSVersion"); writer.WriteString(consoleInfo.PSVersion.ToString()); writer.WriteEndElement(); writer.WriteStartElement("PSSnapIns"); foreach (PSSnapInInfo info in consoleInfo.ExternalPSSnapIns) { writer.WriteStartElement("PSSnapIn"); writer.WriteAttributeString("Name", info.Name); writer.WriteEndElement(); } writer.WriteEndElement(); writer.WriteEndElement(); writer.WriteEndDocument(); writer.Close(); } _mshsnapinTracer.WriteLine("Saving console info succeeded.", new object[0]); } } So the XML that we already saw is all there is... a missed chance there. ### A custom command-line PowerShell host? I have written a few Powershell hosts already, for example one hosted into Visual Studio, and there I encountered the same wrapping issue which I solved by the following implementation of the PSHostRawUserInterface: using System; using System.Management.Automation.Host; namespace Macaw.SolutionsFactory.DotNet3.IntegratedUI.Business.Components.Powershell { /// <summary> /// Implementation of PSHostRawUserInterface. /// </summary> public class PowershellHostRawUI : PSHostRawUserInterface { :  public override Size BufferSize { get { // The width is the width of the output, make it very wide! return new Size(512,1); } set { throw new Exception("BufferSize - set: The method or operation is not implemented."); } }  : } } I solved transcripting in my own Powershell hosts by capturing all text output done by Powershell through custom implemented functions for the PSHostUserInterface you need to implement anyway, works like a breeze. ### The solution, without custom host... I was just getting started to solve the transcripting and wrapping issues by implementing again a Powershell host, but now a command-line Powershell host when I did one last digging step. What is you can set the BufferSize at runtime in your Powershell code. And the answer is.... yes you can! Through the$host Powershell variable: $host.UI.RawUI.BufferSize = new-object System.Management.Automation.Host.Size(512,50). This says that the output may be max 512 chars wide, the height may not be 1 (as in my code), bu this height value is not important in this case. It is used for paging in a interactive shell. And this last statement gives us full control and solves all our transcripting and wrapping issues: PowerShell -Command "$host.UI.RawUI.BufferSize = new-object System.Management.Automation.Host.Size(512,50); "c:\temp\testoutputandcapture.ps1" -argument "A value"" >c:\temp\out.txt 2>&1

And this concludes a long journey into the transcripting and wrapping caves of Powershell. I hope this will save you the days of searching we had to put into it to tame the great but naughty Powershell beast.

• ## Powershell: Generate simple XML from text, useful for CruiseControl.Net merge files

I had the problem that I need to include ordinary text files into the CruiseControl.Net build output log file. This log file is a merge of multiple files in xml format. So I needed to get some text files into a simple xml format. I ended up with the following Powershell code to convert an input text file to a simple output xml file

Powershell code:

function Convert-XmlString
{
param
(
[string]$text ) # Escape Xml markup characters ( http://www.w3.org/TR/2006/REC-xml-20060816/#syntax)$text.replace('&', '&amp;').replace("'", '&apos;').replace('"', '&quot;').replace('<', '&lt;').replace('>', '&gt;')
}

function Convert-TextToXml
{
param
(
$rootNode = 'root',$node = 'node',
$path =$(Throw 'Missing argument: path'),
$destination =$(Throw 'Missing argument: destination')
)
Get-Content -Path $path | ForEach-Object <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; -Begin { <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Write-Output &quot;&lt;$rootNode&gt;&quot; <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; }
-Process {
Write-Output "  <$node>$(Convert-XmlString -text $_)</$node>"
}
-End {
Write-Output "</$rootNode>" } | Set-Content -Path$destination -Force
}

You can call this code as follows:

Convert-TextToXml -rootNode 'BuildAndPackageAll' -node 'message' -path 'c:\temp\in.txt' -destination 'c:\temp\out.xml'

where the file c:\temp\in.txt:

This is line 1
This is a line with the characters <, >, &, ' and "
This is line 3

Will be converted the the file c:\temp\out.xml:

<BuildAndPackageAll>
<message>This is line 1</message>
<message>This is a line with the characters &lt;, &gt;, &amp;, &apos; and &quot;</message>
<message>This is line 3</message>
</BuildAndPackageAll>

• ## Moss 2007 StsAdm Reference Poster by Microsoft

All SharePoint developers and administrators will be familiar with the Stsadm.exe command line tool in the bin folder of the "12 hive", normally located at: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\STSADM.EXE. This tool has many available operations and an extensibility model. For a nice poster on all available operations (Moss2007 SP1) and available properties, see http://go.microsoft.com/fwlink/?LinkId=120150.

Although Stsadm is a nice mechanism for managing SharePoint, we really need a PowerShell interface to do all these same operations. There are already some first small PowerShell libraries available, and also Gary Lapointe is starting a PowerShell library. See this blog post for his first steps in this direction.

• ## Notes from PDC Session: Extending SharePoint Online

* REMOVED SOME HARSH WORDS ON THE SESSION *

I took some notes, and augmented it with some of my own thoughts and information.

-------

SharePoint Online provides:

Managed Services on the net
- No server deployment needed, just a few clicks to bring your instance up and running
- Unified admin center for online services
- Single sign on system, no federated active directory yet

Enterprise class Reliability
- Good uptime
- Anti virus
-...

SharePoint online is available in two tastes: standard (hosted in the cloud) and dedicated (on premises)

Standard is most interesting I think: minimum of 5 seats, max 1TB storage.

On standard we have no custom code deployment, so we need to be inventive!

SharePoint Online is a subset of the standard SharePoint product (extensive slide on this in the slide deck, no access to that yet)

SharePoint online is for intranet, not for anonymous internet publishing.

• ## Reduce the size of a virtual hard disk before delivery for reuse

When delivering a virtual hard disk to your team to build their virtual machines on I perform the following steps to minimize the size of the virtual hard disk. It is assumed that Virtual Server 2005 R2 SP1 is installed.

1. Make sure you merged the Undo disks, and that differencing disks are merged with their parent disks
2. Disable undo disks
3. Start the virtual machine to compact
4. In the virtual machine download CCleaner on http://www.ccleaner.com . This is a great tool to clean your disk from history files, cache files etc. I run this almost daily on my virtual machines and my host system. Thanks Danny for introducing me to this great tool.
Quote from their website:
CCleaner is a freeware system optimization and privacy tool. It removes unused files from your system - allowing Windows to run faster and freeing up valuable hard disk space. It also cleans traces of your online activities such as your Internet history. But the best part is that it's fast (normally taking less than a second to run) and contains NO Spyware or Adware! :)

During installation beware of the option to install the Yahoo toolbar, you often overlook this co-packaging options from Microsoft, Google and Yahoo:
5. In the virtual machine run CCleaner with the options you prefer, my options are:
6. Shut down the virtual machine
7. Mount the virtual hard disk to compact using vhdmount (part of Virtual Server 2005 R2 SP1):
"C:\Program Files\Microsoft Virtual Server\Vhdmount\vhdmount" /p “drive:\folder\YourVirtualHarddiskToCompress.vhd”
8. Go to Start > My Computer; Right-click and select Manage. Now defragment the disk mounted in step 6
9. "C:\Program Files\Microsoft Virtual Server\Vhdmount\vhdmount" /u /c “drive:\folder\YourVirtualHarddiskToCompress.vhd”
10. Now start your virtual machine, and mount the ISO image C:\Program Files\Microsoft Virtual Server\Virtual Machine Additions\Precompact.iso. I personally use VMRCPlus to mount the ISO, right-click on CD-Drive and select Attach Media Image file… as shown in the screenshot below
11. When you navigate to the drive where the ISO image is mounted, the precompaction starts. The precompaction writes zero’s in all unused space in the disk, so the disk can be compacted in the next steps.
12. Shut down the virtual machine
13. Now start compaction of the virtual disk. This can be done in VirtualPC 2007, in the administrative web Virtual Server 2005, or in VMRCPlus, which I use here. Navigate to Tools > Virtual Disks > Inspect Virtual Hard disk, select your vhd to compact and select disk operation Compact
14. Done! Make your virtual hard disk read only, and start creating differencing disks based on your new base disk.

• ## VirtualPC/Virtual Server machine at higher resolution than 1600x1200!

I have always been so annoyed by the fact that on my laptop with 1920x1200 resolution I could only get a connection to my virtual machines at a resolution of 1600x1200, the max resolution by the emulates S3 graphics board, resulting in two 160 pixesl wide black bars on the left and right sides. But on Vista I did get a connection on higher resolutions, after some searching I found that the old Remote Desktop Connection software of XP (SP2) was the problem. Upgrade it to version 6 and you worries are over. See: http://support.microsoft.com/kb/925876/en-us. Happy virtual development!

• ## SharePoint Content Management Package (CMP) explorer

Ronalus has created a great small utility to explore the contents of SharePoint Content Management Pages called Content Migration Package Explorer.

This tool can be used to investigate the data exported by the SharePoint Content Migration API. You can create an export either with stsadm.exe, or with custom code.

As example for this weblog I exported a simple site containing some test data using the following command:

Stsadm.exe –o export –url http://wss3dev/FlexShop -filename c:\temp\FlexShop -nofilecompression

We now have a folder containing the output files, a set XML files and other files:

If we fire up the Content Migration Package Explorer we get the following startup screen:

You can now enter the export folder and browse through the exported information using a simple to use explorer, see below for some screenshots:

• ## SharePoint development: handy little utility to get GUID’s and Attribute names

I just stumbled accross a handy little utility that is really handy during SharePoint development: Show List and ViewGUIDs.

Type a Site URL, and select “Display Lists Titles and Ids”. From the list of lists you can select a list GUID, and with right-click copy it to the List ID input field.

After clicking “Display Views” you see the available list views. Again you can select a view guid, and with right-click copy it to the View input field.

Select “Display Items” to display the list items in the view.

With a click on “Display default List Attribute Names” de internal names of the fields in the list are displayed.

Very useful if you don't have tools like SharePoint Explorer or SharePoint Inspector installed, or if you find those tools too large/slow/complex to get some GUIDs and name information fast.