Private/Get-Parameter.ps1
# Borrowed from http://poshcode.org/5929 with a minor tweak for validateset - thanks all! Function Get-Parameter { #.Synopsis # Enumerates the parameters of one or more commands #.Description # Lists all the parameters of a command, by ParameterSet, including their aliases, type, etc. # # By default, formats the output to tables grouped by command and parameter set #.Example # Get-Command Select-Xml | Get-Parameter #.Example # Get-Parameter Select-Xml [CmdletBinding(DefaultParameterSetName="ParameterName")] param( # The name of the command to get parameters for [Parameter(Position = 1, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [Alias("Name")] [string[]]$CommandName, # The parameter name to filter by (allows Wilcards) [Parameter(Position = 2, ValueFromPipelineByPropertyName=$true, ParameterSetName="FilterNames")] [string[]]$ParameterName = "*", # The ParameterSet name to filter by (allows wildcards) [Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName="FilterSets")] [string[]]$SetName = "*", # The name of the module which contains the command (this is for scoping) [Parameter(ValueFromPipelineByPropertyName = $true)] $ModuleName, # Skip testing for Provider parameters (will be much faster) [Switch]$SkipProviderParameters, # Forces including the CommonParameters in the output [switch]$Force ) begin { $PropertySet = @( "Name", @{n="Position";e={if($_.Position -lt 0){"Named"}else{$_.Position}}}, "Aliases", @{n="Short";e={$_.Name}}, @{n="Type";e={$_.ParameterType.Name}}, @{n="ParameterSet";e={$paramset}}, @{n="Command";e={$command}}, @{n="Mandatory";e={$_.IsMandatory}}, @{n="Provider";e={$_.DynamicProvider}}, @{n="ValueFromPipeline";e={$_.ValueFromPipeline}}, @{n="ValueFromPipelineByPropertyName";e={$_.ValueFromPipelineByPropertyName}}, "ValidateSetValues" # This is a bit specific and not always applicable, but need it for this project.... ) function Join-Object { Param( [Parameter(Position=0)] $First, [Parameter(ValueFromPipeline=$true,Position=1)] $Second ) begin { [string[]] $p1 = $First | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name } process { $Output = $First | Select-Object $p1 foreach ($p in $Second | Get-Member -MemberType Properties | Where-Object {$p1 -notcontains $_.Name} | Select-Object -ExpandProperty Name) { Add-Member -InputObject $Output -MemberType NoteProperty -Name $p -Value $Second."$p" } $Output } } function Add-Parameters { [CmdletBinding()] param( [Parameter(Position=0)] [Hashtable]$Parameters, [Parameter(Position=1)] [System.Management.Automation.ParameterMetadata[]]$MoreParameters ) foreach ($p in $MoreParameters | Where-Object { !$Parameters.ContainsKey($_.Name) } ) { Write-Debug ("INITIALLY: " + $p.Name) $Parameters.($p.Name) = $p | Select * } [Array]$Dynamic = $MoreParameters | Where-Object { $_.IsDynamic } if ($dynamic) { foreach ($d in $dynamic) { if (Get-Member -InputObject $Parameters.($d.Name) -Name DynamicProvider) { Write-Debug ("ADD:" + $d.Name + " " + $provider.Name) $Parameters.($d.Name).DynamicProvider += $provider.Name } else { Write-Debug ("CREATE:" + $d.Name + " " + $provider.Name) $Parameters.($d.Name) = $Parameters.($d.Name) | Select *, @{ n="DynamicProvider";e={ @($provider.Name) } } } } } } } process { foreach ($cmd in $CommandName) { if ($ModuleName) {$cmd = "$ModuleName\$cmd"} Write-Verbose "Searching for $cmd" $commands = @(Get-Command $cmd) foreach ($command in $commands) { Write-Verbose "Searching for $command" # resolve aliases (an alias can point to another alias) while ($command.CommandType -eq "Alias") { $command = @(Get-Command ($command.definition))[0] } if (-not $command) {continue} Write-Verbose "Get-Parameters for $($Command.Source)\$($Command.Name)" $Parameters = @{} ## We need to detect provider parameters ... $NoProviderParameters = !$SkipProviderParameters ## Shortcut: assume only the core commands get Provider dynamic parameters if(!$SkipProviderParameters -and $Command.Source -eq "Microsoft.PowerShell.Management") { ## The best I can do is to validate that the command has a parameter which could accept a string path foreach($param in $Command.Parameters.Values) { if(([String[]],[String] -contains $param.ParameterType) -and ($param.ParameterSets.Values | Where { $_.Position -ge 0 })) { $NoProviderParameters = $false break } } } if($NoProviderParameters) { if($Command.Parameters) { Add-Parameters $Parameters $Command.Parameters.Values } } else { foreach ($provider in Get-PSProvider) { if($provider.Drives.Length -gt 0) { $drive = Get-Location -PSProvider $Provider.Name } else { $drive = "{0}\{1}::\" -f $provider.ModuleName, $provider.Name } Write-Verbose ("Get-Command $command -Args $drive | Select -Expand Parameters") try { $MoreParameters = (Get-Command $command -Args $drive).Parameters.Values } catch {} if($MoreParameters.Length -gt 0) { Add-Parameters $Parameters $MoreParameters } } # If for some reason none of the drive paths worked, just use the default parameters if($Parameters.Length -eq 0) { if($Command.Parameters) { Add-Parameters $Parameters $Command.Parameters.Values } } } ## Calculate the shortest distinct parameter name -- do this BEFORE removing the common parameters or else. $Aliases = $Parameters.Values | Select-Object -ExpandProperty Aliases ## Get defined aliases $ParameterNames = $Parameters.Keys + $Aliases foreach ($p in $($Parameters.Keys)) { $short = "^" $aliases = @($p) + @($Parameters.$p.Aliases) | sort-object { $_.Length } $shortest = "^" + @($aliases)[0] foreach($name in $aliases) { $short = "^" foreach ($char in [char[]]$name) { $short += $char $mCount = ($ParameterNames -match $short).Count if ($mCount -eq 1 ) { if($short.Length -lt $shortest.Length) { $shortest = $short } break } } } if($shortest.Length -lt @($aliases)[0].Length +1){ # Overwrite the Aliases with this new value $Parameters.$p = $Parameters.$p | Add-Member NoteProperty Aliases ($Parameters.$p.Aliases + @("$($shortest.SubString(1))*")) -Force -Passthru } # ValidateSet... $Parameters.$p = $Parameters.$p | Add-Member NoteProperty ValidateSetValues ($Parameters.$p.Attributes | Where{$_.TypeId.name -like 'ValidateSetAttribute'}).ValidValues -Force -Passthru } # Write-Verbose "Parameters: $($Parameters.Count)`n $($Parameters | ft | out-string)" $CommonParameters = [string[]][System.Management.Automation.Cmdlet]::CommonParameters foreach ($paramset in @($command.ParameterSets | Select-Object -ExpandProperty "Name")) { $paramset = $paramset | Add-Member -Name IsDefault -MemberType NoteProperty -Value ($paramset -eq $command.DefaultParameterSet) -PassThru foreach ($parameter in $Parameters.Keys | Sort-Object) { # Write-Verbose "Parameter: $Parameter" if (!$Force -and ($CommonParameters -contains $Parameter)) {continue} if ($Parameters.$Parameter.ParameterSets.ContainsKey($paramset) -or $Parameters.$Parameter.ParameterSets.ContainsKey("__AllParameterSets")) { if ($Parameters.$Parameter.ParameterSets.ContainsKey($paramset)) { $output = Join-Object $Parameters.$Parameter $Parameters.$Parameter.ParameterSets.$paramSet } else { $output = Join-Object $Parameters.$Parameter $Parameters.$Parameter.ParameterSets.__AllParameterSets } Write-Output $Output | Select-Object $PropertySet | ForEach-Object { $null = $_.PSTypeNames.Insert(0,"System.Management.Automation.ParameterMetadata") $null = $_.PSTypeNames.Insert(0,"System.Management.Automation.ParameterMetadataEx") # Write-Verbose "$(($_.PSTypeNames.GetEnumerator()) -join ", ")" $_ } | Add-Member ScriptMethod ToString { $this.Name } -Force -Passthru | Where-Object {$(foreach($pn in $ParameterName) {$_ -like $Pn}) -contains $true} | Where-Object {$(foreach($sn in $SetName) {$_.ParameterSet -like $sn}) -contains $true} } } } } } } } |