Tracking time while presenting PowerShell

I don’t wear a watch.  Maybe I should, but I feel like there are too many clocks in the world already and I don’t want to add to that by putting one on my wrist.  This works just fine for me for the most part.

But last week I was busy having fun giving an introductory presentation about PowerShell to the Ottawa Windows Server User Group and since I can talk about PowerShell for hours without getting tired of it I needed to keep a closer eye on the time.  And with my PowerShell slide deck often full screen on my laptop, I couldn’t rely on the small little clock in my system tray to do the job.  What to do, what to do…

Well since I was demoing PowerShell and some of the many products available that support PowerShell, I came up with a solution that would both keep my eyes on the time and at the same time give me a nice segway within my presentation into a short discussion about PowerGadgets and what they can do.  Here’s a screenshot to show you what I mean:

Presenting PowerShell with a PowerGadgets Clock

See that little digital clock in the corner?  That’s a PowerGadget.  Here’s a close-up of it (taken at a later time):

PowerGadgets Clock Close-Up

It’s configured to always be on top of my desktop, and it is running a short PowerShell script every minute to get the current time in short format.  This doesn’t even begin to scratch the surface of what you can do with PowerGadgets, but it was definitely a nice opportunity to show just one of the many great things being done with PowerShell in the market today.  And it took all of 2 minutes to make it too!

Judging from many attendees at the presentation taking notes about PowerGadgets when I showed them this as well as how easy it can be to use, I think it made a good impression on them as well.  If you are curious about PowerShell and would like to see what some of your data presentation options are, take a look at what PowerGadgets has to offer.

Oh, and since PowerGadgets comes with cmdlets that can be used to create them, you can launch them from within PowerGUI too.  Two rich PowerShell tools that work great together already!  And we haven’t even gotten to the release of version 2 of PowerShell yet!  This certainly is a fun space to be in!

Kirk out.

Technorati Tags: , , , ,

Improving the PowerGUI out-of-the-box experience

One of the things that I’ve been tasked with as part of my PowerGUI duties is to improve the PowerGUI out-of-the-box experience by adding new nodes, links and actions to the default PowerGUI tree so that you get a richer set of functionality right off the bat.  In order to do this right the first time, I’d like to solicit input from any PowerGUI users out there who have either added functionality to the tree that they’d like to share or who would like to put some requests on the table for functionality that they’d like to see in the default PowerGUI tree.

For starters I’d like to stick with the existing root nodes we have in the tree and get your feedback on things you would like to see to enhance that offering with additional functionality.  If you would like to contribute, please either leave a comment on this blog, post a suggestion to the PowerGUI community forums, or email me directly.  My email address ID is simply the title of this blog and I’m using Google’s free email service.  Hopefully that’s not too cryptic for you to piece it together.  The hoops we have to jump through to avoid being discovered by web crawling spam bots… )

Kirk out.

Technorati Tags: , , ,

PowerShell Deep Dive: Discovering dynamic parameters

Not too long ago when I posted an Invoke-Cmdlet function that could be used to extend PowerShell cmdlets, I indicated that I would soon post an example of how I use it to extend a cmdlet’s core functionality.  In this post I will show you that example, where I will extend the Get-Help cmdlet such that it is able to include provider-specific syntaxes for core cmdlets and documentation for any dynamic parameter that supports a given cmdlet regardless of what provider they come from.  Before I show you that example though, I should provide a little background information on core cmdlets and dynamic parameters and why this extension is important when learning how to use core cmdlets.

Background 

What is a core cmdlet?  A core cmdlet is a PowerShell cmdlet that provides consistent user experience when working with any PowerShell drive, regardless of which PowerShell provider the drive is associated with.  In PowerShell 1.0, the list of core cmdlets include any cmdlet with one of the following nouns: ChildItem, Content, Item, ItemProperty, Location, Path, PSDrive or PSProvider.  To see the entire list of core cmdlets, simply execute ‘Get-Help about_core_commands’ in PowerShell.

What is a dynamic parameter?  A dynamic parameter is a provider-specific parameter that is conditionally available on one or more core cmdlets that come with PowerShell.  Dynamic parameters are used to extend the functionality in core cmdlets so that they can use some functionality that is only available when working with certain providers.

