PoshCode Archive  Artifact [6c84d768c5]

Artifact 6c84d768c5ad9594a2df395717936a2f1d8a18273caec22c1abd909e4559f782:

  • File Get-Parameter.ps1 — part of check-in [e3282ec24e] at 2018-06-10 13:16:04 on branch trunk — This is another Must Have upgrade, because I screwed up the last one ;-) (user: JasonMArcher size: 17416)

# encoding: ascii
# api: powershell
# title: Get-Parameter
# description: This is another Must Have upgrade, because I screwed up the last one ;-)
# version: 2.6
# type: script
# author: JasonMArcher
# license: CC0
# function: Join-Object
# x-poshcode-id: 2815
# x-derived-from-id: 3794
# x-archived: 2016-10-25T20:54:21
# x-published: 2011-07-23T20:29:00
#
# Added -ParameterName parameter to filter returned parameters
# Added custom ToString() implementation to support -Like and -Match on the output
# Enumerate the Parameters of a command by ParameterSet, including DynamicParameters
# Now uses FormatData so the output is objects
# Added calculation of shortest names to the aliases (borrowed from Shay Levy http://poshcode.org/1982)
#
#Requires -version 2.0

#.Synopsis
#  Enumerates the parameters of one or more commands
#.Notes
#  With many thanks to Hal Rottenberg, Oisin Grehan and Shay Levy
#  Version 0.80 - April 2008 - By Hal Rottenberg http://poshcode.org/186
#  Version 0.81 - May 2008 - By Hal Rottenberg http://poshcode.org/255
#  Version 0.90 - June 2008 - By Hal Rottenberg http://poshcode.org/445
#  Version 0.91 - June 2008 - By Oisin Grehan http://poshcode.org/446
#  Version 0.92 - April 2008 - By Hal Rottenberg http://poshcode.org/549
#               - ADDED resolving aliases and avoided empty output
#  Version 0.93 - Sept 24, 2009 - By Hal Rottenberg http://poshcode.org/1344
#  Version 1.0  - Jan 19, 2010 - By Joel Bennett http://poshcode.org/1592
#               - Merged Oisin and Hal's code with my own implementation
#               - ADDED calculation of dynamic paramters
#  Version 2.0  - July 22, 2010 - By Joel Bennett http://poshcode.org/get/2005
#               - CHANGED uses FormatData so the output is objects
#               - ADDED calculation of shortest names to the aliases (idea from Shay Levy http://poshcode.org/1982,
#                 but with a correct implementation)
#  Version 2.1  - July 22, 2010 - By Joel Bennett http://poshcode.org/2007
#               - FIXED Help for SCRIPT file (script help must be separated from #Requires by an emtpy line)
#               - Fleshed out and added dates to this version history after Bergle's criticism ;)
#  Version 2.2  - July 29, 2010 - By Joel Bennett http://poshcode.org/2030
#               - FIXED a major bug which caused Get-Parameters to delete all the parameters from the CommandInfo
#  Version 2.3  - July 29, 2010 - By Joel Bennett 
#               - ADDED a ToString ScriptMethod which allows queries like:
#                 $parameters = Get-Parameter Get-Process; $parameters -match "Name"
#  Version 2.4  - July 29, 2010 - By Joel Bennett http://poshcode.org/2032
#               - CHANGED "Name" to CommandName
#               - ADDED ParameterName parameter to allow filtering parameters
#               - FIXED bug in 2.3 and 2.2 with dynamic parameters
#  Version 2.5  - December 13, 2010 - By Jason Archer http://poshcode.org/2404
#               - CHANGED format temp file to have static name, prevents bloat of random temporary files
#  Version 2.6  - July 23, 2011 - By Jason Archer (This Version)
#               - FIXED miscalculation of shortest unique name (aliases count as unique names),
#                 this caused some parameter names to be thrown out (like "Object")
#               - CHANGED code style cleanup
#
#.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
#.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 Force
#  Forces including the CommonParameters in the output
[CmdletBinding()]
param ( 
   [Parameter(Position=1,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
   [Alias("Name")]
   [string[]]$CommandName
,
   [Parameter(Position=2,ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
   [string[]]$ParameterName="*"
,
   [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
   $ModuleName
,
   [switch]$Force
)

Function global: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
    #.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 Force
    #  Forces including the CommonParameters in the output
    [CmdletBinding()]
    param(
        [Parameter(Position = 1, Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
        [string[]]$CommandName
        ,
        [Parameter(Position = 2, ValueFromPipelineByPropertyName=$true)]
        [string[]]$ParameterName = "*"
        ,
        [Parameter(ValueFromPipelineByPropertyName = $true)]
        $ModuleName
        ,
        [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
            }
        }
    }

    process {
        foreach ($cmd in $CommandName) {
        if ($ModuleName) {$cmd = "$ModuleName\$cmd"}
        $commands = @(Get-Command $cmd)

        foreach ($command in $commands) {
            # resolve aliases (an alias can point to another alias)
            while ($command.CommandType -eq "Alias") {
                $command = @(Get-Command ($command.definition))[0]
            }
            if (-not $command) {continue}

            $Parameters = @{}

            foreach ($provider in Get-PSProvider) {
                $drive = "{0}\{1}::\" -f $provider.ModuleName, $provider.Name
                Write-Verbose ("Get-Command $command -Args $drive | Select -Expand Parameters")

                [Array]$MoreParameters = (Get-Command $command -Args $drive).Parameters.Values
                [Array]$Dynamic = $MoreParameters | Where-Object {$_.IsDynamic}
                foreach ($p in $MoreParameters | Where-Object{!$Parameters.ContainsKey($_.Name)}) {$Parameters.($p.Name) = $p}
                    # Write-Verbose "Drive: $Drive | Parameters: $($Parameters.Count)"
                    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) | Add-Member NoteProperty DynamicProvider @($provider.Name) -Passthru
                            }
                        }
                    }
                }

                ## 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
                foreach ($p in $($Parameters.Keys)) {
                    $shortest = "^"
                    foreach ($char in [char[]]$p) {             
                        $shortest += $char
                        $Matches = (($Parameters.Keys + $Aliases) -match $Shortest).Count
                        Write-Debug "$($shortest.SubString(1)) $Matches"
                        if ($Matches -eq 1) {
                            $Parameters.$p = $Parameters.$p | Add-Member NoteProperty Aliases ($Parameters.$p.Aliases + @($shortest.SubString(1).ToLower($PSUICulture))) -Force -Passthru
                            break
                        }
                    }
                }

                Write-Verbose "Parameters: $($Parameters.Count)`n $($Parameters | ft | out-string)"

                foreach ($paramset in @($command.ParameterSets | Select-Object -ExpandProperty "Name")) {
                    foreach ($parameter in $Parameters.Keys | Sort-Object) {
                        Write-Verbose "Parameter: $Parameter"
                        if (!$Force -and ($Parameters.$Parameter.Aliases -match '^(vb|db|ea|wa|ev|wv|ov|ob|wi|cf)$')) {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}
                        }
                    }
                }
            }
        }
    }
}


# Since you can't update format data without a file that has a ps1xml ending, let's make one up...
$tempFile = "$([System.IO.Path]::GetTempPath())Get-Parameter.ps1xml"
Set-Content $tempFile @'
<?xml version="1.0" encoding="utf-8" ?>
<Configuration>
    <Controls>
        <Control>
            <Name>ParameterGroupingFormat</Name>
              <CustomControl>
                  <CustomEntries>
                      <CustomEntry>
                          <CustomItem>
                              <Frame>
                                  <LeftIndent>4</LeftIndent>
                                  <CustomItem>
                                      <Text>Command: </Text>
                                      <ExpressionBinding>
                                          <ScriptBlock>"{0}/{1}" -f $(if($_.command.ModuleName){$_.command.ModuleName}else{$_.Command.CommandType.ToString()+":"}),$_.command.Name</ScriptBlock>
                                      </ExpressionBinding>
                                      <NewLine/>
                                      <Text>Set:     </Text>
                                      <ExpressionBinding>
                                          <ScriptBlock>if($_.ParameterSet -eq "__AllParameterSets"){"Default"}else{$_.ParameterSet}</ScriptBlock>
                                      </ExpressionBinding>
                                      <NewLine/>
                                  </CustomItem> 
                              </Frame>
                          </CustomItem>
                      </CustomEntry>
                  </CustomEntries>
            </CustomControl>
        </Control>
    </Controls>
    <ViewDefinitions>
        <View>
            <Name>ParameterMetadataEx</Name>
            <ViewSelectedBy>
                <TypeName>System.Management.Automation.ParameterMetadataEx</TypeName>
            </ViewSelectedBy>
            <GroupBy>
                <PropertyName>ParameterSet</PropertyName>
                <CustomControlName>ParameterGroupingFormat</CustomControlName>  
            </GroupBy>
            <TableControl>
                <TableHeaders>
                    <TableColumnHeader>
                        <Label>Name</Label>
                        <Width>22</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Aliases</Label>
                        <Width>12</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Position</Label>
                        <Width>8</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Mandatory</Label>
                        <Width>9</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Pipeline</Label>
                        <Width>8</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>ByName</Label>
                        <Width>6</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Provider</Label>
                        <Width>15</Width>
                    </TableColumnHeader>
                    <TableColumnHeader>
                        <Label>Type</Label>
                    </TableColumnHeader>
                </TableHeaders>
                <TableRowEntries>
                    <TableRowEntry>
                        <TableColumnItems>
                            <TableColumnItem>
                                <PropertyName>Name</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>Aliases</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <!--PropertyName>Position</PropertyName-->
                                <ScriptBlock>if($_.Position -lt 0){"Named"}else{$_.Position}</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>Mandatory</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>ValueFromPipeline</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>ValueFromPipelineByPropertyName</PropertyName>
                            </TableColumnItem>
                            <TableColumnItem>
                                <!--PropertyName>Provider</PropertyName-->
                                <ScriptBlock>if($_.Provider){$_.Provider}else{"All"}</ScriptBlock>
                            </TableColumnItem>
                            <TableColumnItem>
                                <PropertyName>Type</PropertyName>
                            </TableColumnItem>
                        </TableColumnItems>
                    </TableRowEntry>
                 </TableRowEntries>
            </TableControl>
        </View>
    </ViewDefinitions>
</Configuration>
'@

Update-FormatData -Append $tempFile


# This is nested stuff, so that you can call the SCRIPT, and after it defines the global function, we will call that.
Get-Parameter @PSBoundParameters