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)!
Thomas Lee's collection of random interesting items, views on things, mainly IT related, as well as the occasional rant
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)!
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:
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 : CommandNotFoundExceptionPS 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 mouseinfoName : 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:
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:
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.
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:
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:
Here is a slightly longer script demonstrating some of these:
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.
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.,
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.
PS c:\foo:\> Get-WMIOBjecct Win32_share | get-membermIn 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.
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();
# Script CBH-1You 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:
<# .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
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
<#
.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
#>
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!
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:
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 | gmTypeName: 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:
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.
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.
From the PowerShell Scripting Guys team comes this Windows PowerShell Holiday Gift Guide.
Merry Christmas!
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:
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:
This lab is based on PowerShell 1.0 (although everything in the lab should work fine with PowerShell V2.0).
Now this is neat - Tweet Grid, a page that shows recent posts about PowerShell, side by side with CTP3. It looks like this:
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.
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.
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!
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!
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.