# Tuesday, December 23, 2008

Just to be completely silly, I thought I’d do a series of posts on CTP3 features themed around Christmas. Hmm. That might read better as a series of Christmas posts themed around CTP3. A very original idea I’m sure, but hey, those who know me will know that I never pass up the opportunity to make a bad joke. So, without further adieu:

On the first day of Christmas, Jeffrey gave to me:

Nested Here-Strings

Here-Strings can now be embedded within each other to make it even easier to construct literal documents! Delimit any nested code between $( and ) and then continue to use a nested string within that as if it was completely stand alone. It just works! Cool, eh?

  1. function Get-CommandDefinitionHtml {  
  2.       
  3.     # this tells powershell to allow advanced features,  
  4.     # like the [validatenotnullorempty()] attribute below.  
  5.     [CmdletBinding()]  
  6.     param(  
  7.         [ValidateNotNullOrEmpty()]  
  8.         [string]$name 
  9.     )  
  10.  
  11.     $command = get-command $name 
  12.       
  13.     # Look mom! I'm a cmdlet!  
  14.     $PSCmdlet.WriteVerbose("Dumping HTML for " + $command)  
  15.       
  16. @"  
  17.     <html>  
  18.         <head>  
  19.             <title>$($command.name)</title>  
  20.         </head>  
  21.         <body>  
  22.             <table border="1">  
  23. $(  
  24.     $command.parametersets | % {  
  25. @" 
  26.  
  27.             <tr>  
  28.                 <td>$($_.name)</td>  
  29.                 <td>  
  30.                     <table border="1">  
  31.                         <tr>  
  32.                             <th colspan="8">Parameters</th>  
  33.                               
  34. $(  
  35.         $count = 0  
  36.         $_.parameters | % {  
  37.             if (0 -eq ($count % 8)) {  
  38. @"  
  39.                         </tr>  
  40.                         <tr>  
  41. "@  
  42.             }                  
  43. @"  
  44.                             <td>$($_.name)</td>  
  45. "@              
  46.             $count++  
  47.     }  
  48. )  
  49.                         </tr>                          
  50.                     </table>  
  51.                 </td>  
  52.             </tr>  
  53. "@  
  54.     }  
  55. )  
  56.             </table>          
  57.         </body>  
  58.     </html>  
  59. "@      
  60. }  
  61.  
  62. Get-CommandDefinitionHtml get-item > out.html  
  63.  
  64. # show in browser  
  65. invoke-item out.html 
posted on Tuesday, December 23, 2008 4:16:03 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Monday, December 22, 2008

To quote the completely understated download blurb:

Windows PowerShell V2 CTP3 introduces several significant features to Windows PowerShell 1.0 and Windows PowerShell V2 CTPs that extends its use, improves its usability, and allows you to control and manage the Windows environment more easily and comprehensively.

The release notes are quite extensive. Here is the section on breaking changes from CTP2:

Breaking Changes to Windows PowerShell V2 (CTP2)

