PowerCLI 4.1: A fork in the road

UPDATE 10-JAN-11: To deal with the issues identified below, I published a beta version of the VMware vSphere PowerPack with PowerCLI 4.1 or later support.  You can read more about the beta and how to install it here.

Earlier this week, VMware released version 4.1 of the PowerCLI.  This release brings some great improvements that the community has been waiting for, and you can read about them on the VMware PowerCLI site and a number of other blogs that have been publicizing the release.  I’m not here to talk about the new features and improvements however.  I’m writing this to notify you about the breaking changes that were introduced in this release that haven’t been discussed externally but that you will want to know about.

With version 4.1 of the PowerCLI, the VMware team has changed the namespaces used in the object model behind the PowerCLI.  The objects themselves have stayed the same, but the namespaces have changed.  This change has a number of impacts once PowerCLI 4.1 is installed, including but not limited to the following:

  • Any PowerShell function that uses strongly typed parameter names with the VMware PowerCLI 4.0 or earlier type names will no longer function properly without an update.
  • Any PowerShell script that uses the is or as operators with the VMware PowerCLI 4.0 or earlier type names type names will no longer function properly without an update.
  • Any PowerGUI extensions (read: PowerPacks) written for PowerCLI 4.0 or earlier will no longer function properly without an update.
  • Any PowerShell scripts that use the VMware PowerCLI 4.0 or earlier type names inside of Add-Type calls will no longer function properly.

In general, any code or script written that is dependent on these type names will have issues once you upgrade to PowerCLI 4.1.  It also means that once these items that don’t work with 4.1 are updated, they may no longer work with PowerCLI 4.0 and earlier.  Also note that these are just PowerShell-related impacts.  If you’re using other languages to manage or automate VMware you need to be aware of the impacts for those languages as well. Here are a few PowerShell-specific examples of the impact of these breaking changes:

  1. The PowerCLI Community Extensions won’t work with PowerCLI 4.1 until they have been updated, and once they have been updated they will not work with PowerCLI 4.0 and earlier as long as they continue to use strongly typed parameter names (which they should).
  2. Scripts on PoshCode like this one and this one will suffer the same fate since they use strongly typed parameters in the advanced functions.
  3. Blog posts like this one from Glenn Sizemore and this one by Maish Saidel-Keesing will only work with PowerCLI 4.0 and earlier unless they are updated.
  4. The VMware Infrastructure PowerPack for PowerGUI and the Virtualization EcoShell will return data from the nodes, however actions will not appear and icons and charts will not show up in the grid.
  5. The VMware Community PowerPack for PowerGUI and the Virtualization EcoShell will return data from the nodes, however actions will not appear and icons and charts will not show up in the grid.
  6. Any blog posts that mentions PowerCLI object types will now be out of date.
  7. Books like this one will contain examples that are now broken.

As you can see, the PowerCLI 4.1 release comes with changes that are pretty far reaching, and they are definitely going to cause confusion in the community.  Unfortunately, since these changes are now in the wild, we’re at a fork in the road where some community contributions will only support 4.0 and earlier for a while and others, as they start supporting 4.1 and later, may only support 4.1 and later depending on how they add that support.  Changes like this are never fun, so please be aware of these changes when considering when to upgrade PowerCLI in your environment. As far as the PowerPack issues go, we will add support for the PowerCLI 4.1 release to the VMware Infrastructure PowerPack soon, but it will take a little while for us to work out the details and do the appropriate testing.  Until then, please don’t upgrade the PowerCLI on your systems where you use the VMware Infrastructure PowerPack. Thanks, Kirk out.

Share this post:

Discover dormant AD accounts with the Windows Security PowerPack

Last week I had the pleasure of participating in a webinar with Randy Franklin Smith of Ultimate Windows Security fame where we demonstrated and discussed the Windows Security PowerPack that was recently published in the PowerPack Library.  Randy’s a great guy to present with and this webinar was a lot of fun.  Judging by the amount of questions and positive feedback we’ve received, it seemed to generate a lot of interest  as well.

A recording of the webinar is now available, so if you missed catching it live you can go here and watch it at your leisure.  You won’t be able to ask questions during the presentation of course, but that’s what the comments on this blog and the PowerGUI Forums are for. 🙂

Enjoy!

Kirk out.

Share this post:

PowerGUI Visual Studio is now in beta!

Due to popular demand, Adam Driscoll has just released Beta 1 of his PowerGUI Visual Studio (aka PowerGUI VSX) project!

If you missed my blog about this last week and don’t know what this product is, it’s an extension for Visual Studio that adds PowerGUI’s editor with Intellisense, syntax highlighting and snippets for PowerShell script files to Visual Studio!  This can make it much easier to create PowerShell scripts or modules if you’re already working inside Visual Studio.

You can learn all about this great project and download the beta release by going to the PowerGUI VSX page on CodePlex now!

This project requires that the following prerequisites be installed first:

Please share any feedback you have for this release in the comments on this blog, on the CodePlex site itself, or on the PowerGUI forums.

Enjoy!

Kirk out.

Share this post:

PowerShell support in Visual Studio!

Update 20-Jun-2010: This is now released as a beta! It supports Intellisense and Syntax Highlighting for any modules you have loaded in PowerGUI, as well as PowerGUI Snippets! Go download it here now!

Here’s something really cool for all the developer types out there.  Adam Driscoll, one of the developers here at Quest Software, is working on an extension for Visual Studio 2010 that integrates PowerGUI Script Editor functionality into the Visual Studio 2010 IDE!  It’s not released yet, but you can learn more about it on the PowerGUI VSX site on CodePlex.  Here’s a teaser screenshot to whet your tastebuds:

I’d love to hear your feedback on this, so please leave comments and let me know if this is of interest to you or not.

Thanks,

Kirk out.

Share this post:

PowerGUI 2.1: The release that keeps on giving

Last Monday while I was down at Tech·Ed we quietly released PowerGUI 2.1 on our website.  I’ve been looking forward to us getting this release out the door for quite a while because there are some really cool features in the release that I wanted to share with you (some of which I’ve been hinting about on my blog recently), so it was very exciting to see this get released.  Since it happened at Tech·Ed though, my schedule was completely booked and I just couldn’t find a minute to start blogging about the release.  Now that I’m back home and fully recovered from a week packed with all sorts of cool technology, I can catch up and share this release with the rest of you.

Aside from the great performance improvements that were made in the Script Editor, not to mention the Charts and custom HTML support in the administrative console, there’s one particular feature that really grabbed my attention in this release: we now have a documented and supported SDK for the PowerGUI Script Editor!  This is great news because up to this point the only extensions that were possible were in the administrative console where you could create PowerPacks.  Now with 2.1 available anyone can create extensions for the Script Editor that add really cool functionality to it as well!

The screenshots I was blogging about a few weeks ago showed some of the Add-ons that I have been working on, and I just started publishing some of those Add-ons in the Script Editor Add-on category on PowerGUI.org.  These Add-ons are just PowerShell modules so you can see exactly how they work by opening the module files in the Script Editor.  With Add-ons, not only do you get the features that were implemented in the core product, you now get to pick and choose additional features that you want as they become available by installing Add-ons.

What sort of things can you do with Add-ons?  Well, for starters you can sign your script files:

image

publish scripts online:

image

or change your embedded PowerShell Console to blue:

image

If that inspires you, you can also try creating your own Add-on:

image

And if you want to learn more about how you can create an Add-on, there’s even a tutorial available to help get you started.

There are some other useful Add-ons available right now, and more are in development so check the Script Editor Add-on category often to see what has been recently published.

If there are Add-ons you would like to see developed but you aren’t comfortable creating them yourself, share the ideas on our forums so that others can step up and help you out (or maybe even create the Add-on for you).

The Script Editor SDK that was added to this release is brand new to the PowerGUI product and we would love to hear your feedback on it.  Please speak up and let us know what you think about the SDK, the Add-ons we have made available so far, or anything else related to PowerGUI.  We’re always listening.

Thanks and happy scripting!

Kirk out.

Share this post:

Taking the PowerGUI Train Down to New Orleans

This weekend I’m heading down to New Orleans, LA for Tech·Ed 2010 North America.  I’m totally excited about the trip because (a) I’ve never been to New Orleans and (b) Tech·Ed is always a ton of fun!  This year I’ll be working the PowerShell booth again plus I’ll be hanging around the Quest booth quite a bit when I’m not in a breakout session.  One of the fun things I’ll be doing while I’m there is on Monday June 7th at 2:15 PM CST (mark your calendar!) when I’ll be at the Quest booth taking questions about PowerShell and PowerGUI and doing demos of some cool new features that we’ve been busy working on, such as a blue PowerShell Console and Online Help.

That’s not the only features that I’ll be talking about though…here’s another teaser screenshot showing you something else you’ll be able to do in the PowerGUI Script Editor really, really soon: Script Signing!

script signing code signing PowerGUI Script Editor

If you’d like to hear more about PowerGUI and what we’ve been up to, come by the 30 minute Q&A session on Monday.  Or, if you can’t make that session track down myself or Dmitry or head over to the Quest booth in the partner expo and ask for a demo of PowerGUI at any time.  I’d love to hear how you’re using PowerShell and PowerGUI and show you some of the new features that I haven’t shared here yet.

See you in New Orleans!

Kirk out.

P.S. I’m not literally taking the train down to New Orleans (although that would be really fun), but I am bringing PowerGUI with me on my laptop.  Maybe after the PowerShell market grows a little more I’ll be able to convince Quest to have a locomotive built for PowerGUI that we can use when travelling to events like Tech·Ed! 🙂

P.P.S. If you’re not going to Tech·Ed but you want to share how you’re using PowerShell and PowerGUI with me anyway, drop me a line anytime and tell me about it, or just share it on our forums!

Share this post :

Online help in the PowerGUI Script Editor

Today I’d like to share a little more of what I’ve been working on recently.  Here’s another teaser of something you’ll be able to get for free in the PowerGUI Script Editor very soon:

Online help in the PowerGUI Script Editor

And if you missed the cool Rock-Paper-Scissors support as well, go check out Tuesday’s blog post! 😉

More to come!

Kirk out.

Share this post:

Coming soon to a release near you

Hi everyone,

I’ve been really quiet lately while I’ve been focused on a bunch of fun projects that I’ve been working on for the next release of PowerGUI.  That release isn’t available just yet (soon though – watch this space!), but I can start sharing a few teasers to whet your appetites in the meantime.  Here’s a screenshot to share a little bit of what I’ve been working on recently:

     Blue console with transparency in the PowerGUI Script Editor

That’s right, it’s Rock-Paper-Scissors for Windows PowerShell!  No, no, that’s not it…look at the cool blue console with the transparent effect applied to it.

Some neat things like this and more are coming your way soon in PowerGUI!

Kirk out.

Share this post:

PowerGUI Pro is now available!

Extra! Extra! Read all about it!

PowerGUI has gone Pro!

You’re favorite PowerShell engine is now available in a cool new package.  PowerGUI Pro has all of the same great features that you know and love from PowerGUI Freeware plus it allows you to:

  • Use PowerShell from your favorite mobile device with MobileShell!
  • Protect your scripts using integrated version control!

All that and you get full commercial support from Quest Software to boot!

If you hurry you can buy it for only $99/user for the first 60 days.  After that, it will return to the regular price of $199/user.

Want to learn more?  You can read all about it here:

http://www.quest.com/PowerGUIPro

If you have any questions or want to learn more, feel free to leave a comment or post your question on our forums.

Thanks,

Kirk out.

Share this post:

PowerShell 3.0: Why wait? Importing typed objects with typed properties from a CSV file

After working exclusively with PowerShell in my career for over two years now, it has become quite clear to me that the single most valuable feature in Microsoft Windows PowerShell, in my opinion anyway, is its extensibility.  In particular, it’s how easily it can be extended in PowerShell itself through a combination of PowerShell scripts and XML files, without the need of a compiler.  There are some features that are a very close second to that (consistency and discoverability), but the extensibility that PowerShell provides is truly second to none.

Version 1.0 of PowerShell was extendible from within PowerShell via combinations of PowerShell functions, the .NET Framework, WMI, ADSI, Add-Member and external ps1xml files that define type extensions and formats, not to mention snapins.  Using these features in PowerShell 1.0, I found them more than capable to allow me to create some really creative workarounds to some challenging issues that were identified in that version.  Not everything can be worked around, of course; some bugs can really only be fixed by the PowerShell team, and that will always be the case.  Those bugs aside though, PowerShell 1.0 really did a great job of providing a ton of functionality and enabling people like you and me to add even more.

Still, the solutions I could come up with in PowerShell 1.0 didn’t function quite the same as a regular PowerShell cmdlet.  There were some subtle differences and limitations in what you could do in that release.  Version 2.0 of PowerShell addresses some of those limitations, bringing even more extendibility options to the table with advanced functions, classes (using Add-Type), modules, and proxy functions.  These new options are a welcome addition to the PowerShell ecosystem and they allow me to ask the question “Why wait for PowerShell 3.0?”, a question I can now try to answer with creative solutions to problems in PowerShell and with creative ways to extend PowerShell so that you don’t necessarily have to wait for the next release to get new features or functionality that you might be looking for.  This article is the first in what I hope becomes a series of solutions that allow you to get some functionality you might find in PowerShell 3.0 without having to wait for it.

First on my list of areas needing improvement comes from a recent question that came up on a mailing list I follow:

I’m using Import-CSV to import a two-"column" CSV file and return a custom object with two additional properties. But I want the first property to be an Int and the second to be a DateTime. How do I do that? (I’ve tried several strategies, including explicit casting of the types in an array, but they come out as strings.

Import-Csv is a really, really handy cmdlet.  It allows you to import the contents of a csv (character-separated value) file as a collection of objects so that you can then do things with them.  It is commonly used in bulk provisioning or modification scenarios, where administrators can work with the data in the csv first if necessary and then write a script to do the required work according to the data from each entry in the csv file.

It has certain limitations, though, and those limitations can cause you to have to include additional complexity in your scripts to work around the limitations.  When you import data using Import-Csv, every property on the objects that are created are all of type string.  If you are trying to work with some properties containing dates (System.Datetime) or others containing numeric values or other types, complicated pipelines with manual conversion using ForEach-Object or Select-Object is required.  That’s fine for one-off scenarios, but this has come up before, and it makes sense for Import-Csv to allow users to set the types for the properties on the objects they are importing — that’s one problem to solve.

Another limitation is that objects imported from Import-Csv don’t necessarily have an appropriate type name associated with them.  If the file was created manually or by another program, the objects will be generic PSObjects.  If the file was created by exporting data from PowerShell using Export-Csv, a type may be included in the csv file but most csv files I work with come from sources other than PowerShell.  You can customize the object type name however you like (and this is recommended if you are doing something like Importing data from a csv file into the PowerGUI Admin Console so that you can then associate relevant actions with that object type), but again this isn’t something you would want to do each time you import csv data because it’s just that much more work.

It sounds to me like this user would have preferred being able to call Import-Csv using a syntax something like this:

Import-Csv C:\birthdays.csv -Type String,Int,Date

or, with a slightly more powerful example, perhaps like this:

Import-Csv C:\birthdays.csv -TypeMap @{Age='Int';Birthday=[System.DateTime]} -As 'BirthdayRecord' -UseETS -Overwrite

We could simply put in a feature request to the PowerShell Connect site (something I recommend you do whenever you come across something you feel is missing or incorrect), but that won’t do anything to help us today.  How can we solve those two problems now and bring Import-Csv into a level of functionality we might like to think we’ll get in PowerShell 3.0, like what is shown above, in such a way that getting typed objects with properly typed properties is as simple as importing data from a csv file using nothing but an Import-Csv command?  The answer to that comes from one of my new best friends in PowerShell: proxy functions.  The proxy function feature in PowerShell allows you to create an advanced function with the same name as a cmdlet that internally calls that cmdlet.  Since functions have a higher precedence that cmdlets in the command precedence order, you’ll always get the proxy function if it’s loaded when you are using the basic (that is to say, non-qualified) cmdlet name.

Creating a proxy function is easy.  All you have to do is execute a static .NET method called Create on the System.Management.Automation.ProxyCommand class and pass in a new System.Management.Automation.CommandMetaData object created by using the result of calling Get-Command for the cmdlet you want to proxy to get the internal script that will be the body of the proxy function, then wrap that in a function with the same name as the cmdlet you are proxying and then, to add that function to your current script file, output it to another file and then copy it over using an editor.  Huh?  That sure sounds complicated.  Well, since it’s not all wrapped up in a cmdlet for you, it is more complicated than it needs to be.

Let’s try that again.

Creating a proxy function is easy.  All you have to do is follow a few steps to get the command you need to run that generates the proxy function body, and then work within your favorite editor to copy that command body into your function in the file you are working on.  My favorite editor is PowerGUI, so I’ll use that in my example.  First, make sure you have installed PowerGUI with the new PowerShell 2.0 snippets (you can read more about those here) and then open up your PowerGUI Script Editor and follow these steps:

  1. Select Edit | Insert Snippet.
  2. Scroll down the list of snippets until you find a folder called “PowerShell v2” and double-click on it.
  3. Scroll down the list of PowerShell v2 snippets until you find one called “function (proxy)” and double-click on it to insert that snippet.
  4. In the snippet Name field, type in the name of the cmdlet you want to create a proxy for and hit enter.

If you like to learn by watching others, you can watch a demonstration of this (and other snippets) in a screencast that is posted on YouTube.  If you’re a keep-your-fingers-on-the-keyboard junkie like me, you can use shortcuts and type in the snippet folder and name and get this done very quickly.  When you’re done, you’ll have a function that looks something like this:

<#
    For more information about proxy functions, see the following article on the
    Microsoft PowerShell Team blog:

        http://blogs.msdn.com/powershell/archive/2009/01/04/extending-and-or-modifing-commands-with-proxies.aspx
#>

function Import-Csv {
    <#
        To create a proxy function for the Import-Csv cmdlet, paste the results of the following command into the body of this function and then remove this comment:
        [Management.Automation.ProxyCommand]::Create((New-Object Management.Automation.CommandMetaData (Get-Command Import-Csv)))
    #>
}

That’s not exactly a proxy function yet.  There’s one more step you need to take, as described in the comment inside the proxy function.  That comment indicates you need to run the command inside it and paste the results of that command over the comment itself.  Copy the command as described in that comment and paste it in the embedded PowerShell Console window that is docked in your PowerGUI Script Editor, and once you have it pasted there, run it by pressing enter.  The result of that command is string output that will become the main body of your proxy function.  If you did this for Import-Csv like I did, it will look like this:


[CmdletBinding(DefaultParameterSetName='Delimiter')]
param(
    [Parameter(ParameterSetName='Delimiter', Position=1)]
    [ValidateNotNull()]
    [System.Char]
    ${Delimiter},

    [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
    [Alias('PSPath')]
    [System.String[]]
    ${Path},

    [Parameter(ParameterSetName='UseCulture', Mandatory=$true)]
    [ValidateNotNull()]
    [Switch]
    ${UseCulture},

    [ValidateNotNullOrEmpty()]
    [System.String[]]
    ${Header})

begin
{
    try {
        $outBuffer = $null
        if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
        {
            $PSBoundParameters['OutBuffer'] = 1
        }
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Import-Csv', [System.Management.Automation.CommandTypes]::Cmdlet)
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}
<#

.ForwardHelpTargetName Import-Csv
.ForwardHelpCategory Cmdlet

#>

Select all of that text that was output in your docked PowerShell Console window and copy it to your clipboard.  Then paste it over the original comment that told you to do this.  Now you have a proxy function.  It doesn’t do anything different than the cmdlet you are proxying yet, but when it is loaded in your PowerShell session it will proxy that cmdlet properly.

So now you might be saying to yourself: “That’s great (although the process could be a little more streamlined…), but now what do I do?”.  Now you can add your own parameters that you wish were on the original cmdlet in the first place, making the proxy function much more powerful.  For our example with Import-Csv that I showed earlier, I would like to be able to specify the type of the properties in the csv file, either as an array when I want to specify all property types or as a hash table when I only want to specify a type for a few named properties, knowing that the rest will default to string.  I’ll accomplish that by adding a Type and a TypeMap parameter to my Import-Csv proxy function.  I’d also like to be able to specify the type of the object that is imported using Import-Csv, and I’d like to be able to define whether my type name should be treated as an Extended Type Name extension as well as whether or not the current type hierarchy should be overwritten or not.  I’ll accomplish that by adding As, UseExtendedTypeSystem (alias UseETS), and OverwriteTypeHierarchy parameters.

Those changes will allow me to use the syntax I proposed above without waiting for someone else to give it to me.  By taking the time to create the proxy function that supports these parameters I’ll save myself and others time and complexity in the scripts they write by moving all of the extra pipeline complexity that would otherwise be necessary directly inside the proxy function.  It is worth noting that a proxy command isn’t as efficient as it would be if the added functionality were included in the cmdlet itself, but that’s not the point.  The point is that you can extend cmdlets when they leave you wanting more today rather than waiting to see if PowerShell 3.0 includes the extensions you want or not tomorrow (or three years from now, who knows when it will be released).

The resulting proxy function is a pretty good sized function, but we’ve added quite a few features to it as well, and those features need to have some logic to support them.  I’m including my version of the Import-Csv proxy function at the bottom of this post in its entirety so that you can give it a try yourself and see if it helps you out.  With the exception of the parameter definitions I added to the param statement, all logic supporting the new parameters I have added is enclosed in collapsible regions so that you can see the specific locations where I inserted my logic.  That should make it a little easier for you to see how logic can be added within a proxy function, enabling you to experiment a little and create your own PowerShell 3.0 flavors of your favorite cmdlets.  If you prefer to download the ps1 file containing the proxy command directly, I have also shared that on my SkyDrive, here.

There are several other important things I should mention about proxy functions, as follows:

  1. You can add parameters, modify parameters, remove parameters, or leave parameters unchanged in proxy functions.
  2. If you add parameters, you need to remove them from the parameter collection ($PSBoundParameters) before you create your wrapped command so that those parameters are not passed to the cmdlet you are proxying.  You may also have to do this if you modify parameters, depending on the modifications you make.
  3. If you find you are adding pipelines to certain commands you call on a regular basis, it is likely a sign that the cmdlet itself needs improvement.  Consider creating proxy functions in these situations so that you don’t have to do as much typing in the long run.
  4. If you create and use proxy functions, share them with the community so that the PowerShell team can see where cmdlets could be improved.  You can’t influence what goes in PowerShell 3.0 if you’re not sharing.

Here’s the final version of my Import-Csv proxy function:

#Requires -Version 2.0

function Import-Csv {
    <#

    .ForwardHelpTargetName Import-Csv
    .ForwardHelpCategory Cmdlet

    #>

    [CmdletBinding(DefaultParameterSetName='Delimiter')]
    param(
        [Parameter(ParameterSetName='Delimiter', Position=1)]
        [ValidateNotNull()]
        [System.Char]
        ${Delimiter},

        [Parameter(Mandatory=$true, Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
        [Alias('PSPath')]
        [System.String[]]
        ${Path},

        [Parameter(ParameterSetName='UseCulture', Mandatory=$true)]
        [ValidateNotNull()]
        [Switch]
        ${UseCulture},

        [ValidateNotNullOrEmpty()]
        [System.String[]]
        ${Header},

        [ValidateNotNullOrEmpty()]
        [System.String[]]
        ${Type},

        [ValidateNotNullOrEmpty()]
        [System.Collections.Hashtable]
        ${TypeMap},

        [ValidateNotNullOrEmpty()]
        [System.String]
        ${As},

        [Alias('UseETS')]
        [ValidateNotNull()]
        [Switch]
        ${UseExtendedTypeSystem},

        [ValidateNotNull()]
        [Switch]
        ${OverwriteTypeHierarchy}
    )

    begin {
        try {
            $outBuffer = $null
            if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) {
                $PSBoundParameters['OutBuffer'] = 1
            }
            $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Import-Csv', [System.Management.Automation.CommandTypes]::Cmdlet)

            #region Initialize helper variables used in the processing of the additional parameters.
            $scriptCmdPipeline = ''
            #endregion

            #region Process and remove the Type parameter if it is present, modifying the pipelined command appropriately.
            if ($Type) {
                $PSBoundParameters.Remove('Type') | Out-Null
                $scriptCmdPipeline += @'
 | ForEach-Object {
    for ($index = 0; ($index -lt @($_.PSObject.Properties).Count) -and ($index -lt @($Type).Count); $index++) {
        $typeObject = [System.Type](@($Type)[$index])
        $propertyName = @($_.PSObject.Properties)[$index].Name
        $_.$propertyName = & $ExecutionContext.InvokeCommand.NewScriptBlock("[$($typeObject.FullName)]`$_.`$propertyName")
    }
    $_
}
'@
            }
            #endregion

            #region Process and remove the TypeMap parameter if it is present, modifying the pipelined command appropriately.
            if ($TypeMap) {
                $PSBoundParameters.Remove('TypeMap') | Out-Null
                $scriptCmdPipeline += @'
 | ForEach-Object {
     foreach ($key in $TypeMap.keys) {
        if ($TypeMap[$key] -is [System.Type]) {
            $typeObject = $TypeMap[$key]
        } else {
            $typeObject = [System.Type]($TypeMap[$key])
        }
        $_.$key = & $ExecutionContext.InvokeCommand.NewScriptBlock("[$($typeObject.FullName)]`$_.`$key")
    }
    $_
}
'@
            }
            #endregion

            #region Process and remove the As, UseExtendedTypeSystem and OverwriteTypeHierarchy parameters if they are present, modifying the pipelined command appropriately.
            if ($As) {
                $PSBoundParameters.Remove('As') | Out-Null
                $customTypeName = $As
                if ($UseExtendedTypeSystem) {
                    $PSBoundParameters.Remove('UseExtendedTypeSystem') | Out-Null
                    $customTypeName = '$($_.PSObject.TypeNames[0] -replace ''#.*$'','''')#$As'
                }
                if ($OverwriteTypeHierarchy) {
                    $PSBoundParameters.Remove('OverwriteTypeHierarchy') | Out-Null
                    $scriptCmdPipeline += @"
 | ForEach-Object {
     `$typeName = "$customTypeName"
     `$_.PSObject.TypeNames.Clear()
    `$_.PSObject.TypeNames.Insert(0,`$typeName)
    `$_
}
"@
                } else {
                    $scriptCmdPipeline += @"
 | ForEach-Object {
     `$typeName = "$customTypeName"
    `$_.PSObject.TypeNames.Insert(0,`$typeName)
    `$_
}
"@
                }
            } else {
                if ($UseExtendedTypeSystem) {
                    $PSBoundParameters.Remove('UseExtendedTypeSystem') | Out-Null
                }
                if ($OverwriteTypeHierarchy) {
                    $PSBoundParameters.Remove('OverwriteTypeHierarchy') | Out-Null
                }
            }
            #endregion

            $scriptCmd = {& $wrappedCmd @PSBoundParameters}

            #region Append our pipeline command to the end of the wrapped command script block.
            $scriptCmd = $ExecutionContext.InvokeCommand.NewScriptBlock(([string]$scriptCmd + $scriptCmdPipeline))
            #endregion

            $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
            $steppablePipeline.Begin($PSCmdlet)
        }
        catch {
            throw
        }
    }

    process {
        try {
            $steppablePipeline.Process($_)
        }
        catch {
            throw
        }
    }

    end {
        try {
            $steppablePipeline.End()
        }
        catch {
            throw
        }
    }
}

Are you still with me?  Whew, if you stuck with me this far, thanks!  There’s a lot of information here, and while it’s definitely not something for a beginner, if you’re comfortable experimenting in PowerShell I encourage you to give proxy functions a try and see what solutions you can come up with.  Or, if you don’t mind taking the time to leave me a note, let me know what your biggest pains are with cmdlets today that you think could be solved with proxy functions and I’ll see what I can do to help create solutions for those.  The feedback system really works, so don’t be shy, participate by either sharing solutions or letting others like me know what your problems are so that we can continue to help evolve PowerShell into the best scripting environment out there!

Thanks for listening!

Kirk out.

Share this: