Powershell Community aggregated blog feed

If you haven’t noticed already, there is a growing community site dedicated to everything PowerShell.  One of the features offered on this site are blogs related to PowerShell.  The list of blogs on this site has been growing over the past few months and will likely continue to grow.  If you are like me and want to stay on top of all things PowerShell, there is a very simple way to subscribe to all blogs on this site, old and new.  Simply point your favorite news reader to the following RSS feed:

 PowerShell Community aggregated blog feed

This RSS feed will aggregate all posts from any blogs on the PowerShell Community site, so you won’t have to worry about managing your feeds for this site manually anymore.

Don’t forget about the plethora of wonderful PowerShell blogs outside of this community site though! 😉

Enjoy!

Kirk out.

Technorati Tags: , , , ,

Kirk Munro, Microsoft MVP

Last night I hinted on my blog about the only Christmas present that I was hoping for possibly arriving in the next few days.  Well today it arrived, and color me a happy camper!

I just received the 2008 Microsoft MVP Award for my efforts in the PowerShell (Windows Server – Admin Frameworks) technical community during 2007!  What a great way to start off the New Year! )

I am truly honored to receive this award.  It has been a dream of mine for many years to become a Microsoft MVP, and I was just waiting for the right time and the right product/technology to come along to go after it.  As I indicated on my first blog entry in August last year, PowerShell came along and totally blew me away.  The PowerShell product and the incredibly rich community surrounding it continue to amaze and excite me, and this is only the beginning.

Many thanks to Microsoft for the award, and to supporters of my PowerShell work in the community.  A special thanks needs to be sent out to David Sengupta and Dmitry Sotnikov for their support as well — without their support I don’t know if this would have happened.  And lastly, thanks to my wonderful wife for supporting my efforts and putting up with many very long hours over the past year while I made my way through quite a few changes, this one included.

My PowerShell MVP profile can be found here.  It’s pretty empty at the moment, but I’ll be updating it very soon.

Thanks again everyone! 

Kirk out.

Technorati Tags: , , , ,

New Year, new opportunities

2007 was a very memorable year for me.  It started out with some big surprises that I never had to deal with before and looked like it was going to be a very difficult year.  Then it progressed into a newfound obsession for PowerShell, the start of this blog, a great change in career (within a company instead of between companies, a first for me), and now it is ending with much anticipation for what’s coming next (I’m still waiting to see if the only Christmas present I’ve been hoping for is coming…just a few more days to find out).

Looking back, it was definitely one of my most challenging years ever and after pushing myself pretty hard and taking a few risks ended up being one of the most rewarding as well.  And it will likely be a year I never forget.

Looking forward, I can’t wait to see what opportunities the New Year brings!

Happy New Year everyone!

Kirk out.

Technorati Tags: , ,

Quest AD Cmdlets gone gold!

It’s official!

The Quest AD Cmdlets are now RTM!  And they’re still 100% free!  If you are doing any scripting with Active Directory and PowerShell, these cmdlets are absolutely indispensable.

You can download the RTM version here.

Note: The initial post of the RTM version still had “ReleaseCandidate” as part of the msi filename.  This is still the RTM release.  The filename will be corrected shortly.

Kirk out.

Technorati Tags: , , ,

Dealing with comment spammers the PowerShell way

Since I started blogging earlier this year I’ve come to notice a two types of spam that I haven’t had to think about before: incoming link spam and comment spam.

Incoming link spam is quite interesting…links show up in my incoming link list trying to get me to be curious enough to click on those links and see what the source site is all about, which then results in trojan horses and other various nasty side effects detrimental to the health of your computer.  Curiosity killed the cat.  I learned that lesson the hard way quite a few months ago, and won’t get suckered by that one again.  I don’t think there is much I can do about that one either, so it’s best to simply be aware of it and only follow through links that look relevant to what you blog about.

Comment spam comes in one of two varieties: links to various sites selling pharmaceuticals or showing pornography (and probably also loaded with trojan horses and other equally nasty exploits), and content theft.  The link variety is just a minor annoyance which gets caught by my spam filters and automatically deleted.  The content theft variety is something that bothers me a little more though.  It comes in the form of a trackback link that would show up in my comments if I let it through.  The spam filters recognize it as spam, so I could just let it be automatically deleted, but I’m too bothered by the content theft to just delete the tracktrack comment.  What bothers me is that the site that is linking to my blog doesn’t care about me or PowerShell or PowerGUI or anything that I blog about.  They just want to get discovered through people following links in my comments or through search engines picking up their sites.  Then once you are on their site, they have advertisements everywhere waiting for you to click on them so that they get click-through income.  These individuals are trying to profit off of other bloggers hard work, not just by getting links on their site but by stealing their content, and that just doesn’t sit right with me.  And it must be working to some degree, because more and more of these types of sites pop up all the time.