The following changes in Windows PowerShell V2.0 CTP3 might prevent features designed for Windows PowerShell 2.0 CTP2 from working correctly.

  • Following cmdlets have been renamed
    • Add-Module to Import-Module
    • Get-Event to Get-WinEvent
    • *-Runspace to *-PSSession
    • Push-Runspace to Enter-PSSession
    • Pop-Runspace to Exit-PSSession
    • *-PSEvent to *-Event
    • Register-PSEvent to Register-EngineEvent
    • *-PSTransaction to *-Transaction
    • *-PSJob to *-Job
    • *-PSEventSubscriber to *-EventSubscriber
    • *-Bite to *-FileTransfer

  • Following parameters have been renamed
    • Import-LocalizedData: Culture to UICulture
    • Invoke-Command: Runspace to Session, Shell to ConfigurationName
    • Get-Job: SessionId to Id
    • Receive-Job: Runspace to Session, SessionId to Id
    • Remove-Job: SessionId to Id
    • Start-Job: Command to Scriptblock
    • Stop-Job: SessionId to Id
    • Wait-Job: SessionId to Id
    • Get-PSSession: RemoteRunspaceID to InstanceId, SessionId to Id
    • New-PSSession: Runspace to Session, Shell to ConfigurationName
    • Enter-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id, Shell to ConfigurationName
    • Remove-PSSession: Runspace to Session, RemoteRunspaceID to InstanceId, SessionId to Id

  • Following parameters have been deleted
    • Export-ModuleMember: Update, ExportList
    • Set-Service: Include, Exclude

  • Following variables have been renamed
    • $CommandLineParameters to $PSBoundParameters
    • $PSPackagePath to $PSModulePath

  • Packages have been renamed to Modules. Packages folder is now renamed to Modules folder. A module imported into another module is now treated as a nested module instead of a peer module. This allows a new module to wrap or repackage one or more existing modules.

  • "Script cmdlets" have been renamed to "advanced functions." The “cmdlet” keyword has been replaced with the “function” keyword. For script cmdlet functionality, use CmdletBinding attribute in the function’s param block. For more information, see about_functions_advanced.
  • The Config-WSMan.ps1 script in the $pshome directory has been replaced by the Enable-PSRemoting function. To configure your system for WS-Management remoting, use the following command:

Enable-PSRemoting –force

Note: If you have upgraded from the Windows PowerShell V2 CTP2 release to the Windows PowerShell V2 CTP3 release, to configure your system for WS-Management remoting, type:

Unregister-PSSessionConfiguration * -force;

Register-PSSessionConfiguration Microsoft.PowerShell –force;

Enable-PSRemoting –force

  • In the Out-GridView cmdlet, the drop-down list used to filter objects is now called “Query” instead of “Filter”.

  • The following changes have been made to Windows PowerShell Integrated Scripting Environment (ISE):
    • The name of the application has changed from “Graphical Windows PowerShell” to “Windows PowerShell Integrated Scripting Environment (ISE)”
    • The executable name has changed from “gpowershell.exe” to “powershell_ise.exe”
    • The profile name has changed from “\Users\<username>\Documents\WindowsPowerShell\Microsoft.GPowerShell_profile.ps1” to “\Users\<username>\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1”
    • The term “runspace” has been replaced with “PowerShell tab”.

Get it from http://www.microsoft.com/downloads/details.aspx?FamilyID=c913aeab-d7b4-4bb1-a958-ee6d7fe307bc – piping hot!

posted on Monday, December 22, 2008 9:59:52 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Sunday, December 21, 2008

This time around, I thought I’d show how to work with programmatically generated dynamic parameters, as opposed to the statically defined sets we saw the last time. The context here is a fairly silly Cmdlet, but it’s good enough to demonstrate the concept end to end. It’s a Cmdlet for removing a file. It takes one string parameter which is the path to the file. The dynamic parameter I’m going to add is a –Force parameter. The trick is, this parameter will only be added if the current user is an administrator (XP), or is elevated as one (Vista).

This first portion of the Cmdlet defines the usual stuff like a verb and noun. This time though, I’m using a regular class constructor. It’s not often you see constructors in simple Cmdlets because typically all one would usually do is override one or more of the three processing methods BeginProcessing, ProcessRecord and EndProcessing. In this case, I need to create a instance of a “RuntimeDefinedParameterDictionary,” which does exactly what it says on the tin. It’s a dictionary of parameters, the key being a string (the name of the parameter) and the value being a instance of a RuntimeDefinedParameter class. These classes are all members of the System.Management.Automation namespace.

In the constructor, I’m calling a generic method defined as AddDynamicParameter<T>(string name). This is only called if the current user is an admin. I’ve defined three generic helper methods which you can see a little further down below.

  1. [Cmdlet(VerbsCommon.Remove, NOUN_FILE)]  
  2. public class RemoveFileCommand : PSCmdlet, IDynamicParameters  
  3. {  
  4.     private const string NOUN_FILE      = "File";  
  5.     private const string SWITCH_FORCE   = "Force";  
  6.  
  7.     private readonly RuntimeDefinedParameterDictionary _parameters;  
  8.  
  9.     public RemoveFileCommand()  
  10.     {  
  11.         _parameters = new RuntimeDefinedParameterDictionary();  
  12.  
  13.         // we only want to add the -Force parameter if  
  14.         // the current user is an administrator  
  15.         var principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());  
  16.  
  17.         // if vista and not elevated, this will be false even  
  18.         // if you are a member of administrators.  
  19.         if (principal.IsInRole(WindowsBuiltInRole.Administrator))  
  20.         {  
  21.             this.AddDynamicParameter<SwitchParameter>(SWITCH_FORCE);  
  22.         }  
  23.     }  
  24.  
  25.     [Parameter]  
  26.     public string FilePath  
  27.     {  
  28.         get;  
  29.         set;  
  30.     }   
  31.  
  32.     protected override void EndProcessing()  
  33.     {  
  34.         // does file exist?  
  35.         if (File.Exists(FilePath))  
  36.         {  
  37.             RemoveFile();  
  38.         }  
  39.         else 
  40.         {  
  41.             WriteWarning(FilePath + " does not exist.");  
  42.         }  
  43.     } 

This is a simple piece of code who’s role is to remove the file specified by the user. I’ve omitted the actual code that would delete the file for brevity. I’m using another helper method to see if the –Force parameter has been added to the Cmdlet’s definition, and if so, was it specified by the invoker of the Cmdlet. The idea is here is that the Cmdlet will not remove the file if it’s marked Read-Only, but if –Force is specified it will remove the R/O attribute and continue as planned.

  1. private void RemoveFile()  
  2. {  
  3.     // read file attributes  
  4.     var attribs = File.GetAttributes(FilePath);  
  5.  
  6.     // is read-only attribute set?  
  7.     if ((attribs & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)  
  8.     {  
  9.         bool shouldForce;  
  10.  
  11.         // see if the dynamic switch -Force was added (and specified)  
  12.         if (TryGetSwitchParameter(SWITCH_FORCE, out shouldForce))  
  13.         {  
  14.             WriteVerbose("Force.IsPresent: " + shouldForce);  
  15.         }  
  16.  
  17.         if (shouldForce)  
  18.         {  
  19.             RemoveReadOnlyAttribute();  
  20.         }  
  21.         else 
  22.         {  
  23.             WriteWarning(FilePath + " is marked Read-Only!");  
  24.             return;  
  25.         }  
  26.     }  
  27.  
  28.     // ... code to remove file ...  

And the final piece is here. The first method GetDynamicParameters, belongs to the IDynamicParameters interface and tells PowerShell that the Cmdlet may return extra parameters not defined on the class itself. In this case, we are returning a RuntimeDefinedParameterDictionary instead of a statically defined parameters on a nested class.

  1. public object GetDynamicParameters()  
  2. {  
  3.     return _parameters;  
  4. }  
  5.  
  6. // add a simple parameter of type T to this cmdlet  
  7. private void AddDynamicParameter<T>(string name)  
  8. {  
  9.     // create a parameter of type T.  
  10.     var parameter = new RuntimeDefinedParameter  
  11.                     {  
  12.                         Name = name,  
  13.                         ParameterType = typeof (T),                                  
  14.                     };  
  15.  
  16.     // add the [parameter] attribute  
  17.     var attrib = new ParameterAttribute  
  18.                  {                               
  19.                      ParameterSetName =  
  20.                         ParameterAttribute.AllParameterSets  
  21.                  };  
  22.       
  23.     parameter.Attributes.Add(attrib);  
  24.  
  25.     _parameters.Add(name, parameter);  
  26. }  
  27.  
  28. private bool TryGetSwitchParameter(string name, out bool isPresent)  
  29. {  
  30.     RuntimeDefinedParameter parameter;  
  31.       
  32.     if (TryGetDynamicParameter(name, out parameter))  
  33.     {  
  34.         isPresent = parameter.IsSet;  
  35.         return true;  
  36.     }  
  37.  
  38.     isPresent = false;  
  39.     return false;  
  40. }  
  41.  
  42. // get a parameter of type T.  
  43. private bool TryGetParameter<T>(string name, out T value)  
  44. {  
  45.     RuntimeDefinedParameter parameter;  
  46.       
  47.     if (TryGetDynamicParameter(name, out parameter))  
  48.     {  
  49.         value = (T)parameter.Value;  
  50.         return true;  
  51.     }  
  52.  
  53.     value = default(T);  
  54.       
  55.     return false;  
  56. }  
  57.  
  58. // try to get a dynamically added parameter  
  59. private bool TryGetDynamicParameter(string name, out RuntimeDefinedParameter value)  
  60. {  
  61.     if (_parameters.ContainsKey(name))  
  62.     {  
  63.         value = _parameters[name];  
  64.         return true;  
  65.     }  
  66.  
  67.     // need to set this before leaving the method  
  68.     value = null;  
  69.  
  70.     return false;  
  71. }  

Finally, the three helper methods are revealed. One is used for checking for dynamic SwitchParameters, the next is for ordinary parameters that return type T, the generic argument. The third method, TryGetDynamicParameter is used by the first two methods.

I hope this helps reveal some of the mystery behind dynamic parameters on Cmdlets. There is one more type of dynamic parameter that I will be examining in one of my next few posts, that is the scenario where a provider (like the FileSystemProvider or RegistryProvider) passes a dynamic parameter to a Cmdlet. In this particular case, the provider can only pass dynamic parameters to the built-in Cmdlets that operate on providers, e.g. Get-ChildItem, Get-Item, Get-ItemProperty etc.

Have fun!

posted on Sunday, December 21, 2008 5:28:27 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Monday, December 15, 2008

The dynamic duo / masterminds of PowerShell will be cornered and fiercely grilled by none other than our very own master podcaster, Hal Rottenberg this Thursday.  From the mouth of the suffixed one himself:

Coming up on the PowerScripting Live show this Thursday will be Jeffrey Snover,
the architect for PowerShell as I’m sure you all know, and he’ll be accompanied
by none other than Bruce Payette, author of PowerShell in Action and a core
developer on the PowerShell team.

We’re excited and we hope you can make it this Thursday at 9pm EST!

The live stream address is http://www.ustream.tv/channel/powerscripting-podcast

So if you want to get the lowdown on CTP3 (maybe), join us, the unwashed masses as we clamour to be near our idols. A lock of their hair and a signed discarded printout of directions to building 18 could be yours!

I made that last bit up. Who cares! This is going to be cool! Join us!

posted on Monday, December 15, 2008 4:14:40 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback
# Sunday, December 14, 2008

Now this is cool. I’ve always wanted to try out TDD, but as I’m primarily a SharePoint developer, a lot of the time my code is written on my laptop running XP, so I can’t actually test anything since SharePoint won’t install there. The folks at Bamboo Solutions came up with some clever hacks to get WSS 3.0 and MOSS running on Vista, but it’s a bit of a heavyweight solution, especially when you consider this:

Typemock are offering their new product for unit testing SharePoint called Isolator For SharePoint, for a special introduction price. it is the only tool that allows you to unit test SharePoint without a SharePoint server. To learn more click here.

The first 50 bloggers who blog this text in their blog and tell us about it, will get a Full Isolator license, Free. for rules and info click here.

Unfortunately the competition is actually over, but it’s still worth a peek!

posted on Sunday, December 14, 2008 6:58:36 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0] Trackback