# encoding: ascii
# api: powershell
# title: Get-Parameter
# description: Enumerate the Parameters of a command by ParameterSet, including DynamicParameters. Includes a -Full output mode and support for specifying the module.  The only Get-Parameter you need :)
# version: 0.1
# type: script
# author: Joel Bennett
# license: CC0
# function: Join-Object
# x-poshcode-id: 1592
# x-archived: 2010-03-23T07:03:37
#
#
#Requires -version 2.0
##This is just script-file nesting stuff, so that you can call the SCRIPT, and after it defines the global function, it will call it.
param ( 
   [Parameter(Position=1,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
   [string[]]$Name
,
   [Parameter(Position=2,ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
   $ModuleName
,
   [switch]$ShowCommon
, 
   [switch]$Full
,
   [switch]$Passthru
)


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

param ( 
   [Parameter(Position=1,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
   [string[]]$Name
,
   [Parameter(Position=2,ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
   $ModuleName
,
   [switch]$ShowCommon
, 
   [switch]$Full
,
   [switch]$Passthru
)
   if($Passthru) {
      $PSBoundParameters.Remove("Passthru")
      Get-ParameterRaw @PSBoundParameters
   } elseif(!$Full) {
      $props = "Name", "Type", "ParameterSet", "Mandatory", "Provider"
      Get-ParameterRaw @PSBoundParameters | Format-Table $props -GroupBy @{n="Command";e={"{0}`n   Set:     {1}" -f $_.Command,$_.ParameterSet}}
   } else {
      $props = "Name", "Aliases", "Type", "ParameterSet", "Mandatory", "Provider", "Pipeline", "PipelineByName", "Position"

      Get-ParameterRaw @PSBoundParameters | Format-Table $props -GroupBy @{n="Command";e={"{0}`n   Set:     {1}" -f $_.Command,$_.ParameterSet}}
   }
}

## This is Hal's original script (modified a lot)
Function global:Get-ParameterRaw {
param ( 
   [Parameter(Position=1,ValueFromPipelineByPropertyName=$true,Mandatory=$true)]
   [string[]]$Name
,
   [Parameter(Position=2,ValueFromPipelineByPropertyName=$true,Mandatory=$false)]
   $ModuleName
,
   [switch]$ShowCommon
, 
   [switch]$Full
)
BEGIN {
   $PropertySet = @( "Name", 
                     "Aliases", 
                     @{n="Type";e={$_.ParameterType.Name}}, 
                     "ParameterSet",
                     @{n="Command";e={"{0}/{1}" -f $(if($command.ModuleName){$command.ModuleName}else{$Command.CommandType.ToString()+":"}),$command.Name}},
                     @{n="Mandatory";e={$_.IsMandatory}}, 
                     @{n="Provider";e={$_.DynamicProvider}},
                     @{n="Pipeline";e={$_.ValueFromPipeline}},                     
                     @{n="PipelineByName";e={$_.ValueFromPipelineByPropertyName}},
                     "Position"
                  )
   if(!$Full) {
      $PropertySet = $PropertySet[0,2,3,4,5,6]
   }
   function Join-Object {
   Param(
      [Parameter(Position=0)]
      $First
   ,
      [Parameter(ValueFromPipeline=$true,Position=1)]
      $Second
   )
      begin {
         [string[]] $p1 = $First | gm -type Properties | select -expand Name
      }
      process {
         $Output = $First | Select $p1
         foreach($p in $Second | gm -type Properties | Where { $p1 -notcontains $_.Name } | select -expand Name) {
            Add-Member -in $Output -type NoteProperty -name $p -value $Second."$p"
         }
         $Output
      }
   }
}
PROCESS{
   foreach($cmd in $Name) {
      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")
            
            $MoreParameters = Get-Command $command -Args $drive | Select -Expand Parameters
            $Dynamic = $MoreParameters | Select -Expand Values | Where { $_.IsDynamic }
            foreach($k in $Parameters.Keys){ $null = $MoreParameters.Remove($k) }
            $Parameters += $MoreParameters
            
            # Write-Verbose "Drive: $Drive | Parameters: $($Parameters.Count)"
            if($dynamic) {
               foreach($d in $dynamic) {
                  if(Get-Member -input $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
                  }
               }
            }
         }
         
         
         #Write-Output $Parameters
        
         foreach ($paramset in @($command.ParameterSets | Select -Expand "Name")){
            foreach($parameter in $Parameters.Keys) {
               if(!$ShowCommon -and ($Parameters.$Parameter.aliases -match "vb|db|ea|wa|ev|wv|ov|ob|wi|cf")) { continue }
               # Write-Verbose "Parameter: $Parameter"
               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
                  }
                  if($Full -and $output.Position -lt 0) {$output.Position = $null}
                  $setName = $(if($paramset -eq "__AllParameterSets") { "Default" } else { $paramset })
                  Write-Verbose "ParameterSet: $setName"
                  $output = $output | Add-Member NoteProperty ParameterSet -value "$setName" -Passthru
                  Write-Output $Output | Select-Object $PropertySet
               }
            }
         }
      }
   }
}
}

# 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