How can I find out which dynamic parameters are available for a core cmdlet and where can I read documentation about them?  If you’re trying to learn more about a core cmdlet in PowerShell 1.0, and if you want to find out information about the dynamic parameters that are available for that cmdlet, you have the following options:

  1. Execute ‘Get-Help CmdletName -Full’ in PowerShell and hope that your dynamic parameter was included in the default documentation for the cmdlet.  With very few exceptions, if you do this you’ll most likely find the documentation you’re looking for isn’t available.  For example, the CodeSigningCert dynamic parameter is included in the parameter documentation for Get-ChildItem, but it is not included in syntax for Get-ChildItem nor is it included in the parameter documentation or syntax for Get-Item where it also applies.  Most dynamic parameters that are part of the providers included in PowerShell 1.0 are not included in the default cmdlet documentation, and no dynamic parameters that are available through third-party providers are included in the default cmdlet documentation (obviously, because they didn’t exist at the time that the PowerShell documentation was written).
  2. Use the Syntax parameter and optionally the ArgumentList parameter of Get-Command to view the syntax for the core cmdlet you are curious about when working with a specific provider.  If you only use the Syntax parameter, then the syntax that is returned will be for the provider associated with the current working directory.  If you pass in a path in the ArgumentList parameter as well, then the syntax that is returned will be for the provider associated with that path.  This works well when you are doing ad-hoc scripting using the drive that hosts your current working directory and you just want the syntax without other help details, but if you are working in an IDE and writing scripts without the concept of a current working directory or if you want more documentation about the dynamic parameters you’ll have to go elsewhere for information.
  3. Execute ‘Get-Help -Category Provider -Name ProviderName‘ in PowerShell and then look in the section titled “Dynamic Parameters” to see what dynamic parameters are added and which core cmdlets they are added to.  This is the most useful out-of-the-box way to find help on dynamic parameters, but the help information is in a slightly different format than other parameter help and to truly get the big picture for the cmdlet and how it works with different providers you need to refer to the provider help AND the cmdlet help just to get parameter information.  Add to that the fact that you don’t get to see the updated syntax unless you use Get-Command with the Syntax parameter and it all adds up to more work than you should have to do just to learn everything about how a cmdlet works.

Based on these options, you can see that it is possible to retrieve all of the help documentation for a core cmdlet when working with a particular provider but it requires multiple calls and the documentation isn’t nicely compiled together into a comprehensive document.  I wasn’t satisfied with this because I thought I should be able to see all of the help information for a given cmdlet inside the documentation for that cmdlet.  In fact, I expected that it functioned this way from the start and used core cmdlets during many months of working with PowerShell oblivious to the fact some of them had dynamic parameters.  I simply didn’t know the dynamic parameters existed until I came across a dynamic parameter in PowerShell when using tab completion for a core cmdlet that had dynamic parameters for my current working directory at the time.  Cmdlet parameters shouldn’t be found just by chance like that.

There are other problems with the out-of-the-box implementation of dynamic parameters as well.  One of my favorite tricks for the Get-Help cmdlet these days is to use it to discover cmdlets with similar parameters.  For example, to see all cmdlets containing parameters with ‘path’ as a substring of one or more parameter names, you can simply execute ‘Get-Help * -Parameter *path*’. But this only works for parameters that are in the parameter list in the documentation for a cmdlet.  If a dynamic parameter exists that isn’t included in that parameter list in the cmdlet documentation, that parameter won’t be found.  Because of how this works behind the scenes, if the documentation for cmdlets did include all parameters, including dynamic ones, you could use this same trick to find all cmdlets that use a dynamic parameter.  Unfortunately, that won’t work though because as I mentioned earlier, the documentation for the vast majority of core cmdlets does not include dynamic parameters.