Fortunately I have found through personal experience that you can successfully take action against the content theft sites.  I’ve had the blog entries linking to my blog removed from some sites (which now are shut down, so maybe removing the blog entries wasn’t enough for them), and I’ve had other sites shut down immediately and no longer available on the web.  This works because of policies that ISPs have against abuse, and fortunately spam is often considered as abuse in those policies.  An ISP that was used to host one of the sites that I’ve successfully had shut down has a strict no spam policy including the following penalties:

  • seizure of all on-premises equipment and data;
  • forfeit of all funds paid;
  • a demand for payment of a fine (to cover damage to our reputation)
  • $500/incident/spam clean-up fee, all of which is payable within 24 hours or will be referred to a collection agency;

That sounded like fair and just punishment to me, and they were very quick to shut down the site in question, so I recommend others try this as well.

If you have a blog and you want to take similar action against content theft, how do you go about doing it?  Well you could use a good whois database like http://ws.arin.net/whois/, enter the IP associated with the site that stole the content, go to the website of the ISP identified in the who, check out their abuse policy and then contact them with the details about the comment theft in hopes that they will shut them down.  Or you could use PowerShell to look after the retrieval of the whois record and have it open the website of the ISP for you as well as an email in your default email program already populated with the email address, subject and body.  Then it’s as simple as verifying the abuse policy on the ISP’s site, clicking send on that email and with a little luck, presto!  Another spammer gone! 🙂

Since this seems to be a trend that will only continue, I started writing a script to do this for me a little while ago and when I saw that content-theft trackback spam message in my spam folder this morning, I decided today I would finish it.  Well now it’s finished and ready for you to customize for your blog.

The script uses two functions to do its work:

  1. Get-WhoIsRecord – used to retrieve the whois record for a site identified by a dns name or an ip address from the specified whois database and build a custom PowerShell object with the data in that record.
  2. Fight-ContentTheft – used to extract the dns name from the offending blog url that is passed in, lookup the whois record, extract the abuse email address from that whois record, open the website for the ISP that hosts the offending blogger in the default browser and open a new email message in the default email program with the abuse email address, an appropriate subject and a message body already entered into the message.

I need to note that this script has only been tested for my own comment spam and therefore may need to be tweaked to work in your environment.  Also it has a two placeholders in the message body waiting for you to provide your blog address as well as your signature.  And finally note that this may not work through firewalls depending on their configuration.  But it can work because I’ve gotten it to work from my laptop, so if you have some issues I encourage you to troubleshoot and see if you can get it working if you want to fight this type of spam like me.

Since the script is a little long, I’m keeping it in an attachment to this post so that you can download it more easily.  The attachment is a text file so you’ll need to save it as a ps1 file if you want to run it within PowerShell.

To get the script, click here.

Enjoy!

Kirk out.

Technorati Tags: , ,

When in doubt, ask the community

In case you hadn’t noticed already, there are many people who are ready, eager and waiting to help you with your next PowerShell problem.  The list of PowerShell enthusiasts is long and growing steadily, and they’re responsiveness to questions is incredible.  So responsive in fact that it seems like there is a competition to see who can answer questions first!

Leverage that community!

If you have questions, post them somewhere.  If you have scripts that you can’t quite work out, share them and get the community to help.  If you think you can work it out but just want a few pointers, search the community and find if the answers you seek have already been posted somewhere.  There’s really no reason to wait.  If you’re stumped, ask for help and you’ll get it.

Here’s an updated (thanks to Hal for pointing out some important ones that I missed) list of just a few places you can go if you have questions:

  1. PowerShell Newsgroup – a very active newsgroup for discussions about anything related to PowerShell
  2. PowerGUI Community – the place to go to share PowerGUI PowerPacks or to ask questions about PowerGUI and Quest AD cmdlets
  3. PowerShell Community – a non-profit PowerShell Community site with forums for anything related to PowerShell, a script repository, and much more
  4. PowerShell Blog Search – a custom Google search of many PowerShell blogs; created and maintained by Brandon Shell (PowerShell MVP)
  5. The PowerScripting Podcast – a semi-weekly podcast about everything PowerShell; Jonathan Walz and Hal Rottenburg are the hosts, and this is a great source of current PowerShell information, interviews, tips and tricks, etc.
  6. PowerShell IRC channel (#PowerShell on irc.freenode.net) – an IRC chat room with many PowerShell savvy people hanging out, discussing PowerShell, ready to answer your questions right then and there.

If you’re looking for help on PowerShell, please use the community.  You’ll be thankful you did!

Kirk out.

Technorati Tags: , , , , ,

Sometimes you just want a property

On the PowerShell newsgroup I often (really often) see users new to PowerShell getting stuck transitioning from the point where they have a set of objects to creating an array of the values of one of the properties on those objects.  For example, if you are using the free Quest AD cmdlets and you want to retrieve a list of group names to which a member belongs, you can do this:

(Get-QADUser “Poshoholic”).memberOf | Get-QADGroup | ForEach-Object {$_.Name}

This seems simple enough but many people get stuck going from a collection such as that returned by Get-QADGroup to an array of names such as that returned by the ForEach-Object cmdlet shown in this exanple.  The missing piece of knowledge is usually understanding how to use ForEach-Object to extract the member you want.  Also, even when you know how to use ForEach-Object, I find it a little inconvenient to use ForEach-Object with a script block just to pull out a property name, or to put brackets around part of a command so that I can access members on the result.  And I find myself doing this quite regularly in my PowerShell work.

To both save myself from having to use ForEach-Object or brackets when all I want is to invoke a member on an individual object or a collection of objects, and to share this convenience with others, I have created an Invoke-Member function that makes the one-liner I listed above a little more elegant and PowerShelly.  Here’s an updated version of the one-liner I used above, revised to use the Invoke-Member function:

Get-QADUser “Poshoholic” | Invoke-Member memberOf | Get-QADGroup | Invoke-Member name

This one-liner retrieves an AD user named Poshoholic and from that user it retrieves the memberOf member value.  That value contains an array of DNs for groups to which the user belongs.  For each of those DNs, the one-liner then retrieves the AD group object and once it has that it extracts the name of that group.

The Invoke-Member function can be used to invoke any type of member, including both properties and methods (e.g. Invoke-Member “Open()”).  It can also be used to invoke nested members (e.g. Invoke-Member parameters.parameter).  And it can take input from the pipeline or alternatively through the InputObject parameter.  When using the InputObject parameter, the object is passed in as one object, even if it is a collection.  When using the pipeline collections are passed into Invoke-Member one item at a time.

[Update] Since this was originally posted, Xaegr pointed out in the comments that the PowerShell team already had published a function on their blog that does this, and that he has modified that function to support multiple members.  You can find that blog entry here, and Xaegr’s modifications can be found in the comments in this blog entry.  The problem with those two implementations of the … function  is that they don’t support calling methods and they don’t support nesting members, both of which are supported by the Invoke-Member function.  I liked Xaegr’s idea to support retrieving multiple members at once though, which I think could be useful for simplified output of member values without member names attached to that output.  I also think it would be useful when working with certain datasets that have different members with the same type that you want to do something with in one pass through that data set, or when you want to execute multiple methods in sequence during one pass through a dataset.  I added support to the Invoke-Member function so that it would support multiple members as well.

Here is the updated source code for the Invoke-Member function as well as a script to create im and … aliases for the Invoke-Member function:

Function Invoke-Member {
    param (
        [string[]]
$name = $(throw $($(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘ParameterArgumentValidationErrorNullNotAllowed’) -f $null,‘Name’)),
       
$inputObject = $null
   
)
    BEGIN {
    }
    PROCESS {
       
if ($inputObject -and $_) {
           
throw $(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘AmbiguousParameterSet’)
           
break
        } elseif ($inputObject) {
            foreach ($member in $name) {
               
Invoke-Expression “`$inputObject.$member”
           
}
        }
elseif ($_) {
           
foreach ($member in $name) {
               
Invoke-Expression “`$_.$member”
           
}
        } else {
           
throw $(Get-PSResourceString -BaseName ‘ParameterBinderStrings’ -ResourceId ‘InputObjectNotBound’)
        }
    }
    END {
    }
}
if (-not (Get-Alias -Name im -ErrorAction SilentlyContinue)) {
    New-Alias -Name im -Value Invoke-Member -Description ‘Invokes a member of each of a set of input objects.’
}
if (-not (Get-Alias -Name-ErrorAction SilentlyContinue)) {
    New-Alias -Name … -Value Invoke-Member -Description ‘Invokes a member of each of a set of input objects.’
}

Note that this function uses the Get-PSResourceString function that I published recently in my Cmdlet Extension Library (you can read more about what this library contains here).  If you want to use the Invoke-Member function by itself, you will have to change the calls to Get-PSResourceString with static strings that you want to throw on error instead.  To simplify sharing the Invoke-Member function with the community I have added it to my Cmdlet Extension Library and uploaded the updated version to the PowerShell Community site.

Thanks to Joel Bennett for his article about writing functions that can also be executed in the pipeline.  I didn’t end up using Joel’s template as is because I wanted Invoke-Member to follow the model of other cmdlets that have the InputObject parameter, but it was my starting point before I went through numerous revisions and ended up with the final version shown above in the Invoke-Member function code.

Comments/suggestions are welcome and appreciated, as always.

Kirk out.

Technorati Tags: , , , , ,

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: , , , , , , , ,