# Thursday, May 14, 2009

Hey, so we did the unthinkable. We released another version of the PowerShell Community Extensions. We’re calling it a beta, because we’ve be so swamped with Real Life stuff that we’re not 100% confident that it is defect-free. It’s not going to murder your servers or anything, but there might be some documentation missing and other minor stuff. We’d really appreciate it if you can give it a test-drive. If you’re running PowerShell v1.0 or v2.0 CTP3, please use the MSI installer. It will upgrade your Pscx 1.1.1 install if you have one. If, on the other hand, you are running Windows 7 RC and/or have a later version of PowerShell than v2 CTP3, you can download the zipped module and unzip to your user profile module directory at ~\documents\windowspowershell\modules\ and load it using “import-module pscx.”

Thanks for your infinite patience (yes, it’s been a while and we’re sorry) and please leave comments and issues on the tracker at http://pscx.codeplex.com/

View the 1.2 Beta release page.

posted on Thursday, May 14, 2009 8:28:13 PM (Eastern Daylight Time, UTC-04: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
# Wednesday, October 15, 2008

The verbs list for naming your Cmdlets is pretty strict. You should definitely try to pick one of the known verbs. You can see them here:

function Get-Verb {
    [psobject].assembly.getexportedtypes() | `
        ? {$_.name -like "Verbs*"} | gm -static -membertype property | `
        sort Name | select Name
}

ps> Get-Verb

The noun end of the spectrum is pretty open-ended. Single nouns are better, and try to use the singular if you can. Cmdlets typically return one or more objects. so the singular form is the convention - better than trying to name your Cmdlet "Get-Noun(s)" which is just plain silly.

To prefix or not to prefix: this is a sticky one. The Religious Right, aka the Microsoft Powershell team, dictate that you should not prefix. The reality is more complicated and is under constant debate. If you pick a verb-noun pair that already exists and is currently loaded into powershell, you must disambiguate the command with the snapin name (snapinname\verb-noun) or it won't run. The snapin name is typically long and ugly. A noun prefix is typically short and sweet. The problem with the latter is that your commands are now harder to discover for someone who doesn't know they are there (and as such doesn't know your magic prefix). Ultimately though, people load your snapin explicitly and should know the prefix, so I tend to lean towards this although I feel a strong connection with the "One Noun Way."

(taken from one of my newgroup posts)

posted on Wednesday, October 15, 2008 12:20:19 PM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback
# Tuesday, August 12, 2008

It’s getting harder to post useful scripting tips for PowerShell these days as there are so many talented hardcore scripting bloggers around. My day to day is job is not system/network/server administrator; I’m a .NET developer, having started the C# habit about eight or nine years ago with the early CLR 1.0 beta. So, from here on in, I’ve decided that a better direction for me to take from now on is that of a PowerShell developer,  as opposed to a scripter. There are very few (if any?) dedicated PowerShell developer blogs around, and so I figured I should try to fill that gap as best I can. I have a not insignificant amount of experience writing providers, cmdlets and other widgety bits, so it’s a good time to share my experiences. Of course, my way is not “the” way, so please reply with your own experiences/advice/mocking/whatever. ;-)

That said, I am not eschewing scripting altogether – I have some stuff in the pipeline (har-har) concerning areas I’m interested in, like eventing and jobs/remoting.

posted on Tuesday, August 12, 2008 10:03:20 AM (Eastern Daylight Time, UTC-04:00)  #    Comments [0] Trackback