There are other examples to further illustrate how hidden dynamic parameters are, including the following:

  • They don’t show up when using tab completion or PowerTab unless the provider associated with the current working directory has the dynamic parameters you are looking for (and therefore if you try to use tab completion or PowerTab at the end of this line, you will never see the Type parameter: ‘Set-Item -LiteralPath hkcu:\temp -‘.
  • They don’t show up when using PowerShell Plus for the same reason as above (and since PowerShell Plus uses PowerTab internally this is completely understandable).
  • They don’t show up when using Intellisense in PowerGUI.

Not being satisfied with this, I started investigating what I could do to improve on the user experience by making dynamic parameters much more discoverable in the documentation.  Then it dawned on me that I should be able to extend the Get-Help cmdlet so that the documentation it returns will include all dynamic parameters, in both the cmdlet syntax and the cmdlet parameter lists.

Introducing the CmdletExtensionLibrary.ps1 script

The trick to extending existing cmdlets is to wrap them in functions of the same name.  Within those functions you can do whatever extra work you want done and then call the original cmdlet using the Invoke-Cmdlet function I referred to earlier.  This works because function names take precedence over cmdlet names in command name resolution.

Using that information as well as the knowledge I gained when researching dynamic parameters, I have created a CmdletExtensionLibrary.ps1 PowerShell script file that includes the following functions:

  1. Get-PSResourceString
    The Get-PSResourceString function returns a resource string that is looked up in the System.Management.Automation namespace. It is used to load error messages and localized strings used in PowerShell cmdlet documentation so that the Get-Help extension properly displays the added help documentation in the current culture.
  2. Invoke-Cmdlet
    This function is the same as the one I published on my blog earlier.  It is used to invoke a cmdlet by using its fully qualified name.
  3. Get-DynamicParameterMap
    The Get-DynamicParameterMap function extracts the dynamic parameter help information from the PSProvider help documentation and builds a map of cmdlet names to dynamic parameters.
  4. Add-PSSnapin
    The Add-PSSnapin function is a simple wrapper around the Add-PSSnapin cmdlet.  Once the snapin is added, it refreshes the dynamic parameter map using the Get-DynamicParameterMap function.  This is necessary to ensure that dynamic parameter information is always up to date with the list of PSSnapins that have been added in the PowerShell session.
  5. Remove-PSSnapin
    The Remove-PSSnapin function is a simple wrapper around the Remove-PSSnapin cmdlet.  Once the snapin is removed, it refreshes the dynamic parameter map using the Get-DynamicParameterMap function.  This is necessary to ensure that dynamic parameter information is always up to date with the list of PSSnapins that have been added in the PowerShell session.
  6. Get-Help
    The Get-Help function integrates the dynamic parameter documentation directly into the help documentation for any core cmdlet where they apply.  This includes the cmdlet syntax as well as the cmdlet parameter help information.  Once integrated, the dynamic parameter documentation will be displayed in the same language as the rest of the documention.

 You can find the latest revision of the CmdletExtensionLibrary.ps1 file in the Script Vault on the PowerShell Community site.  Alternatively, if you want to access it directly you can get it here.

All of the functions in the CmdletExtensionLibrary.ps1 file are fully documented in comments that precede the function definitions.  In order to add these functions to your PowerShell session, simply dot source the file (e.g. ‘. C:\MyPSScripts\CmdletExtensionLibrary.ps1’).  If you want these extensions always loaded, place the dot source command you just ran into the appropriate profile or copy the functions you want directly into your profile (but be careful when doing this since many of the functions call other functions in the same file so if you leave some out others may not work).

Once the functions are available in your PowerShell session, you should start noticing the full cmdlet documentation for core cmdlets when you execute Get-Help.  You can see this in PowerShell by executing any of the following commands:

  • Get-Help * -Parameter Wait
  • Add-PSSnapin pscx; Get-Help * -Parameter Raw
  • Help Set-Item -Full
  • Get-Help Set-Item -Full | more

When running these commands you will notice how dynamic parameters are now included in the documentation (and are therefore discoverable using the -Parameter parameter for Get-Help).  For the first two commands you will get information that was not previously available via Get-Help.  For the last two commands you will see that the cmdlet documentation includes all available syntaxes, including provider-specific syntaxes, as well as parameter help for every dynamic parameter that is available.  Also note that both the Help function and the Get-Help cmdlet automatically support the Get-Help cmdlet extension function, providing seamless integration into your PowerShell environment.  Is that cool or what?  It’s amazing how much you can do to customize PowerShell to your liking.  Hats off to the PowerShell team for making such a wonderful and flexible scripting environment!

I should point out that adding this set of functions to your PowerShell session does not make the dynamic parameters show up in tab completion or Intellisense in any of the products mentioned above.  I believe this could be done by creating a Get-Command extension that returns all available syntaxes for a core cmdlet, including provider-specific syntaxes.  I will have to test that theory out later and possibly update this library to support that as well.

Also, despite everything that I did figure out with respect to dynamic parameters I still have one big unanswered question.  If the purpose of dynamic parameters is to allow generic core cmdlets to access some provider-specific functionality then why are there dynamic parameters in the Exchange cmdlets?  For example, run the script below this paragraph before and after you add the Exchange cmdlets to your environment.  Before you add the Exchange snapin, the script will return all core cmdlets that have dynamic parameters (based on the provider associated with the current working directory).  After you add the Exchange snapin, the script will return the same core cmdlets as before plus many Exchange cmdlets.  It doesn’t make sense to me that parameters would be marked as dynamic in Exchange since there isn’t a provider for Exchange and therefore the core cmdlets do not work against Exchange.  Here is the script I was referring to:

foreach ($cmdlet in Get-Command -CommandType Cmdlet) {
   
$cmdlet.ParameterSets | ForEach-Object {
       
$_.Parameters | Where-Object { $_.IsDynamic } | ForEach-Object {
           
$cmdlet.Name | Write-Output
           
continue
        }
   
}
}

That about wraps it up for this post.  I have tested the CmdletExtensionLibrary.ps1 functions pretty extensively on Windows XP SP2 using PowerShell in English and also in French with the PowerShell MUI pack.  That doesn’t mean there aren’t any issues in these functions, though, so if you find any please report them back to me and I’ll try to resolve them for you.

Kirk out.

Technorati Tags: , , , , , , , ,

PowerGUI 1.0.12 (now with a debugger!) is now available

Almost a week ago I hinted about the next release of PowerShell (1.0.12) coming soon and showed a screenshot to give people a little teaser of what was coming.  Well that release is now available for download here!  I have been using 1.0.12 for the past three weeks now and its debugging functionality is indispensable when writing PowerShell scripts.  So what are you waiting for?  It’s free!  It rocks!  Go and download it already! ;)

Kirk out.

Technorati Tags: , , , , ,

Passing arguments to nested functions or cmdlets

Last week I posted a function that could be used to  invoke a cmdlet using the fully qualified name (which consists of the name of the PSSnapin followed by a backslash and then the cmdlet name).  This function can be useful when you want to wrap a cmdlet with a function of the same name so that you can do some additional work when that cmdlet is used in a script.

In a script I have been working on, that function has come in very handy however I found a problem with the original function that I posted: it wasn’t properly passing parameters of type array to the cmdlet being invoked.  Fortunately a little work with the debugger that is included in the upcoming release of the PowerGUI Script Editor helped me find the error.  As a result of this debugging session I have come up with three rules that I will follow in the future when passing arguments from one function to another:

  1. When you want to pass the contents of $args on to another function or cmdlet, copy it to another variable and pass the values from there instead.
  2. Leave variables containing values as variables when passing them on to another function or cmdlet.
  3. Be sure to evaluate parameter names in the $args variable (or its copy) before passing them to another function or cmdlet so that the values are assigned to parameters by name, if appropriate.

Here’s a simple, festive example that shows how you would go about doing this while following these rules:

$v1 = “Joy”
$v2 = [string[]]@(‘to’,‘the’)
$v3 = “world”

function one {
   
$args | Out-Host
   
Invoke-Expression “two $($passThruArgs = $args; for ($i = 0; $i -lt $passThruArgs.Count; $i++) { if ($passThruArgs[$i] -match ‘^-‘) { $passThruArgs[$i] } else { `”`$passThruArgs[$i]`” } })”
}
function two {
   
$args | Out-Host
}one -firstWord $v1 -middlePart $v2 -lastWord $v3

All this code does is invoke function one passing a bunch of arguments.  Function one simply passes those arguments directly on to function two without any modification to them.  You can see this in the line that starts with the Invoke-Expression cmdlet.

The post I refered to earlier has been updated with a corrected Invoke-Cmdlet function that follows these rules as well.

Kirk out.

Technorati Tags: , , ,

Change is a very good thing

For over half a year I’ve spent every free moment I could muster outside of work using PowerShell or a PowerShell related tool.  I made the decision a while back to do this with a few goals in mind, and today I finally achieved one of those goals.  Today marks my first day as a member of the PowerGUI team at Quest Software!  I couldn’t be happier about it!

Kirk out.

Technorati Tags: , , ,

Something wicked this way comes…

Troubleshooting PowerShell scripts is about to get easier.

I’ve had the privilege of beta testing early builds of PowerGUI 1.0.12 for the past couple of weeks, and it’s just fantastic!  This release is not generally available yet, but it will be very soon.  To wet your appetite, here’s a screenshot of the PowerGUI Script Editor that is included in the PowerGUI 1.0.12 release.

PowerGUI 1.0.12 Script Editor

Keep your eyes on the PowerGUI Community Site and Dmitry’s blog for news about the official release of PowerGUI 1.0.12 over the next week!

Kirk out.

Technorati Tags: , , , , , ,

What should you do when a cmdlet doesn’t do enough?

Now that I’ve been using PowerShell extensively for almost a year, I frequently discover opportunities for core cmdlets to provide a richer experience than they do out of the box.  Since PowerShell is a scripting language there are many ways to take advantage of these opportunities including writing new cmdlets, adding type data or format data for specific object types, writing specialized functions, etc.  Sometimes though, all I want to do is extend an existing cmdlet as is while adhering to the following rules:

  1. It improves on the functionality of the original version.
  2. It can be used interchangeably in place of the original cmdlet in any script with no modification required and no loss of functionality.

I just finished the first revision of a helper function that is required if you want to extend existing cmdlets in this way.  This helper function allows me to invoke the original cmdlet that I am modifying with the same parameters that my override received.  It’s called Invoke-Cmdlet, and its purpose is simple: retrieve all cmdlets from all loaded snapins that have a specific name and from those determine which one should be executed by following Microsoft’s name resolution rules as closely as possible.  In this particular function, the logic is simply to invoke the core cmdlet if there is a core cmdlet that has the same name; otherwise, the first non-core cmdlet that has the same name will be invoked.  Here is the PowerShell script defining the function:

Function Invoke-Cmdlet {
    param([
string]$cmdletName = $(throw “Cannot bind argument to parameter ‘CmdletName’ because it is empty.”
))

    $matchingCmdlets
= Microsoft.PowerShell.Core\Get-Command -CommandType cmdlet -Name $cmdletName
   
if (@($matchingCmdlets).Count -eq
0) {
       
throw
“The term ‘$cmdletName’ is not recognized as a cmdlet. Verify the term and try again.”
   
}
    $cmdletName = $null
   
foreach ($cmdlet in $matchingCmdlets
) {
       
if ($cmdlet
.PSSnapin.IsDefault) {
           
$cmdletName =
“$($cmdlet.PSSnapin.Name)\$($cmdlet.Name)”
           
break
       
} elseif (-not $cmdletName) {
            $cmdletName = “$($cmdlet.PSSnapin.Name)\$($cmdlet.Name)”
        }
    }


   
Invoke-Expression “$cmdletName $($passThruArgs = $args; for ($i = 0; $i -lt $passThruArgs.Count; $i++) { if ($passThruArgs[$i] -match ‘^-‘) { $passThruArgs[$i] } else { `”`$passThruArgs[$i]`” } }) | Write-Output”

}

Now that this function is written, what is an example where you could use this to extend a cmdlet while following the rules outlined above?  Right here.

Kirk out.

Technorati Tags: , ,

Exciting news: PowerShell support in SQL Server 2008!

This was just announced earlier today, and it’s really exciting so I wanted to make sure readers of this blog news about it.  Microsoft just announced that SQL Server 2008 will provide simplified scripting through PowerShell!  What great news to wake up to!  I’m thrilled about this news because I work with SQL Server a lot in my work and this will likely greatly simplify that work and open up a lot of opportunities for really cool and powerful PowerShell scripts.  You can read all about it here.

[Update 16-Nov-07]
Well while this has the potential to be something truly great, according to the details that came out of the TechEd IT Forum today it won’t live up to that potential, at least not in the first iteration.  My friend Dmitry shares the details here.

Kirk out.

Technorati Tags: , , , ,

PowerShell v2.0 CTP is now available!

What a wonderful thing to wake up to this morning!  The CTP of PowerShell v2.0 is now available!  I’m still digesting all of the details (and there are lots of them).  Read all about it here and here.

And of course, make sure you understand what a CTP is before you even consider using it.

The PowerShell V2 CTP is not for everyone. You should read this PowerShell Team blog entry ( http://blogs.msdn.com/powershell/archive/2007/11/02/ctp-watch-this-space.aspx ) to find out what it is and what it isn’t and then make an informed decision before installing the CTP.

Kirk out.

Technorati Tags: , ,