Monday, January 05, 2009

PowerShell-Scripting.com

My French is none too great. If it were, PowerShell-Scripting.com might be of more use. The site looks to be a rich resource for French speaking PowerShell users.

Now if only they’s list my PowerShell Scripts blog (http://pshscripts.blogspot.com)!

Technorati Tags: ,,

Sunday, January 04, 2009

Modules in PowerShell V2

Introduction

As PowerShell has evolved, there are a number of things that have been needed to be added in order to make it truly enterprise ready. One of the key concepts added into Version 2 of PowerShell is that of a module. A module is some chunk of code that you can import into PowerShell and then use. Once imported, any cmdlets, scripts, or providers can be accessed. Installation of a module is now very simple – just use xcopy. 

Modules came originally with CTP2 of PowerShell V2 and are greatly improved in the latest CTP (CTP3) issued late December 2008. Unfortunately, good documentation on how to use modules is scarce: there’s no detailed information in the release notes, no about_module help information, and all the module cmdlets lack auto-help (get-help just dumps raw syntax and offers nothing else in the way of help). Nevertheless, a bit of playing, extensive Googling, and lots of trial and error has yielded a better understanding. For such an important feature, MS has let the side down a bit. But I digress!

Modules vs Snap-ins

In Version 1, we had the Snap-in as the way to add functionality into PowerShell. Teams like Exchange used this to add their own Exchange cmdlets into Exchange 2007. You install a snap-in by copying the necessary files and then updating registry entries to point to those files. Once installed, you could use the Add-PSSnapIn cmdlet to add the functionality of the snap-in into your environment. With a snap-in, the installation routine had to be written (although it could be partly automated) and the user had to run commands to perform the installation. Modules simplify this greatly.

Modules are a replacement for Snap-ins, although V2 will still support V1 type snap-ins. Modules are a much much improved way of creating add-ins and are to be strongly preferred going forward. You can create a module either by using compiled code (as you did in V2),  but also by writing them in PowerShell script. You can decorate modules with meta data, including Parameter descriptions, to enable them to be better integrated into a user’s  PowerShell experience. By using the Auto-Help feature, the module is self documenting.

Creating a Module with Powershell CTP3

At it’s simplest, a module is just a PowerShell script, contained in a file with a .PSM1 extension. For it to be of any use, you must save this script in a folder below your modules folder which is where PowerShell looks for modules. PowerShell has an environment variable, PSMODULEPATH, which defines where modules are to be found. On my system, I can see this as follows:

PS C:\foo> dir env:psmodulepath

Name                           Value
----                           -----
PSMODULEPATH                   C:\Users\tfl\Documents\WindowsPowerShell\Modules; C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules

As you can see, there are two folders on my system (one a per user, the other a per system). As you can also see, I’m running on an X64 OS (specifically Windows Server 2008 configured as a workstation!). I’m running PowerShell to create this post from within PowerShell Plus. Thus, you might see a different set of values on your system.

Much like Profiles, the per user module paths does not actually exist by default. You need to create the actual folder as Jeffrey Snover describes at the end of an interesting blog post. 

Sample Module

To illustrate PowerShell modules, here’s a module based on a script I posted to MDSN and to my PowerShell Scripts blog:

  1. function DeviceInterface { 
  2. param ($value) 
  3. switch ($value) { 
  4. 0    {"Other"} 
  5. 1    {"Unknown"} 
  6. 3    {"Serial"} 
  7. 4    {"PS/2"} 
  8. 5    {"Infrared"} 
  9. 6    {"HP-HIL"} 
  10. 7    {"Bus Mouse"} 
  11. 8    {"ADP (Apple Desktop Bus)"} 
  12. 160  {"Bus Mouse DB-9"} 
  13. 161  {"Bus Mouse Micro-DIN"} 
  14. 162  {"USB"} 
  15. } 
  16. } 
  17.  
  18. function Handedness { 
  19. param ($value) 
  20. switch ($value) { 
  21. 0 {"Unknown"} 
  22. 1 {"Not Applicable"} 
  23. 2 {"Right-Handed Operation"} 
  24. 3 {"Left-Handed Operation"} 
  25. } 
  26. } 
  27.  
  28. function PointingType { 
  29. param ($value) 
  30. switch ($value) { 
  31. 1 {"Other"} 
  32. 2 {"Unknown"} 
  33. 3 {"Mouse"} 
  34. 4 {"Track Ball"} 
  35. 5 {"Track Point"} 
  36. 6 {"Glide Point"} 
  37. 7 {"Touch Pad"} 
  38. 8 {"Touch Screen"} 
  39. 9 {"Mouse - Optical Sensor"} 
  40. } 
  41. } 
  42.  
  43. function get-MouseInfo { 
  44.  
  45. # Now do script stuff 
  46. # Get Mouse information 
  47. $mouse = Get-WmiObject -Class Win32_PointingDevice 
  48.  
  49. # Display details 
  50. "Mouse Information on System: {0}" -f $mouse.systemname 
  51. "Description            : {0}" -f $mouse.Description 
  52. "Device ID              : {0}" -f $mouse.DeviceID 
  53. "Device Interface       : {0}" -f (Deviceinterface($mouse.DeviceInterface)) 
  54. "Double Speed Threshold : {0}" -f $mouse.DoubleSpeedThreshold 
  55. "Handedness             : {0}" -f (Handedness($mouse.handedness)) 
  56. "Hardware Type          : {0}" -f $mouse.Hardwaretype 
  57. "INF FIle Name          : {0}" -f $mouse.InfFileName 
  58. "Inf Section            : {0}" -f $mouse.InfSection 
  59. "Manufacturer           : {0}" -f $mouse.Manufacturer 
  60. "Name                   : {0}" -f $mouse.Name 
  61. "Number of buttons      : {0}" -f $mouse.NumberOfButtons 
  62. "PNP Device ID          : {0}" -f $mouse.PNPDeviceID 
  63. "Pointing Type          : {0}" -f (Pointingtype ($mouse.PointingType)) 
  64. "Quad Speed Threshold   : {0}" -f $mouse.QuadSpeedThreshold 
  65. "Resolution             : {0}" -f $mouse.Resolution 
  66. "Sample Rate            : {0}" -f $mouse.SampleRate 
  67. "Synch                  : {0}" -f $mouse.Synch 
  68. } 
  69.  
  70. # Export just the last function. 
  71. Export-ModuleMember Get-Mouseinfo 
  72. # End of Script 

Using Modules

First, I saved this file to MouseInfo.psm1, and then I stored that file under the folder MouseInfo contained in my per-user module folders (in specific, C:\Users\tfl\Documents\WindowsPowerShell\Modules\MouseInfo). Once this folder and the .PSM1 file are in place, you add this module into PowerShell by calling Import-Module, as follows:

PS C:\foo> # Note function does not currently exist!
PS C:\foo> get-mouseinfo
The term 'get-mouseinfo' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and try again.
At line:1 char:14
+ get-mouseinfo <<<<
    + CategoryInfo          : ObjectNotFound: (get-mouseinfo:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

PS C:\foo> # So now import it – note no output by default
PS C:\foo>
Import-Module mouseinfo
PS C:\foo> # now use a function contained in the module
PS C:\foo> get-mouseinfo
Mouse Information on System: COOKHAM8
Description            : PS/2 Compatible Mouse
Device ID              : ACPI\PNP0F13\4&33DCE2F0&0
Device Interface       : PS/2
Double Speed Threshold :
Handedness             :
Hardware Type          : PS/2 Compatible Mouse
INF FIle Name          : msmouse.inf
Inf Section            : PS2_Inst
Manufacturer           : Microsoft
Name                   : PS/2 Compatible Mouse
Number of buttons      : 0
PNP Device ID          : ACPI\PNP0F13\4&33DCE2F0&0
Pointing Type          : Unknown
Quad Speed Threshold   :
Resolution             :
Sample Rate            :
Synch                  :
PS C:\foo> # Find out more with Get-Module cmdlet
PS C:\foo> Get-Module mouseinfo

Name              : mouseinfo
Path              : C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules\mouseinfo\mouseinfo.psm1
Description       :
Guid              : 00000000-0000-0000-0000-000000000000
Version           : 0.0
ModuleBase        : C:\Windows\SysWOW64\WindowsPowerShell\v1.0\Modules\mouseinfo
ModuleType        : Script
PrivateData       :
AccessMode        : ReadWrite
ExportedAliases   : {}
ExportedCmdlets   : {}
ExportedFunctions : {[get-MouseInfo, get-MouseInfo]}
ExportedVariables : {}
NestedModules     : {}

As you can see, importing a module is very simple (once it’s in the right folder). And once you have imported your module, you can use the functions from the module that have been exported. In the MouseInfo module above, there are several helper functions to decrypt the values returned from WMI and which I (as the module’s author) do not wish to expose to a user of the module. The only exported function – in other words the only function that you can use from this module – is Get-MouseInfo. I explicitly export this function by using the Export-ModuleMember cmdlet in line 71 of the module.

Module Cmdlets

Modules are a key part of CTP3. To support modules, there are 7 module related cmdlets included with Powershell V2 CTP3, as follows:

  • New-Module – creates a new module from a script block.
  • Import-Module – imports a module from your Modules folder
  • Export-ModuleMember – notes the functions that a module exports and you can use once you import the module
  • Get-Module – gets information about modules
  • Remove-Module – removes a module
  • New-ModuleManifest – Helps create a new module manifest
  • Test-ModuleManifest – tests a module manifest

In addition, you can use the Get-Command cmdlet, specifying the module you want to get information from. For example:

PS MyMod:\> Get-Command -Module mouseinfo

CommandType Name              Definition
----------- ----              ----------
Function    get-MouseInfo     ...

I’ll try to blog more details on the module (and manifest) related cmdlets in due course.

Module Manifests

A module manifest is a specially constructed PowerShell script saved in a .PSD1 file. A module manifest is used to define precisely what is contained in a module. A manifest is an optional component, but the PowerShell team strongly advises use of a manifests to better document and describe a module. For more complex modules, e.g. more than just a single .psm1 file, a manifest is probably required.

A Module Manifest is really just a script that creates a hash table. This hash table contains the keys/values that PowerShell uses in managing your module. Since the manifest is pretty simple, it is very easy create one – just use your favourite script edtiro, and add in the values that you need. To make things even simpler, you can use the New-ModuleManifest cmdlet to create a manifest (and then tweak it using your favourite script editor).

Based on the MouseInfo module above, creating a new manifest using New-ModuleManifest is simple:

PS C:\foo> New-Modulemanifest .\mouseinfo.psd1

cmdlet New-ModuleManifest at command pipeline position 1
Supply values for the following parameters:
NestedModules[0]:Mouseinfo.psm1
Author: Thomas Lee
CompanyName: PS Partnership
Copyright: 2009
Description: My first module
TypesToProcess[0]:
FormatsToProcess[0]:
RequiredAssemblies[0]:
OtherFiles[0]:

After a bit of reformatting for publication and tidiness, here’s what the Mouseinfo module manifest  looks like:

  1. # Module manifest for module 'Mouseinfo' 
  2. # Generated by: Thomas Lee 
  3. # Generated on: 1/3/2009 
  4. @{ 
  5. # These modules will be processed when the module manifest is loaded. 
  6. NestedModules = ‘Mouseinfo.psm1’
  7. # This GUID is used to uniquely identify this module. 
  8. GUID = '94979266-70b4-4243-bef8-6fd87529af69' 
  9. # The author of this module. 
  10. Author = 'Thomas Lee' 
  11. # The company or vendor for this module. 
  12. CompanyName = 'PS Partnership' 
  13. # The copyright statement for this module. 
  14. Copyright = '2009' 
  15. # The version of this module. 
  16. ModuleVersion = '1.0' 
  17. # A description of this module. 
  18. Description = 'Cool Module' 
  19. # The minimum version of PowerShell needed to use this module. 
  20. PowerShellVersion = '2.0' 
  21. # The CLR version required to use this module. 
  22. CLRVersion = '2.0' 
  23. # Functions to export from this manifest. 
  24. ExportedFunctions = 'Get-MouseInfo' 
  25. # Aliases to export from this manifest. 
  26. ExportedAliases = '*' 
  27. # Variables to export from this manifest. 
  28. ExportedVariables = '*' 
  29. # Cmdlets to export from this manifest. 
  30. ExportedCmdlets = '*' 
  31. # This is a list of other modules that must be loaded before this module. 
  32. RequiredModules = @() 
  33. # The script files (.ps1) that are loaded before this module. 
  34. ScriptsToProcess = @() 
  35. # The type files (.ps1xml) loaded by this module. 
  36. TypesToProcess = @() 
  37. # The format files (.ps1xml) loaded by this module. 
  38. FormatsToProcess = @() 
  39. # A list of assemblies that must be loaded before this module can work. 
  40. RequiredAssemblies = @() 
  41. # Lists additional items like icons, etc. that the module will use. 
  42. OtherItems = @() 
  43. # Module specific private data can be passed via this member. 
  44. PrivateData = '' 
  45. } 

If I had included this manifest in my Mouseinfo module folder, after importing the Module, I’d be able to get better help information about the module (e.g. Get-Module would provide the description and the GUID created by New-ModuleManifest, etc). Manifests are an important aspect of PowerShell modules – I’ll cover them more in a future blog post.

References For More Information on Modules

As noted above, details on modules in CTP3 are hard to come by (and many are out of date) . Even the help text is pretty bare! Some blog posts that discuss modules and may be still be useful include:

Summary

With PowerShell V2 CTP3, you create and use modules to add functionality into PowerShell simply and easily. Modules are built using code, script or a combination. A module can be just one .PSM1 file, while more complex modules can be a combination of code, script, and other resources described in a module manifest. You can control what your users see when they import a module by using a module manifest and by using Export-ModuleMember cmdlet. To manage modules, you have a number of module related cmdlets to use. Finally, Module manifests are a key tool to describe modules.

I’ll be posting more about modules in the coming weeks.

Technorati Tags: ,,,

Saturday, January 03, 2009

Parameter Attributes in PowerShell V2 CTP Advanced Functions

In PowerShell V2 CTP3, you can create Advanced Functions which are, in effect, cmdlets written in script. I’ve already blogged about some of the cool features, particularly AutoHelp, which I find utterly cool! One neat aspect is the ability to define the parameters that your script accepts. Thus you can get PowerShell to do at least some of the validation of the parameter for you automagically. With Advanced Functions, you can do two things: you can define the parameter details in your script and have Get-Help provide them as documentation and you can decorate your script with Attributes telling PowerShell how to treat each parameter.

For many PowerShell users, the terms “decorate” and “attribute” may be new. By decorate, I mean just adding in extra text. Attributes are text that tell PowerShell how to do something. In CTP3, you can specify the [Parameter] attribute – decorating your script with these attributes (i.e. adding in the text to your script) enables you to tell PowerShell just how it should handle parameters to your script. I believe this is an important feature – and takes PowerShell further down the road towards being a full .NET language.

Here’s a snipped of code, a param block, showing the use of [Parameter] attributes:

  1. param ( 
  2. [Parameter(Position=0, Mandatory=$false)] 
  3. [string] $Domain = "Cookham" ,     
  4. [Parameter(Position=1, Mandatory=$false)] 
  5. [string] $Computer = "Cookham8", 
  6. [Parameter(Position=2, Mandatory=$false] 
  7. [string] $User     = "tfl"             
  8. ) 

This parameter (param) block defines three script parameters ($domain, $computer, $user). The Parameter attributes are also specified using named attributes (eg Mandatory, Position, etc) to ensure PowerShell knows how to handle them. The documentation thus far on these parameter attributes is limited. Well, limited in terms of PowerShell documentation. The MSDN Library has a ton of documentation on how to write PowerShell Cmdlet, but these are written for C# programmers. I’m assuming that, in due course, there will be additional documentation that is more PowerShell focused.

If this script fragment were from a script called Get-Foo (ok bad name but work with me!), then you might call this script as follows:

PS C:\foo> Get-Foo NWTraders MyWorkstation BillyBob

In terms of Parameter attributes, http://msdn.microsoft.com/en-us/library/ms714348(VS.85).aspx contains a list of the name attributes you can use. These are:

  • Mandatory  - a boolean saying whether the parameter is required or not. A mandatory parameter that is not specified generates a run time exception.
  • ParameterSetName – a string naming the parameter set a parameter belongs to. You can use this name in your script to handle different sets of parameters (that result in different behaviour of your script).
  • Position – an integer specifying where parameter’s order. As you can see in the above example, the $User paramater is the third parameter, while $domain is the first and $computer the second.
  • ValueFromPipeline – a boolean indicating if the parameter can come from the pipeline.
  • ValueFromPipelineByPropertyName  - a boolean indicating whether the parameter is filled from a property of the piped-in object that has either the same name or the same alias as this parameter.
  • ValueFromRemainingArguments – a Boolean indicating whether this cmdlet accepts all the remaining arguments passed. This is a good way to pickup any overspecified parameters.
  • HelpMessage – a string containing a short description of this parameter.
  • HelpMessageBaseName – the base name of the help message resource.
  • HelpMessageResourceId – an identifier used when a help message is localised.

Here is a slightly longer script demonstrating some of these:

  1. <#
  2. .SYNOPSIS 
  3.     Shows Parameter attributes 
  4. .DESCRIPTION 
  5.     Script is decorated with Parameter attributes to demostrate the use of them 
  6. .NOTES 
  7.     File Name  : Get-ParameterAttribute1.ps1 
  8.     Author     : Thomas Lee - tfl@psp.co.uk 
  9.     Requires   : PowerShell V2 CTP3 
  10. .LINK 
  11.     To be posted at: 
  12.     http://www.pshscripts.blogspot.com 
  13. .EXAMPLE 
  14.     Simple usage, with partial parameters specified 
  15.     PS C:\foo> .\Get-ParameterAttribute1.ps1 abc 
  16.     ---- 
  17.     Domain    : abc 
  18.     Computer  : Cookham8 
  19.     User      : tfl 
  20.     ---- 
  21. .EXAMPLE 
  22.     Simple usage, with all parameters specified 
  23.     PS C:\foo> .\Get-ParameterAttribute1.ps1 kapoho, kapoho1, BigKahuna 
  24.     ---- 
  25.     Domain    : kapoho 
  26.     Computer  : kapoho1 
  27.     User      : BigKahuna 
  28.     ---- 
  29. .EXAMPLE 
  30.     Showing getting first parameter from the pipeline 
  31.     PS C:\foo> "abc", "def", "GHI" |.\Get-ParameterAttribute1.ps1 
  32.     ---- 
  33.     Domain    : abc 
  34.     Computer  : Cookham8 
  35.     User      : tfl 
  36.     ---- 
  37.     ---- 
  38.     Domain    : def 
  39.     Computer  : Cookham8 
  40.     User      : tfl 
  41.     ---- 
  42.     ---- 
  43.     Domain    : GHI 
  44.     Computer  : Cookham8 
  45.     User      : tfl 
  46.     ---- 
  47. EXAMPLE 
  48.     Shows getting all Value From Remaining Arguments 
  49.     PS C:\foo> .\Get-ParameterAttribute1.ps1 abc def ghi xxx xxx xxx xxx 
  50.     ---- 
  51.     Domain    : abc 
  52.     Compuyter : def 
  53.     User      : ghi xxx xxx xxx xxx 
  54. .PARAMETER Domain 
  55.     A domain name - must be a string 
  56. .PARAMETER Computer 
  57.     A computer Name - must be a string 
  58. .PARAMETER User 
  59.     A user name - must be a string 
  60. #> 
  61. param ( 
  62. [Parameter(Position=0, Mandatory=$true,ValueFromPipeLine=$true)] 
  63. [string] $Domain = "Cookham" ,     
  64. [Parameter(Position=1, Mandatory=$false)] 
  65. [string] $Computer = "Cookham8", 
  66. [Parameter(Position=2, Mandatory=$false, ValueFromRemainingArguments=$true)] 
  67. [string] $User     = "tfl"             
  68. ) 
  69.  
  70. Process { 
  71. "----" 
  72. "Domain    : {0}" -f $domain 
  73. "Computer  : {0}" -f $computer 
  74. "User      : {0}" -f $user 
  75. "----" 
  76. } 

Friday, January 02, 2009

Posting PowerShell Scripts – one solution

On my PowerShell Scripts blog, I publish daily, or near daily, PowerShell scripts. I am slowly decorating the MSDN on-line library with PowerShell samples. I am also playing with the latest version of PowerShell V2 (aka CTP3) and the new auto-help feature.

Now that CTP3 is out, I’ve decided to change the way I posts scripts – I’ll use the auto-help approach, and include examples in the posted script. You may have noticed based on recently posted scripts. Well – those of you who look at my script blog have noticed. May have noticed. Or not…

In the past, when I’ve created a script, I use Live Writer to create the blog post. In that post, I copy in the script AND the results (each formatted separately). With V2 CTP3’s auto-help, I’ve decided to decorate each script post with documentation that includes expected output. All of this is neatly embedded into the script as posted, with expected output specified in the .EXAMPLE section in the opening comment block.

With the new auto-help format, I can also document the posted scripts better – a comment made on the blog some whiles back.

I’d be interested in thoughts on this idea. Suggestions naturally welcome.

Thursday, January 01, 2009

Free Group Policy Cmdlet from SDM Software

Those nice folks over at the SDM Software Group have posted a new Group Policy Cmdlet. This PoweShell cmdlet lets you check the health of Group Policy processing across computers in your domain. The cmdlethas a number of parameters you can use to check different aspects of GP Health. The cmdlet provides a quick "red or green" status indication of GP processing on an end-user system. It also provides a detailed listing of GPOs that apply to a given computer/user.  A very neat tool! And free!

The cmdlet comes wrapped in an MSI that installs the cmdlet into your environment. After running the MSI, you just need to invoke add-pssnapin to get the snap-in installed into your environment.,

Wednesday, December 31, 2008

Monad Manifesto – A Blast from the Past

I was looking today for some information about PowerShell (details on modules if you must know!), and I came across a very old Blog Posting by Jeffrey Snover. Entitled “Monad Manifesto – the origin of Windows PowerShell”, there’s also an 18-page white paper dated August 8 2002 entitled Monad Manifesto.

With the New Year just ahead, this old paper makes great reading. Of course, as the blog post points out, this is not an official white paper and it’s no longer very accurate (and shows the very old syntax that we had in the early versions of MSH). But as a vision, writen in 2002, this paper is required reading.

It’s interesting that it’s taken nearly 6.5 years from that paper to CTP3, and we’re still 6-9 months (or more) away from V2 RTW/RTM. I’ve always sort of thought the pace of development in PowerShell was fairly quick. As the Grateful Dead sing: “What a long, strange trip it’s been”.

Happy new year – and best wishes for 2009.

Tuesday, December 30, 2008

PowerShell’s [WMICLASS] Type accelerator

In January of this year, I wrote a basic article on PowerShell’s WMI Type Accelerators. A type accelerator is, in effect,a shortcut to some underlying .NET component. PowerShell comes with three type accellerators for WMI:
  • [WMI] – a shortcut way of getting to a single instance of a class. I described this type accellerator in an article in February.
  • [WMICLASS] – a short cut to a WMI Class definition to enable access to the class’s static properties and methods. I describe this type accelerator below.
  • [WMISEARCHER] – a short cut to .NET’s ManagementObjectSearcher enabling you to search for objects easily. This type accellerator is an opportunity for a future article.
The [WMICLASS] type accelerator takes a string containing a relative or absolute path to an WMI class, and returns a a System.Management.ManagementClass object that represents the specified class (as opposed to an occurance of that class). For example let’s take a look at the Win32_Share WMI Class. First, look at what Get-WMIObject returns, then look at what the [WMICLASS] type accelerator returns:
 PS c:\foo:\> Get-WMIOBjecct Win32_share | get-memberm
  TypeName: System.Management.ManagementObject#root\cimv2\Win32_Share
Name                MemberType   Definition
----                ----------   ----------
Delete              Method       System.Management.ManagementBaseObject Delete()
GetAccessMask       Method       System.Management.ManagementBaseObject GetAccessMask()
SetShareInfo        Method       System.Management.ManagementBaseObject SetShareInfo(System.UInt32 MaximumAllowed, System.String Descr...
AccessMask          Property     System.UInt32 AccessMask {get;set;}
AllowMaximum        Property     System.Boolean AllowMaximum {get;set;}
Caption             Property     System.String Caption {get;set;}
Description         Property     System.String Description {get;set;}
InstallDate         Property     System.String InstallDate {get;set;}
MaximumAllowed      Property     System.UInt32 MaximumAllowed {get;set;}
Name                Property     System.String Name {get;set;}
Path                Property     System.String Path {get;set;}
Status              Property     System.String Status {get;set;}
Type                Property     System.UInt32 Type {get;set;}
__CLASS             Property     System.String __CLASS {get;set;}
__DERIVATION        Property     System.String[] __DERIVATION {get;set;}
__DYNASTY           Property     System.String __DYNASTY {get;set;}
__GENUS             Property     System.Int32 __GENUS {get;set;}
__NAMESPACE         Property     System.String __NAMESPACE {get;set;}
__PATH              Property     System.String __PATH {get;set;}
__PROPERTY_COUNT    Property     System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH           Property     System.String __RELPATH {get;set;}
__SERVER            Property     System.String __SERVER {get;set;}
__SUPERCLASS        Property     System.String __SUPERCLASS {get;set;}
PSStatus            PropertySet  PSStatus {Status, Type, Name}
ConvertFromDateTime ScriptMethod System.Object ConvertFromDateTime();
ConvertToDateTime   ScriptMethod System.Object ConvertToDateTime();

PS c:\foo:\> [WMICLASS]'Win32_share' | get-member
   TypeName: System.Management.ManagementClass#ROOT\cimv2\Win32_Share
Name                MemberType    Definition
----                ----------    ----------
Name                AliasProperty Name = __Class
Create              Method        System.Management.ManagementBaseObject Create(System.String Path, System.String Name, System.UInt32 ...
__CLASS             Property      System.String __CLASS {get;set;}
__DERIVATION        Property      System.String[] __DERIVATION {get;set;}
__DYNASTY           Property      System.String __DYNASTY {get;set;}
__GENUS             Property      System.Int32 __GENUS {get;set;}
__NAMESPACE         Property      System.String __NAMESPACE {get;set;}
__PATH              Property      System.String __PATH {get;set;}
__PROPERTY_COUNT    Property      System.Int32 __PROPERTY_COUNT {get;set;}
__RELPATH           Property      System.String __RELPATH {get;set;}
__SERVER            Property      System.String __SERVER {get;set;}
__SUPERCLASS        Property      System.String __SUPERCLASS {get;set;}
ConvertFromDateTime ScriptMethod  System.Object ConvertFromDateTime();
ConvertToDateTime   ScriptMethod  System.Object ConvertToDateTime();
In this example, you can see that Get-WMIObject returns System.Management.ManagementObject objects, while [WMICLASS} returns System.Management.ManagementClass objects – in other words, different object types with different members. I note that the MSDN library documentation does not really differentiate static and object members clearly – so you just have to know which is which when dealing with WMI classes.
The object occurrences returned from Get-WMIObject contain three methods: Delete, GetAccessMask and SetShareInfo. These three methods operate on a particular occurrence, i.e. Delete means “delete this occurrence”. However, the object returned from [WMICLASS} both contains none of those three dynamic methods, but does create a static method: Create, i.e. create a new share.
Why bother with [WMICLASS] you might ask. The answer is simple: to access the static methods and properties/fields that the class exposes. In the case of theWin32_Share class, the class has a static method (create) and three dynamic methods( delete, GetAccessMask and SetShareInfo). If you want to create a new share, then use [WMICLASS] to get access to the create method. You can get access to the Delete method by getting the appropriate method. This bit of code illustrates this:

.SYNOPSIS
    Demonstrates WMI and Win32_Share
.DESCRIPTION
    This script looks at objects retured from Get-WMIObject, and [WMICLASS] and demonstrates
    the use of a static method (create) and a dynamic or object method (delete).
.NOTES
    Author   : Thomas Lee - tfl@psp.co.uk
.LINK
    http://www.pshscripts.blogspot.com
.EXAMPLE
    Left as an exercise for the reader
#>

# Display shares at start
$start = get-wmiobject win32_share | where {$_.name -match "Foo"}
if ($start) {
  "{0} foo shares at start, as follows:" -f $start.count;
  $start}
else {"No foo shares"}

# Create a foo22 share
"";"Adding Foo22 share"
$class = [WMICLASS]'win32_share'
$ret = $class.create("c:\foo", "foo22", 0,$null,"Test Share Creation with WMI")
if ($ret.returnvalue -eq 0){
"Foo22 Share created OK"}
else {
"Share not created, error code: {0}" -f $ret.returnvalue
}

# Display results
"";"Foo shares now:"
get-wmiobject win32_share | where {$_.name -match "foo"}
""

# Delete the foo22 share
$del = Get-WmiObject win32_share | where {$_.name -eq "foo22"}
$ret = $del.delete()
if ($ret.returnvalue -eq 0){
"share deleted OK"}
else {
"Share not deleted, error code: {0}" -f $ret.returnvalue
}

# Display final results
"";"Foo at the end:"
$finish = get-wmiobject win32_share | where {$_.name -match "foo"}
if ($finish) {
  "{0} foo shares at the end, as folllows:" -f $start.count;
  $start}
else {"No foo shares at the end:"}
""
This sample, after the now obligatory Advanced Function help stuff, obtains and displays any shares on the local system that contain the string “foo”. Then, in line 24 the scripts gets the Win32_Share class, and in line 25 used the create static method to create a new share (Foo22). In line 39, the script deletes the newly added share, and finally prints out the remaining shares matching “foo”.
In summary, the [WMICLASS] gives you access to the static methods or members exposed by a WMI class.

Monday, December 29, 2008

Type Accelerators for PowerShell CTP3

Type Accelerators are a PowerShell feature that simplifies access to underlying WMI or .NET objects. Earlier this year I wrote two blog articles, the first about the WMI type accelerators and the second specifically about the [WMI] type accelerators. At some point, I intend to write about the other two ([WMICLASS] and [WMISEARCHER]) WMI related type accelerators.
In a most interesting Christmas Day post, Osin posted a detailed look at Type Accelerators within PowerShell CTP3. By using Reflector to look at the actual PowerShell code, you can see how PowerShell implements Type Accelerators, through using the TypeAccellerator class. Neat! But neater still, Osin shows how to make use of this technique to both list out the existing Type Accelerators as well as how to add more.
Here’s a simple function definition that returns the existing type accelerators:

function Get-Typeaccelerator
{  #  reference the accelerators
     $acceleratorsType = [type]::gettype("System.Management.Automation.TypeAccelerators")  
  #  return all built-in accelerators (property)     return $acceleratorstype::get.GetEnumerator()|
     select @{Name="Name"; expression={$_.key}},
     @{name="Type"; expression={$_.value}} | sort name
}


Sunday, December 28, 2008

PowerShell CTP3 Comment Based Help

I’ve been playing a lot with comment based help (CBH) in PowerShell CTP3.CBH enables you to decorate a script with help information. This information can then be read by Get-Help to provide help text back to a user of your script. From an enterprise, production scripting point of view, this is very cool and super useful. Production scripts should always be well documented. And for community generated scripts, having great help text will only aid other users trying to integrate these community scripts into their environment.

The CBH information is specified inside a block comment at the start of your script. A block comment begins with  “<# “ and ends with “#>”- everything inside these two character blocks is considered to be a comment. Here’s a very simple CBH block within a script:

# Script CBH-1
<# .SYNOPSIS
     Cool Script 
.DESCRIPTION
     No really. It's really really cool"
.NOTES
     Author     : Thomas Lee - tfl@psp.co.uk
.LINK
     http://tfl09.blogspot.com
#>
"The meaning of life, the universe and everything is {0}" -f 42 
You can run this script, and it'll produce a predictable output. BUT, if you save it, say as Truth.Ps1, you can then run Get-Help against it, with output as follows:

PS C:\Foo:\> Get-Help  C:\Foo\Truth.ps1
NAME
     C:\foo\truth.ps1
SYNOPSIS
     Cool Script
SYNTAX
     C:\Foo\truth.ps1 []
DETAILED DESCRIPTION
     No really. It's really really cool"
RELATED LINKS http://tfl09.blogspot.com
REMARKS
     To see the examples, type: "get-help C:\Foo\Truth.ps1 -examples".     For more information, type: "get-help C:\Users\tfl\AppData\Local\Temp\Untitled19.ps1 -detailed".
     For technical information, type: "get-help C:\Foo\Truth.ps -full".
PS C:\foo>Get-Help C:\foo\truth.ps1 -Full
NAME     C:\foo\truth.ps1
SYNOPSIS     Cool Script
SYNTAX     C:\Foo\Truth.ps []
DETAILED DESCRIPTION
     No really. It's really really cool"
PARAMETERS
     This cmdlet supports the common parameters: -Verbose, -Debug,
     -ErrorAction, -ErrorVariable, -WarningAction, -WarningVariable,
     -OutBuffer and -OutVariable. For more information, type,
     "get-help about_commonparameters".
 INPUT TYPE
 RETURN TYPE
 NOTES
         Author     : Thomas Lee - tfl@psp.co.uk
RELATED LINKS http://tfl09.blogspot.com

This is very useful, as I hope you can imagine.

I’ve been doing some digging into this feature. The CTP3 release notes make mention of the various sections that help reports. I’ve built a sample script with what I think to be all the section names used. The idea being that this basic script can be used to demonstrate Get-Help in all its glory. However, what I’ve discovered is a great idea, but with some challenges.
First, here’s my sample auto-help demo script:

<#
.SYNOPSIS
    A summary of what this script does
    In this case, this script documents the auto-help text in PSH CTP 3
    Appears in all basic, -detailed, -full, -examples
.DESCRIPTION
    A more in depth description of the script
    Should give script developer more things to talk about
    Hopefully this can help the community too
    Becomes: "DETAILED DESCRIPTION"
    Appears in basic, -full and -detailed
.NOTES
    Additional Notes, eg
    File Name  : Get-AutoHelp.ps1
    Author     : Thomas Lee - tfl@psp.co.uk
    Appears in -full
.LINK
    A hyper link, eg
    http://www.pshscripts.blogspot.com
    Becomes: "RELATED LINKS"
    Appears in basic and -Full
.EXAMPLE
    The first example - just text documentation
    You should provide a way of calling the script, plus expected output
    Appears in -detailed and -full
.EXAMPLE
    The second example - more text documentation
    This would be an example calling the script differently. You can have lots
    and lots, and lots of examples if this is useful.
    Appears in -detailed and -full
.INPUTTYPE
   Documentary text, eg:
   Input type  [Universal.SolarSystem.Planetary.CommonSense]
   Appears in -full
.RETURNVALUE
   Documentary Text, eg:
   Output type  [Universal.SolarSystem.Planetary.Wisdom]
   Appears in -full
.COMPONENT
#>

Saturday, December 27, 2008

MSDN Code Search Preview (http://msdn.krugle.com/)

Looking at the MSDN Library site tonight and I noticed a new “Feature Spotlight” – point to a new site that enables you to search for code inside MSDN. The site enables  you to search for code, and if you find something of interest, you can book mark it, or create a unique URL to the appropriate page. It’s clearly early days for this site. You can’t yet search for  code on the MSDN Forums, the MSDN Code Gallery or Codeplex.

Another downside – under Language, there’s no PowerShell. There’s Perl and Ruby and Python and C++ and  C#, etc – but no PowerShell. :-(  You can filter on PowerShell and find some PowerShell related code. Shame no one in MSDN recognises PowerShell as a language!

Technorati Tags: ,

Friday, December 26, 2008

Enums, Enum values and PowerShell

 

I’ve been reading Jeffrey Snover's discussions on ENUMs over on the PowerShell Team blog (here, and here). I knew most of this stuff and have  been playing with Enums and PowerShell for a while. I’ve created a bunch of sample scripts I’ve uploaded both to the MDSN Wiki and to my PowerShell Scripts blog. This morning, I stumbled upon an interesting use of Enums – parsing strings into Integer values, as shown on the MSDN Library at http://msdn.microsoft.com/en-us/library/system.globalization.numberstyles.aspx.

Effectively want I wanted to do was to convert the following C# code to PowerShell:

  1. // Parse the string, allowing a leading sign, and ignoring leading and trailing white spaces. 
  2. num = "    -45   "; 
  3. val = int.Parse(num, NumberStyles.AllowLeadingSign |  
  4.      NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite); 
  5. Console.WriteLine("'{0}' parsed to an int is '{1}'.", num, val); 

Initially, I could not work out how to use the enums  (In System.Globalization.NumberStyles). Thanks to Shay Levy, it turns out to be remarkably easy (although not quite as succinct as in C'#). Basically, in true PowerShell style, every enum value is just an object. Objects have properties, and one property of an enum value is “value__” as demonstrated here:

PSH [D:\foo]: [System.Globalization.NumberStyles]::AllowLeadingSign
AllowLeadingSign
PSH [D:\foo]: [System.Globalization.NumberStyles]::AllowLeadingSign | gm

   TypeName: System.Globalization.NumberStyles

Name        MemberType   Definition
----        ----------   ----------
CompareTo   Method       System.Int32 CompareTo(Object target)
Equals      Method       System.Boolean Equals(Object obj)
GetHashCode Method       System.Int32 GetHashCode()
GetType     Method       System.Type GetType()
GetTypeCode Method       System.TypeCode GetTypeCode()
ToString    Method       System.String ToString(), System.String ToString(String format, IFormatPr...
value__     Property     System.Int32 value__ {get;set;}
MSDN        ScriptMethod System.Object MSDN();

PSH [D:\foo]: [System.Globalization.NumberStyles]::AllowLeadingSign.value__
4
PSH [D:\foo]:

As you can see from this output, the enum [System.Globalization.NumberStyles]::AllowLeadingSign displays normally the value “AllowLeadingSign” , but if you use the .value__ property on this enum value, you get back a number – in this case a decimal 4 (0x0004). You can then combine these as follows to convert the above C# Code into PowerShell:

  1. $num = " -45 "; 
  2.   $val = [system.int32]::Parse($num, 
  3.                [System.Globalization.NumberStyles]::AllowLeadingSign.value__ + 
  4.                [System.Globalization.NumberStyles]::AllowLeadingWhite.value__ + 
  5.                [System.Globalization.NumberStyles]::AllowTrailingWhite.value__) 
  6. "'{0}' parsed to an int is '{1}'." -f $num, $val 

Thanks to Shay Levy for his post in the PowerShell newsgroup for helping me to work this out. FWIW: you can the results of this up on the MSDN Library and on my PowerShell Scripts blog.

 

Thursday, December 25, 2008

Merry Christmas

Today is Christmas day and I’m away from the computer, enjoying Christmas dinner with my wife and daughter – I’m off the grid! As is our tradition, we’ll start with a nice bottle of Champagne and some smoked salmon. Then a bottle of Opus 1, with some cold roast duck, along with roasted turkey and roasted boneless chicken. We’ll finish up with some pudding and a nice bottle of vintage port. If anyone’s in the area and is not driving, they would be most welcome – I’d be happy to open up another bottle or two should that prove needed!

There’s no real PowerShell content today, but in keeping with the spirit of the season, there’s a fun PowerShell script up on PowerShell.Com to keep you amused. Enjoy.

And for the real hard-core PowerShell Addict, I’ll be posting tomorrow with some interesting stuff I discovered about using Enums and .NET. Stay tuned.

Merry Christmas and Seasons Greetings to you all.

Windows PowerShell Holiday Gift Guide

From the PowerShell Scripting Guys team comes this Windows PowerShell Holiday Gift Guide.

Merry Christmas!

 

Technorati Tags:

Wednesday, December 24, 2008

PowerShell – Online Virtual Lab

Microsoft TechNet has produced an on-line Virtual Lab on PowerShell.

The lab, which lasts up to 2 hours 50 minutes, covers the following topics:

  • PowerShell Variables
  • Branching and Script Blocks
  • Looping, Functions, and Filters
  • WMI Scripting
  • .NET Forms with Windows PowerShell
  • Visual Basic scripting functionality within PowerShell
  • PowerShell and Active Directory Domain Services
  • PowerShell scripting to reset a ADDS user password
  • Remote management using PowerShell
  •  

    If you are unfamiliar with PowerShell, or if you want to dig a bit deeper into some of these areas, then head on over. It takes a minute or two for the TechNet Virtual Lab to come up, but once it does, you’re presented with a screen like this:

    image

    This lab is based on PowerShell 1.0 (although everything in the lab should work fine with PowerShell V2.0).

    Technorati tags: , ,

    Tuesday, December 23, 2008

    Tweet Grid For PowerShell

    Now this is neat - Tweet Grid, a page that shows recent posts about PowerShell, side by side with CTP3. It looks like this:

    image

    The page auto updates, so you can see new Tweets as they come in. I will be using this page a lot over the coming days to monitor the Twitter-sphere reaction to CTP 3.

    One minor issue – the right hand pane is searching just for the phrase “CTP3” – which could also be some other product, or a part of a URL. While most tweets are relevant, a few aren’t. A slightly improved URL is here.

    Technorati Tags: ,,,

    Windows PowerShell V2 CTP3 Arrives!!

    Well –this is cool and a tad unexpected. In a recent post, I noted that I’d heard PowerShell had been delayed till the new year. Well, that’s WRONG. It released last night, as explained over on the PowerShell Team blog.

    image

    image

    You can get PowerShell from the MS download site. And if you plan to use remoting (one of the key features of PowerShell V2, you’ll also need WinRM which you can also download from Microsoft connect.

    Let the fun begin!

     

    Technorati Tags: ,,

    Monday, December 22, 2008

    PowerShell and Clustering in Server 2008 R2

    Just read an interesting blog article over on the Clustering and High Availability blog written by Symon Perriman a program manager for clustering and high availability. The article, entitled PowerShell for Failover Clustering in Windows Server R2, discusses the clustering team’s intention to use PowerShell as the scripting language for clustering technologies in Server 2008 R2.

    If you are a clustering person, you should check this article out – it documents that the team will deliver over 60 cmdlets to manage clustering. There will also be a custom console, as shown in the blog article.

    It looks like the Windows team(s) now finally get PowerShell!

    Sunday, December 21, 2008

    PowerShell Twitterers

    If you are in to Twitter, and into PowerShell –here's a list of PowerShell Twitterers. It appears to be relatively up to date!  The list was created by Steven Murawski, a US based PowerShell guy.

    Technorati Tags: ,

    Saturday, December 20, 2008

    PowerShell Scripts Blog now features on PowerShell.com

    Tobias and the cool folks from Idera are behind the PowerShell.Com community site. They’ve just added my PowerShell Scripts Blog (http://pshscripts.blogspot.com) to their featured blogs list.
    Yeah!  So come on over and join the community!