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.
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.
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
0 comments