Created
November 23, 2018 09:17
-
-
Save Trucido/3691286368432a260aa77cba0c638436 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.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. | |
.Parameter CommandName | |
The name of the command to get parameters for. | |
.Parameter ParameterName | |
Wilcard-enabled filter for parameter names. | |
.Parameter ModuleName | |
The name of the module which contains the command (this is for scoping) | |
.Parameter SkipProviderParameters | |
Skip testing for Provider parameters (will be much faster) | |
.Parameter SetName | |
The ParameterSet name to filter by (allows wildcards) | |
.Parameter Force | |
Forces including the CommonParameters in the output. | |
.Example | |
Get-Command Select-Xml | Get-Parameter | |
.Example | |
Get-Parameter Select-Xml | |
#> | |
function Get-Parameter { | |
[CmdletBinding(DefaultParameterSetName="ParameterName")] | |
param( | |
[Parameter(Position = 1, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] | |
[Alias("Name")] | |
[string[]]$CommandName, | |
[Parameter(Position = 2, ValueFromPipelineByPropertyName=$true, ParameterSetName="FilterNames")] | |
[string[]]$ParameterName = "*", | |
[Parameter(ValueFromPipelineByPropertyName=$true, ParameterSetName="FilterSets")] | |
[string[]]$SetName = "*", | |
[Parameter(ValueFromPipelineByPropertyName = $true)] | |
$ModuleName, | |
[Switch]$SkipProviderParameters, | |
[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}} | |
) | |
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, | |
[Parameter(Position=2)] | |
[System.Management.Automation.ProviderInfo]$Provider | |
) | |
foreach ($p in $MoreParameters | Where-Object { !$Parameters.ContainsKey($_.Name) } ) { | |
Write-Debug ("INITIALLY: " + $p.Name) | |
$Parameters.($p.Name) = $p | Select * | |
} | |
if ($Provider) { | |
[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} | |
if ($PSVersionTable.PSVersion.Major -ge 5) { | |
Write-Verbose "Get-Parameters for $($Command.Source)\$($Command.Name)" | |
$isCoreCommand = $Command.Source -eq "Microsoft.PowerShell.Management" | |
} else { | |
Write-Verbose "Get-Parameters for $($Command.ModuleName)\$($Command.Name)" | |
$isCoreCommand = $Command.ModuleName -eq "Microsoft.PowerShell.Management" | |
} | |
$Parameters = @{} | |
## We need to detect provider parameters ... | |
$NoProviderParameters = !$SkipProviderParameters | |
## Shortcut: assume only the core commands get Provider dynamic parameters | |
if(!$SkipProviderParameters -and $isCoreCommand) { | |
## 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.Count -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") | |
$MoreParameters = @() | |
try { | |
$MoreParameters = (Get-Command $command -Args $drive).Parameters.Values | |
} catch {} | |
if($MoreParameters.Count -gt 0) { | |
Add-Parameters $Parameters $MoreParameters $provider | |
} | |
} | |
# If for some reason none of the drive paths worked, just use the default parameters | |
if($Parameters.Count -eq 0) { | |
if($Command.Parameters) { | |
Add-Parameters $Parameters $Command.Parameters.Values $provider | |
} | |
} | |
} | |
## 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 { $_.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 | |
} | |
} | |
# 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} | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment