Weekend Scripter: Use PowerShell to Find Dynamic Parameters

Weekend Scripter: Use PowerShell to Find Dynamic Parameters

  • Comments 2
  • Likes

Summary: Microsoft Scripting Guy, Ed Wilson, talks about using Windows PowerShell to discover dynamic parameters for his favorite cmdlets.

Microsoft Scripting Guy, Ed Wilson, is here. I submitted my session for SQL Saturday in Atlanta, Georgia. To be honest, I was not going to do so because it is only two weeks prior to TechEd in New Orleans—but hey, there are a lot of cool people that attend SQL Saturday. I think we will probably have an all-day Windows PowerShell track at SQL Saturday in Atlanta. We did last year, and it was an absolute blast.  The question came up when I was on the PowerScripting podcast, and I have been mulling it over for a while. Finally, we decided to go. So the Scripting Wife and I will be at SQL Saturday in Atlanta (assuming they approve my session submission).

Playing around with Get-Command

Anyway, I was playing around with Windows PowerShell this morning, and I decided to go back and read the Help file content for Get-Command. I ran across the –ArgumentList parameter. I can use it to change the context for the Get-Command cmdlet. Cool.   

Note   I am constantly reading over the Help content for Windows PowerShell because I simply cannot remember everything about everything. There is a difference between reading content when looking for an answer to a particular problem and simply grazing. When I am looking for a specific answer, I find the answer and I leave to go solve my problem. When I am grazing, I take my time and sample a bit of everything. I believe both types of reading are necessary.

OK, so I use the Get-Command cmdlet and the –ArgumentList parameter to display the definition of the command. Unfortunately, the first attempt does not work too well as shown here.

PS C:\> Get-Command Get-ChildItem -ArgumentList cert: | select definition

 

Definition

----------

...

No problem; I know how to deal with this issue. I need to expand the object that is contained in the property. To do this, I use the Select-Object cmdlet and choose the –ExpandProperty parameter. This results in a nice display of the parameter sets that are available when using the Get-Command cmdlet. These results are shown here.

PS C:\> Get-Command Get-ChildItem -ArgumentList cert: | select -expand definition

 

Get-ChildItem [[-Path] <string[]>] [[-Filter] <string>] [-Include <string[]>] [-Excl

ude <string[]>] [-Recurse] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert] [-S

SLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-Expir

ingInDays <int>] [<CommonParameters>]

 

Get-ChildItem [[-Filter] <string>] -LiteralPath <string[]> [-Include <string[]>] [-E

xclude <string[]>] [-Recurse] [-Force] [-Name] [-UseTransaction] [-CodeSigningCert]

[-SSLServerAuthentication] [-DnsName <DnsNameRepresentation>] [-Eku <string[]>] [-Ex

piringInDays <int>] [<CommonParameters>]

Well that is a command to keep in the back of my mind. I can get a nice display of a cmdlet parameter set on a per-provider basis by using the Get-Command cmdlet. Sweet!

Now, I want to find only the parameters. To do this, I use the Select-Object cmdlet and choose parameters. The command and its output are shown here.

PS C:\> Get-Command Get-ChildItem -ArgumentList cert: | select parameters

 

Parameters

----------

{[Path, System.Management.Automation.ParameterMetadata], [LiteralPath, System.Man...

Ah, ha. The Parameters property returns an object—actually, a collection of objects. So once again, I will send the result to the ExpandProperty parameter. This is shown here.

PS C:\> Get-Command Get-ChildItem -ArgumentList cert: | select -ExpandProperty parameters

 

Key                                        Value

---                                        -----

Path                                       System.Management.Automation.Parameter...

LiteralPath                                System.Management.Automation.Parameter...

Filter                                     System.Management.Automation.Parameter...

Include                                    System.Management.Automation.Parameter...

Exclude                                    System.Management.Automation.Parameter...

Recurse                                    System.Management.Automation.Parameter...

Force                                      System.Management.Automation.Parameter...

Name                                       System.Management.Automation.Parameter...

Verbose                                    System.Management.Automation.Parameter...

Debug                                      System.Management.Automation.Parameter...

ErrorAction                                System.Management.Automation.Parameter...

WarningAction                              System.Management.Automation.Parameter...

ErrorVariable                              System.Management.Automation.Parameter...

WarningVariable                            System.Management.Automation.Parameter...

OutVariable                                System.Management.Automation.Parameter...

OutBuffer                                  System.Management.Automation.Parameter...

UseTransaction                             System.Management.Automation.Parameter...

CodeSigningCert                            System.Management.Automation.Parameter...

SSLServerAuthentication                    System.Management.Automation.Parameter...

DnsName                                    System.Management.Automation.Parameter...

Eku                                        System.Management.Automation.Parameter...

ExpiringInDays                             System.Management.Automation.Parameter...

Now the information is contained in a generic dictionary object. This means there are a number of additional methods and properties to deal with. Actually, I am only interested in the Keys property. So, I use the group and dot technique, and select only the Keys. This is shown here.

PS C:\> (Get-Command Get-ChildItem -ArgumentList cert: | select -ExpandProperty parameters).keys

Path

LiteralPath

Filter

Include

Exclude

Recurse

Force

Name

Verbose

Debug

ErrorAction

WarningAction

ErrorVariable

WarningVariable

OutVariable

OutBuffer

UseTransaction

CodeSigningCert

SSLServerAuthentication

DnsName

Eku

ExpiringInDays

Groovy. Now all I need to do is sort my list of properties so I can feed the results to Compare-Object. So, I back up a bit and I store the expanded parameters in a variable. I do this for the Certificate provider and for the FileSystem provider. These two commands are shown here.

PS C:\> $cert = Get-Command Get-ChildItem -ArgumentList cert: | select -ExpandProperty parameters

PS C:\> $file = Get-Command Get-ChildItem -ArgumentList c: | select -ExpandProperty parameters

Now, I want to sort the keys, and store the sorted list of keys in a variable. The following two commands do this for me.

PS C:\> $certKeys = $cert.Keys | sort

PS C:\> $filekeys = $file.Keys | sort

Now it is time to use the Compare-Object cmdlet to compare the two lists of provider-specific parameters for the Get-ChildItem cmdlet. This command is shown here.

Compare-Object -ReferenceObject $filekeys -DifferenceObject $certKeys

Following are the commands and the output associated with the commands.

Image of command output

If I keep my comparisons consistent—that is, I use the FileSystem provider as my ReferenceObject, and I use the other providers for the DifferenceObject, the output will be consistent. The SideIndicator => will always point to new parameters added by the different PS Provider. Because the returned difference object is a PSCUSTOM object, it means that SideIndicator is a NoteProperty, and I can use it in a Where-Object statement. The following command returns only parameters added by DifferenceObject (my collection of Certificate provider-specific parameters).

PS C:\> Compare-Object -ReferenceObject $filekeys -DifferenceObject $certKeys | ? sideindicator -eq '=>'

 

InputObject                                SideIndicator

-----------                                -------------

CodeSigningCert                            =>

DnsName                                    =>

Eku                                        =>

ExpiringInDays                             =>

SSLServerAuthentication                    =>

Comparing Get-ChildItem with the Registry provider

Any drive I pass to the –ArgumentList parameter causes Get-Command to return provider-specific parameters. Therefore, I can use HKLM: as my drive to return Registry provider parameters. The following code illustrates the technique.

$reg = Get-Command Get-ChildItem -ArgumentList hklm: | select –ExpandProperty parameters

$file = Get-Command Get-ChildItem -ArgumentList c: | select -ExpandProperty parameters

$regKeys = $reg.Keys | sort

$filekeys = $file.Keys | sort

 Compare-Object -ReferenceObject $filekeys -DifferenceObject $regKeys

When I run the command, the following output displays.

Image of command output

I can see from the previous output that there are no added parameters to Get-ChildItem when it is used on the registry drives. Instead, I see that a number of parameters are actually removed. This makes sense when reviewing the missing parameters: Attributes, Directory, File, Hidden, ReadOnly, and System. These are related to files and folders, not to registry keys.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • Oisin Grehan posted a very elegant solution to this a while back:

    www.nivot.org/.../PowerShell20AboutDynamicParameters

    #----

    # this function will pass a drive name in position 0 as an unnamed argument

    # most path-oriented cmdlets accept this binding

    function Get-DynamicParameter {

       param(        

           [string]$command

       )

       $parameters = @{}

       get-psdrive | sort -unique provider | % {

           $parameters[$_.provider.name] = gcm $command -args "$($_.name):" | % {

               $c = $_; @($_.parameters.keys) | sort | ? {

                   $c.parameters[$_].isdynamic

               }

           }

       }

       $parameters  

    }

    #----

  • @Greg Wojan, yes it is a nice solution. Thanks for sharing.