# Tuesday, May 20, 2008

I have two machines at home here, one is a Vista SP1 laptop, the other an XP SP3 Desktop. The latter was recently patched with SP3 in a desperate attempt to prolong its dwindling desire to function in a reasonable fashion. It's what I call from a development box point of view, "Encrusted." Encrustation is the point at which you no longer have any idea what beta, CTP, evaluation or otherwise not recommended software is installed. It defies its digital nature by throwing up different errors each time its booted. Anyway, the SP1 Beta would not install on this machine, specifically the .NET 3.5 beta bits. I may investigate further, but frankly I think it's time for fenestrecide and a corresponding rebirth.

This led me to try updating my Vista laptop instead. If you download the VS2008 patch you'll notice it's only about 450KB. It's a stub which detects what's missing from your environment and downloads only what it needs. I found the installer to be extremely useless in terms of giving feedback over what it was doing. It just says "installing" and you have to watch a progress bar slowly creeping across with many stalls where your machine doesn't seem to be doing anything at all. This time I downloaded the separate .NET 3.5  SP1 beta bits which size about 220MB. I installed this first and it seemed to go OK. Next, I downloaded the VS patch and let it go ahead. Again many stalls where you're wondering if it's actually going to work at all. Eventually, it failed. After some examination of the logs, I discovered that it didn't like the post-RTM patches for supporting the Reference Source server ( Shawn Burke's Blog - Configuring Visual Studio to Debug .NET ). After removing these updates, I was able to progress to past this prior point of failure but by this time it was midnight, having started the process in earnest at around 8pm. I decided to leave it to run overnight.

In the morning I had a stalled install process and a dialog notifying me that files were in use and that I should shutdown "Machine Debug Manager," "Windows Sidebar Component" and "Windows Sidebar" - Vista GUI cruft - if I wanted to avoid a reboot. I stopped the MDM service and shutdown Windows Sidebar and chose "Retry" from the options of "Retry," "Cancel" and "Ignore." Even though I hit "Retry," the bland dialog displaying "installing" now switched to "Installation failed.. rolling back" - but thankfully, it was NOT rolling back. The status bar appeared stalled for about 10 minutes then popped up the same dialog, this time with only "Windows Sidebar" listed. This time I chose "Ignore" implicitly accepting the penalty of a reboot to allow the status bar to continue its inexorable journey to the right, all the time the text telling me that the installation had failed and it was rolling back. Ten more minutes and the install succeeded. To summarise, VS seems snappier, and everything seems to work fine. I'll post more if I discover anything of interest.

The usual suspects have more information:

Beta of .NET 3.5 and VS2008 SP1 is out (Scott Guthrie)

VS2008 and .Net 3.5 SP1 Beta - Should You Fear This Release- (Scott Hanselman)

.NET 3.5 SP1 Beta- Changes Overview (Patrick Smacchia)

posted on Tuesday, May 20, 2008 10:30:14 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Thursday, May 08, 2008

After installing the new WinRM 2.0 and PowerShell 2.0 CTP bits onto my Vista/SP1 laptop, I kept getting "Access is denied" messages continually while running the "Configure-WSMan.ps1" script. Fellow MVP Richard Siddaway discovered that disabling UAC seemed to clear up the problem for him, but this is not really a good solution. I want to keep UAC enabled. It turns out also that another precondition for this error is that your machine is not joined to a domain or is in a workgroup/standalone. After some communication with the PowerShell team, who in turn talked to the WinRM team, it appears that some additional configuring is needed for machines in this situation:

If the account on the remote computer has the same logon username and password, the only extra information you need is the transport, the domain name, and the computer name. Because of User Account Control (UAC), the remote account must be a domain account and a member of the remote computer Administrators group. If the account is a local computer member of the Administrators group, then UAC does not allow access to the WinRM service. To access a remote WinRM service in a workgroup, UAC filtering for local accounts must be disabled by creating the following DWORD registry entry and setting its value to 1: [HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System] LocalAccountTokenFilterPolicy.

This is taken from http://msdn.microsoft.com/en-us/library/aa384423.aspx

This information can also be found buried in one of PowerShell 2.0's help files, accessed via:

ps> get-help about_remote_faq | more

posted on Thursday, May 08, 2008 9:57:30 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [1] Trackback
# Wednesday, April 02, 2008

Now this is barely worth blogging, but one of the things I used a lot when I was confined to cmd.exe (yes, "confined" is the word I would use, 4NT aside) is the wonderfully simple copy con filename.txt then type a few lines and end it all with CTRL+Z and enter. So, if you're a PowerShell noob and yearn for this olden-days simplicity like dead parrots pine for the fjords, then this is for you:

  1. rm function:copy-console -ea 0 # silentlycontinue   
  2. rm alias:cc -ea 0   
  3.   
  4. # encoding can be String, Unicode, Byte, BigEndianUnicode, UTF8, UTF7, Ascii   
  5. function global:copy-console {   
  6.        
  7.     param(   
  8.         [string]$Filename = $(Throw "Need output filename."),   
  9.         $Encoding = "ASCII"  
  10.     )   
  11.        
  12.     $out = [io.path]::combine($pwd$Filename)   
  13.   
  14.     $buffer = @()   
  15.     $crlf = "`r`n"  
  16.        
  17.     do {   
  18.         $line = [console]::readline()   
  19.         if ($line -eq $null) { break; }   
  20.         $buffer += $line  
  21.     } while ($TRUE)   
  22.   
  23.     $buffer | set-content $out -Encoding $Encoding  
  24. }   
  25. new-alias cc copy-console   
  26.   
  27. # Usage:   
  28. #   
  29. # PS> cc test.txt -Encoding utf8   
  30. # bleh   
  31. # moop   
  32. # vlorg   
  33. # ^Z   
  34. # PS> cat test.txt   
  35. # bleh   
  36. # ...   
  37.   

I saved this to copy-console.ps1 and aliased it to "cc." Of course, you can do whatever you want - it's probably easier to just put it into a function in your profile. Just place the script above into your profile and remember: CTRL+Z then enter to save.

UPDATE 2008-04-04: Somehow I completely broke this in my attempts to "clean it up" before posting. I've reposted a better version (imho), and implemented encoding support as suggested out in Jason's comment below ;-)

posted on Wednesday, April 02, 2008 4:28:46 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1] Trackback
# Thursday, March 27, 2008

PowerShell has several "type accelerators" which are used exactly like a casting operation. Examples of these special operators are [xml] and [wmi]. The former is used for quickly converting a string of xml into a fully-fledged System.Xml.XmlDocument object.

Often I find myself converting things to and from hexadecimal using the -f operator, but this always seemed like just a little too much typing for me. Enter the [hex] accelerator type:

image

As you can see from the source below, there's no magic here. This is just a straight cast, but I have no namespace. If I had a namespace, say, like "Nivot.PowerShell", we'd have to cast using [nivot.powershell.hex] instead of just [hex]. All of the trickery is done using operator overloads in C#. These tells .NET (and in turn, powershell) how to behave should someone try to add, subtract, remove or divide our instances.

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Text;  
  4.  
  5. public class Hex  
  6. {  
  7.     private readonly int _value = 0;  
  8.  
  9.     private Hex(int value)  
  10.     {  
  11.         _value = value;  
  12.     }  
  13.  
  14.     private Hex(string value)  
  15.     {  
  16.         _value = Convert.ToInt32(value, 16);  
  17.     }  
  18.  
  19.     public static implicit operator Hex(int value)  
  20.     {  
  21.         return new Hex(value);  
  22.     }  
  23.  
  24.     public static implicit operator int(Hex value)  
  25.     {  
  26.         return value._value;  
  27.     }  
  28.  
  29.     public static explicit operator Hex(string value)  
  30.     {  
  31.         return new Hex(value);  
  32.     }  
  33.  
  34.     public static Hex operator +(Hex op1, Hex op2)  
  35.     {  
  36.         return new Hex(op1._value + op2._value);  
  37.     }  
  38.  
  39.     public static Hex operator -(Hex op1, Hex op2)  
  40.     {  
  41.         return new Hex(op1._value - op2._value);  
  42.     }  
  43.  
  44.     public static Hex operator *(Hex op1, Hex op2)  
  45.     {  
  46.         return new Hex(op1._value * op2._value);  
  47.     }  
  48.  
  49.     public static Hex operator /(Hex op1, Hex op2)  
  50.     {  
  51.         return new Hex(op1._value / op2._value);  
  52.     }  
  53.  
  54.     public override string ToString()  
  55.     {  
  56.         return "0x" + _value.ToString("X");
  57.     }  

The next step is to tell PowerShell's formatter what to do with the new type. Here's a simple format definition that tells the formatter to call ToString() on the Hex instance. This is the method that does the conversion by calling ToString("X") on the integer field. "X" means format the integer as hexadecimal using upper case. A lower-case "x" would output the value using lower-case (if you couldn't guess ;-)).

  1. <Configuration> 
  2.   <ViewDefinitions> 
  3.     <View> 
  4.       <Name>Hex</Name> 
  5.       <ViewSelectedBy> 
  6.         <TypeName>Hex</TypeName> 
  7.       </ViewSelectedBy> 
  8.       <CustomControl> 
  9.         <CustomEntries> 
  10.           <CustomEntry> 
  11.             <CustomItem> 
  12.               <ExpressionBinding> 
  13.                 <ScriptBlock>$_.ToString()</ScriptBlock> 
  14.               </ExpressionBinding> 
  15.             </CustomItem> 
  16.           </CustomEntry> 
  17.         </CustomEntries> 
  18.       </CustomControl> 
  19.     </View> 
  20.   </ViewDefinitions> 
  21. </Configuration> 

If we don't load this format file, PowerShell just emits a couple of blank lines when you try to use it.  You'll notice from the screenshot above that the blank lines still appear. I'm not sure how to remove these - it looks pretty ugly compared to the output of the [int] object. If you want to play with this, you can download the zip file below and unzip the contents into a single folder and run "hex.ps1". I didn't bother with a full Snap-In, it just loads the DLL using reflection. It also loads the format ps1xml too. Have fun.

HexAccelerator1.zip (2.4 KB)
posted on Thursday, March 27, 2008 8:19:15 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Thursday, March 06, 2008

Just a minor thing, but this is a filter I've been using for a while now as a replacement for Get-Member. It's always annoyed me that the Get_ and Set_ methods are returned along with the actual properties. The only place that's actual useful is when you're using an object wrapped in the [xml] adapter since those objects do not expose the XmlDocument's properties in the adapted member set.

update: if you use (of course you do!) MoW's PowerTab, you can disable display of the accessor methods with $PowerTabConfig.ShowAccessorMethods = $false.

  1. filter get-memberex {   
  2.     $_ | gm | ? { -not($_.name -match "^[gs]et_.+") }   
  3. }   
  4. new-alias gmx get-memberex  
posted on Thursday, March 06, 2008 11:35:21 AM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback