PoshCode Logo PowerShell Code Repository

Get-Parameter 2.6 by JasonMArcher 3 years ago (modification of post by JasonMArcher view diff)
View followups from Joel Bennett | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/2815"></script>download | new post

This is another Must Have upgrade, because I screwed up the last one ;-)

  1. #Requires -version 2.0
  2.  
  3. #.Synopsis
  4. #  Enumerates the parameters of one or more commands
  5. #.Notes
  6. #  With many thanks to Hal Rottenberg, Oisin Grehan and Shay Levy
  7. #  Version 0.80 - April 2008 - By Hal Rottenberg http://poshcode.org/186
  8. #  Version 0.81 - May 2008 - By Hal Rottenberg http://poshcode.org/255
  9. #  Version 0.90 - June 2008 - By Hal Rottenberg http://poshcode.org/445
  10. #  Version 0.91 - June 2008 - By Oisin Grehan http://poshcode.org/446
  11. #  Version 0.92 - April 2008 - By Hal Rottenberg http://poshcode.org/549
  12. #               - ADDED resolving aliases and avoided empty output
  13. #  Version 0.93 - Sept 24, 2009 - By Hal Rottenberg http://poshcode.org/1344
  14. #  Version 1.0  - Jan 19, 2010 - By Joel Bennett http://poshcode.org/1592
  15. #               - Merged Oisin and Hal's code with my own implementation
  16. #               - ADDED calculation of dynamic paramters
  17. #  Version 2.0  - July 22, 2010 - By Joel Bennett http://poshcode.org/get/2005
  18. #               - CHANGED uses FormatData so the output is objects
  19. #               - ADDED calculation of shortest names to the aliases (idea from Shay Levy http://poshcode.org/1982,
  20. #                 but with a correct implementation)
  21. #  Version 2.1  - July 22, 2010 - By Joel Bennett http://poshcode.org/2007
  22. #               - FIXED Help for SCRIPT file (script help must be separated from #Requires by an emtpy line)
  23. #               - Fleshed out and added dates to this version history after Bergle's criticism ;)
  24. #  Version 2.2  - July 29, 2010 - By Joel Bennett http://poshcode.org/2030
  25. #               - FIXED a major bug which caused Get-Parameters to delete all the parameters from the CommandInfo
  26. #  Version 2.3  - July 29, 2010 - By Joel Bennett
  27. #               - ADDED a ToString ScriptMethod which allows queries like:
  28. #                 $parameters = Get-Parameter Get-Process; $parameters -match "Name"
  29. #  Version 2.4  - July 29, 2010 - By Joel Bennett http://poshcode.org/2032
  30. #               - CHANGED "Name" to CommandName
  31. #               - ADDED ParameterName parameter to allow filtering parameters
  32. #               - FIXED bug in 2.3 and 2.2 with dynamic parameters
  33. #  Version 2.5  - December 13, 2010 - By Jason Archer http://poshcode.org/2404
  34. #               - CHANGED format temp file to have static name, prevents bloat of random temporary files
  35. #  Version 2.6  - July 23, 2011 - By Jason Archer (This Version)
  36. #               - FIXED miscalculation of shortest unique name (aliases count as unique names),
  37. #                 this caused some parameter names to be thrown out (like "Object")
  38. #               - CHANGED code style cleanup
  39. #
  40. #.Description
  41. #  Lists all the parameters of a command, by ParameterSet, including their aliases, type, etc.
  42. #
  43. #  By default, formats the output to tables grouped by command and parameter set
  44. #.Example
  45. #  Get-Command Select-Xml | Get-Parameter
  46. #.Example
  47. #  Get-Parameter Select-Xml
  48. #.Parameter CommandName
  49. #  The name of the command to get parameters for
  50. #.Parameter ParameterName
  51. #  Wilcard-enabled filter for parameter names
  52. #.Parameter ModuleName
  53. #  The name of the module which contains the command (this is for scoping)
  54. #.Parameter Force
  55. #  Forces including the CommonParameters in the output
  56. [CmdletBinding()]
  57. param (
  58.    [Parameter(Position=1,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
  59.    [Alias("Name")]
  60.    [string[]]$CommandName
  61. ,
  62.    [Parameter(Position=2,ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
  63.    [string[]]$ParameterName="*"
  64. ,
  65.    [Parameter(ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
  66.    $ModuleName
  67. ,
  68.    [switch]$Force
  69. )
  70.  
  71. Function global:Get-Parameter {
  72.     #.Synopsis
  73.     #  Enumerates the parameters of one or more commands
  74.     #.Description
  75.     #  Lists all the parameters of a command, by ParameterSet, including their aliases, type, etc.
  76.     #
  77.     #  By default, formats the output to tables grouped by command and parameter set
  78.     #.Example
  79.     #  Get-Command Select-Xml | Get-Parameter
  80.     #.Example
  81.     #  Get-Parameter Select-Xml
  82.     #.Parameter CommandName
  83.     #  The name of the command to get parameters for
  84.     #.Parameter ParameterName
  85.     #  Wilcard-enabled filter for parameter names
  86.     #.Parameter ModuleName
  87.     #  The name of the module which contains the command (this is for scoping)
  88.     #.Parameter Force
  89.     #  Forces including the CommonParameters in the output
  90.     [CmdletBinding()]
  91.     param(
  92.         [Parameter(Position = 1, Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
  93.         [string[]]$CommandName
  94.         ,
  95.         [Parameter(Position = 2, ValueFromPipelineByPropertyName=$true)]
  96.         [string[]]$ParameterName = "*"
  97.         ,
  98.         [Parameter(ValueFromPipelineByPropertyName = $true)]
  99.         $ModuleName
  100.         ,
  101.         [switch]$Force
  102.     )
  103.  
  104.     begin {
  105.         $PropertySet = @( "Name",
  106.             @{n="Position";e={if($_.Position -lt 0){"Named"}else{$_.Position}}},
  107.             "Aliases",
  108.             @{n="Short";e={$_.Name}},
  109.             @{n="Type";e={$_.ParameterType.Name}},
  110.             @{n="ParameterSet";e={$paramset}},
  111.             @{n="Command";e={$command}},
  112.             @{n="Mandatory";e={$_.IsMandatory}},
  113.             @{n="Provider";e={$_.DynamicProvider}},
  114.             @{n="ValueFromPipeline";e={$_.ValueFromPipeline}},
  115.             @{n="ValueFromPipelineByPropertyName";e={$_.ValueFromPipelineByPropertyName}}
  116.         )
  117.         function Join-Object {
  118.             Param(
  119.                 [Parameter(Position=0)]
  120.                 $First
  121.                 ,
  122.                 [Parameter(ValueFromPipeline=$true,Position=1)]
  123.                 $Second
  124.             )
  125.             begin {
  126.                 [string[]] $p1 = $First | Get-Member -MemberType Properties | Select-Object -ExpandProperty Name
  127.             }
  128.             process {
  129.                 $Output = $First | Select-Object $p1
  130.                 foreach ($p in $Second | Get-Member -MemberType Properties | Where-Object {$p1 -notcontains $_.Name} | Select-Object -ExpandProperty Name) {
  131.                     Add-Member -InputObject $Output -MemberType NoteProperty -Name $p -Value $Second."$p"
  132.                 }
  133.                 $Output
  134.             }
  135.         }
  136.     }
  137.  
  138.     process {
  139.         foreach ($cmd in $CommandName) {
  140.         if ($ModuleName) {$cmd = "$ModuleName\$cmd"}
  141.         $commands = @(Get-Command $cmd)
  142.  
  143.         foreach ($command in $commands) {
  144.             # resolve aliases (an alias can point to another alias)
  145.             while ($command.CommandType -eq "Alias") {
  146.                 $command = @(Get-Command ($command.definition))[0]
  147.             }
  148.             if (-not $command) {continue}
  149.  
  150.             $Parameters = @{}
  151.  
  152.             foreach ($provider in Get-PSProvider) {
  153.                 $drive = "{0}\{1}::\" -f $provider.ModuleName, $provider.Name
  154.                 Write-Verbose ("Get-Command $command -Args $drive | Select -Expand Parameters")
  155.  
  156.                 [Array]$MoreParameters = (Get-Command $command -Args $drive).Parameters.Values
  157.                 [Array]$Dynamic = $MoreParameters | Where-Object {$_.IsDynamic}
  158.                 foreach ($p in $MoreParameters | Where-Object{!$Parameters.ContainsKey($_.Name)}) {$Parameters.($p.Name) = $p}
  159.                     # Write-Verbose "Drive: $Drive | Parameters: $($Parameters.Count)"
  160.                     if ($dynamic) {
  161.                         foreach ($d in $dynamic) {
  162.                             if (Get-Member -InputObject $Parameters.($d.Name) -Name DynamicProvider) {
  163.                                 Write-Debug ("ADD:" + $d.Name + " " + $provider.Name)
  164.                                 $Parameters.($d.Name).DynamicProvider += $provider.Name
  165.                             } else {
  166.                                 Write-Debug ("CREATE:" + $d.Name + " " + $provider.Name)
  167.                                 $Parameters.($d.Name) = $Parameters.($d.Name) | Add-Member NoteProperty DynamicProvider @($provider.Name) -Passthru
  168.                             }
  169.                         }
  170.                     }
  171.                 }
  172.  
  173.                 ## Calculate the shortest distinct parameter name -- do this BEFORE removing the common parameters or else.
  174.                 $Aliases = $Parameters.Values | Select-Object -ExpandProperty Aliases  ## Get defined aliases
  175.                 foreach ($p in $($Parameters.Keys)) {
  176.                     $shortest = "^"
  177.                     foreach ($char in [char[]]$p) {            
  178.                         $shortest += $char
  179.                         $Matches = (($Parameters.Keys + $Aliases) -match $Shortest).Count
  180.                         Write-Debug "$($shortest.SubString(1)) $Matches"
  181.                         if ($Matches -eq 1) {
  182.                             $Parameters.$p = $Parameters.$p | Add-Member NoteProperty Aliases ($Parameters.$p.Aliases + @($shortest.SubString(1).ToLower($PSUICulture))) -Force -Passthru
  183.                             break
  184.                         }
  185.                     }
  186.                 }
  187.  
  188.                 Write-Verbose "Parameters: $($Parameters.Count)`n $($Parameters | ft | out-string)"
  189.  
  190.                 foreach ($paramset in @($command.ParameterSets | Select-Object -ExpandProperty "Name")) {
  191.                     foreach ($parameter in $Parameters.Keys | Sort-Object) {
  192.                         Write-Verbose "Parameter: $Parameter"
  193.                         if (!$Force -and ($Parameters.$Parameter.Aliases -match '^(vb|db|ea|wa|ev|wv|ov|ob|wi|cf)$')) {continue}
  194.                         if ($Parameters.$Parameter.ParameterSets.ContainsKey($paramset) -or $Parameters.$Parameter.ParameterSets.ContainsKey("__AllParameterSets")) {
  195.                             if ($Parameters.$Parameter.ParameterSets.ContainsKey($paramset)) {
  196.                                 $output = Join-Object $Parameters.$Parameter $Parameters.$Parameter.ParameterSets.$paramSet
  197.                             } else {
  198.                                 $output = Join-Object $Parameters.$Parameter $Parameters.$Parameter.ParameterSets.__AllParameterSets
  199.                             }
  200.  
  201.                             Write-Output $Output | Select-Object $PropertySet | ForEach-Object {
  202.                                     $null = $_.PSTypeNames.Insert(0,"System.Management.Automation.ParameterMetadata")
  203.                                     $null = $_.PSTypeNames.Insert(0,"System.Management.Automation.ParameterMetadataEx")
  204.                                     Write-Verbose "$(($_.PSTypeNames.GetEnumerator()) -join ", ")"
  205.                                     $_
  206.                                 } |
  207.                                 Add-Member ScriptMethod ToString { $this.Name } -Force -Passthru |
  208.                                 Where-Object {$(foreach($pn in $ParameterName) {$_ -like $Pn}) -contains $true}
  209.                         }
  210.                     }
  211.                 }
  212.             }
  213.         }
  214.     }
  215. }
  216.  
  217.  
  218. # Since you can't update format data without a file that has a ps1xml ending, let's make one up...
  219. $tempFile = "$([System.IO.Path]::GetTempPath())Get-Parameter.ps1xml"
  220. Set-Content $tempFile @'
  221. <?xml version="1.0" encoding="utf-8" ?>
  222. <Configuration>
  223.    <Controls>
  224.        <Control>
  225.            <Name>ParameterGroupingFormat</Name>
  226.              <CustomControl>
  227.                  <CustomEntries>
  228.                      <CustomEntry>
  229.                          <CustomItem>
  230.                              <Frame>
  231.                                  <LeftIndent>4</LeftIndent>
  232.                                  <CustomItem>
  233.                                      <Text>Command: </Text>
  234.                                      <ExpressionBinding>
  235.                                          <ScriptBlock>"{0}/{1}" -f $(if($_.command.ModuleName){$_.command.ModuleName}else{$_.Command.CommandType.ToString()+":"}),$_.command.Name</ScriptBlock>
  236.                                      </ExpressionBinding>
  237.                                      <NewLine/>
  238.                                      <Text>Set:     </Text>
  239.                                      <ExpressionBinding>
  240.                                          <ScriptBlock>if($_.ParameterSet -eq "__AllParameterSets"){"Default"}else{$_.ParameterSet}</ScriptBlock>
  241.                                      </ExpressionBinding>
  242.                                      <NewLine/>
  243.                                  </CustomItem>
  244.                              </Frame>
  245.                          </CustomItem>
  246.                      </CustomEntry>
  247.                  </CustomEntries>
  248.            </CustomControl>
  249.        </Control>
  250.    </Controls>
  251.    <ViewDefinitions>
  252.        <View>
  253.            <Name>ParameterMetadataEx</Name>
  254.            <ViewSelectedBy>
  255.                <TypeName>System.Management.Automation.ParameterMetadataEx</TypeName>
  256.            </ViewSelectedBy>
  257.            <GroupBy>
  258.                <PropertyName>ParameterSet</PropertyName>
  259.                <CustomControlName>ParameterGroupingFormat</CustomControlName>  
  260.            </GroupBy>
  261.            <TableControl>
  262.                <TableHeaders>
  263.                    <TableColumnHeader>
  264.                        <Label>Name</Label>
  265.                        <Width>22</Width>
  266.                    </TableColumnHeader>
  267.                    <TableColumnHeader>
  268.                        <Label>Aliases</Label>
  269.                        <Width>12</Width>
  270.                    </TableColumnHeader>
  271.                    <TableColumnHeader>
  272.                        <Label>Position</Label>
  273.                        <Width>8</Width>
  274.                    </TableColumnHeader>
  275.                    <TableColumnHeader>
  276.                        <Label>Mandatory</Label>
  277.                        <Width>9</Width>
  278.                    </TableColumnHeader>
  279.                    <TableColumnHeader>
  280.                        <Label>Pipeline</Label>
  281.                        <Width>8</Width>
  282.                    </TableColumnHeader>
  283.                    <TableColumnHeader>
  284.                        <Label>ByName</Label>
  285.                        <Width>6</Width>
  286.                    </TableColumnHeader>
  287.                    <TableColumnHeader>
  288.                        <Label>Provider</Label>
  289.                        <Width>15</Width>
  290.                    </TableColumnHeader>
  291.                    <TableColumnHeader>
  292.                        <Label>Type</Label>
  293.                    </TableColumnHeader>
  294.                </TableHeaders>
  295.                <TableRowEntries>
  296.                    <TableRowEntry>
  297.                        <TableColumnItems>
  298.                            <TableColumnItem>
  299.                                <PropertyName>Name</PropertyName>
  300.                            </TableColumnItem>
  301.                            <TableColumnItem>
  302.                                <PropertyName>Aliases</PropertyName>
  303.                            </TableColumnItem>
  304.                            <TableColumnItem>
  305.                                <!--PropertyName>Position</PropertyName-->
  306.                                <ScriptBlock>if($_.Position -lt 0){"Named"}else{$_.Position}</ScriptBlock>
  307.                            </TableColumnItem>
  308.                            <TableColumnItem>
  309.                                <PropertyName>Mandatory</PropertyName>
  310.                            </TableColumnItem>
  311.                            <TableColumnItem>
  312.                                <PropertyName>ValueFromPipeline</PropertyName>
  313.                            </TableColumnItem>
  314.                            <TableColumnItem>
  315.                                <PropertyName>ValueFromPipelineByPropertyName</PropertyName>
  316.                            </TableColumnItem>
  317.                            <TableColumnItem>
  318.                                <!--PropertyName>Provider</PropertyName-->
  319.                                <ScriptBlock>if($_.Provider){$_.Provider}else{"All"}</ScriptBlock>
  320.                            </TableColumnItem>
  321.                            <TableColumnItem>
  322.                                <PropertyName>Type</PropertyName>
  323.                            </TableColumnItem>
  324.                        </TableColumnItems>
  325.                    </TableRowEntry>
  326.                 </TableRowEntries>
  327.            </TableControl>
  328.        </View>
  329.    </ViewDefinitions>
  330. </Configuration>
  331. '@
  332.  
  333. Update-FormatData -Append $tempFile
  334.  
  335.  
  336. # This is nested stuff, so that you can call the SCRIPT, and after it defines the global function, we will call that.
  337. Get-Parameter @PSBoundParameters

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me