PoshCode Logo PowerShell Code Repository

TabExpansion by foobar 3 years ago (modification of post by foobar view diff)
View followups from foobar | diff | embed code: <script type="text/javascript" src="http://PoshCode.org/embed/798"></script>download | new post

Ported TabExpansion from V2CTP2 to v1.0 and extended.
Some features(relate to ‘$_’ expansion) requirs Get-Pipeline.ps1 in a same diretory. (latest is here http://poshcode.org/783)
Update:

Path expansion with variable and ‘\’ or ‘/’
$PWD\../../<tab>\<tab>
“$env:SystemDrive/pro<tab>/<tab>

Operator expansion which starts with ‘-’
“Power”,“Shell” -m<tab> “Power” -r<tab> ‘(Pow)(er)’,’$1d$2’
1..9 -co<tab> 5

  1. ## Tab-Completion
  2. #################
  3. ## Please dot souce this script file.
  4. ## In first loading, it may take a several minutes, in order to generate ProgIDs and TypeNames list.
  5. ## Some features(relate to '$_' expansion) require the latest Get-Pipeline.ps1 in a same diretory. (from http://poshcode.org/author/foobar)
  6. ##
  7. ## What this can do is:
  8. ##
  9. ## [datetime]::n<tab>
  10. ## [datetime]::now.d<tab>
  11. ## $a = New-Object "Int32[,]" 2,3; $b = "PowerShell","PowerShell"
  12. ## $c = [ref]$a; $d = [ref]$b,$c
  13. ## $d[0].V<tab>[0][0].Get<tab>
  14. ## $d[1].V<tab>[0,0].tos<tab>
  15. ## $function:a<tab>
  16. ## $env:a<tab>
  17. ## [System.Type].a<tab>
  18. ## [datetime].Assembly.a<tab>
  19. ## ).a<tab> # shows System.Type properties and methods...
  20.  
  21. ## #native command name expansion
  22. ## fsu<tab>
  23.  
  24. ## #command option name expansion (for fsutil ipconfig net powershell only)
  25. ## fsutil <tab>
  26. ## ipconfig <tab>
  27. ## net <tab>
  28. ## powershell <tab>
  29.  
  30. ## #TypeNames expansion
  31. ## [Dec<tab>
  32. ## [Microsoft.PowerShell.Com<tab>
  33. ## New-Object -TypeName IO.Dir<tab>
  34. ## New-Object System.Management.Auto<tab>
  35.  
  36. ## #ProgIDs expansion
  37. ## New-Object -Com shel<tab>
  38.  
  39. ## #Enum option expansion
  40. ## Set-ExecutionPolicy <tab>
  41. ## Set-ExecutionPolicy All<tab>
  42. ## Set-ExcusionPolisy -ex <tab>
  43. ## Get-TraceSource@Inte<tab>
  44. ## iex -Err <tab> -wa Sil<tab>
  45.  
  46. ## #WmiClasses expansion
  47. ## Get-WmiObject -class Win32_<tab>
  48. ## gwmi __Instance<tab>
  49.  
  50. ## #Encoding expansion
  51. ## [Out-File | Export-CSV | Select-String | Export-Clixml] -enc <tab>
  52. ## [Add-Content | Get-Content | Set-Content} -Encoding Big<tab>
  53.  
  54. ## #PSProvider name expansion
  55. ## [Get-Location | Get-PSDrive | Get-PSProvider | New-PSDrive | Remove-PSDrive] [-PSProvider] <tab>
  56. ## Get-PSProvider <tab>
  57. ## pwd -psp al<tab>
  58.  
  59. ## #PSDrive name expansion
  60. ## [Get-PSDrive | New-PSDrive | Remove-PSDrive] [-Name] <tab>
  61. ## Get-PSDrive <tab>
  62. ## pwd -psd <tab>
  63.  
  64. ## #PSSnapin name expansion
  65. ## [Add-PSSnapin | Get-PSSnapin | Remove-PSSnapin ] [-Name] <tab>
  66. ## Get-Command -PSSnapin <tab>
  67. ## Remove-PSSnapin <tab>
  68. ## Get-PSSnapin M<tab>
  69.  
  70. ## #Eventlog name and expansion
  71. ## Get-Eventlog -Log <tab>
  72. ## Get-Eventlog w<tab>
  73.  
  74. ## #Eventlog's entrytype expansion
  75. ## Get-EventLog -EntryType <tab>
  76. ## Get-EventLog -EntryType Er<tab>
  77. ## Get-EventLog -Ent <tab>
  78.  
  79. ## #Service name expansion
  80. ## [Get-Service | Restart-Service | Resume-Service | Start-Service | Stop-Service | Suspend-Service] [-Name] <tab>
  81. ## New-Service -DependsOn <tab>
  82. ## New-Service -Dep e<tab>
  83. ## Get-Service -n <tab>
  84. ## Get-Service <tab>,a<tab>,p<tab>
  85. ## gsv <tab>
  86.  
  87. ## #Service display name expansion
  88. ## [Get-Service | Restart-Service | Resume-Service | Start-Service | Stop-Service | Suspend-Service] [-DisplayName] <tab>
  89. ## Get-Service -Dis <tab>
  90. ## gsv -Dis <tab>,w<tab>,b<tab>
  91.  
  92. ## #Cmdlet and Topic name expansion
  93. ## Get-Help [-Name] about_<tab>
  94. ## Get-Help <tab>
  95.  
  96. ## #Category name expansion
  97. ## Get-Help -Category c<tab>,<tab>
  98.  
  99. ## #Command name expansion
  100. ## Get-Command [-Name] <tab>
  101. ## Get-Command -Name <tab>
  102. ## gcm a<tab>,<tab>
  103.  
  104. ## #Scope expansion
  105. ## [Clear-Variable | Export-Alias | Get-Alias | Get-PSDrive | Get-Variable | Import-Alias
  106. ## New-Alias | New-PSDrive | New-Variable | Remove-Variable | Set-Alias | Set-Variable] -Scope <tab>
  107. ## Clear-Variable -Scope G<tab>
  108. ## Set-Alias  -s <tab>
  109.  
  110. ## #Process name expansion
  111. ## [Get-Process | Stop-Process] [-Name] <tab>
  112. ## Stop-Process -Name <tab>
  113. ## Stop-Process -N pow<tab>
  114. ## Get-Process <tab>
  115. ## ps power<tab>
  116.  
  117. ## #Trace sources expansion
  118. ## [Trace-Command | Get-TraceSource | Set-TraceSource] [-Name] <tab>,a<tab>,p<tab>
  119.  
  120. ## #Trace -ListenerOption expansion
  121. ## [Set-TraceSource | Trace-Command] -ListenerOption <tab>
  122. ## Set-TraceSource -Lis <tab>,n<tab>
  123.  
  124. ## #Trace -Option expansion
  125. ## [Set-TraceSource | Trace-Command] -Option <tab>
  126. ## Set-TraceSource -op <tab>,con<tab>
  127.  
  128. ## #ItemType expansion
  129. ## New-Item -Item <tab>
  130. ## ni -ItemType d<tab>
  131.  
  132. ## #ErrorAction and WarningAction option expansion
  133. ## CMDLET [-ErrorAction | -WarningAction] <tab>
  134. ## CMDLET -Error s<tab>
  135. ## CMDLET -ea con<tab>
  136. ## CMDLET -wa <tab>
  137.  
  138. ## #Continuous expansion with comma when parameter can treat multiple option
  139. ## # if there are spaces, occur display bug in the line
  140. ## # if strings contains '$' or '-', not work
  141. ## Get-Command -CommandType <tab>,<tab><tab>,cm<tab>
  142. ## pwd -psp <tab>,f<tab>,va<tab>
  143. ## Get-EventLog -EntryType <tab>,i<tab>,s<tab>
  144.  
  145. ## #Enum expansion in method call expression
  146. ## # this needs one or more spaces after left parenthesis or comma
  147. ## $str = "day   night"
  148. ## $str.Split( " ",<space>rem<tab>
  149. ## >>> $str.Split( " ", "RemoveEmptyEntries" ) <Enter> ERROR
  150. ## $str.Split( " ", "RemoveEmptyEntries" -as<space><tab>
  151. ## >>> $str.Split( " ", "RemoveEmptyEntries" -as [System.StringSplitOptions] ) <Enter> Success
  152. ## $type = [System.Type]
  153. ## $type.GetMembers(<space>Def<tab>
  154. ## [IO.Directory]::GetFiles( "C:\", "*",<space>All<tab>
  155. ## # this can do continuous enum expansion with comma and no spaces
  156. ## $type.GetMembers( "IgnoreCase<comma>Dec<tab><comma>In<tab>"
  157. ## [IO.Directory]::GetAccessControl( "C:\",<space>au<tab><comma>ac<tab><comma>G<tab>
  158.  
  159. ## #Better '$_.' expansion when cmdlet output objects or method return objects
  160. ## ls |group { $_.Cr<tab>.Tost<tab>"y")} | tee -var foo| ? { $_.G<tab>.c<tab> -gt 5 } | % { md $_.N<tab> ; copy $_.G<tab> $_.N<tab>  }
  161. ## [IO.DriveInfo]::GetDrives() | ? { $_.A<tab> -gt 1GB }
  162. ## $Host.UI.RawUI.GetBufferContents($rect) | % { $str += $_.c<tab> }
  163. ## gcm Add-Content |select -exp Par<tab>|select -exp <tab> |
  164. ## select -ExpandProperty Par<tab>| | ? { $_.Par<tab>.N<tab> -eq "string" }
  165. ## $data = Get-Process
  166. ## $data[2,4,5]  | % { $_.<tab>
  167. ## #when Get-PipeLineObject failed, '$_.' shows methods and properties name of FileInfo and String and Type
  168.  
  169. ## #Property name expansion
  170. ## [ Format-List | Format-Custom | Format-Table | Format-Wide | Compare-Object |
  171. ##  ConvertTo-Html | Measure-Object | Select-Object | Group-Object | Sort-Object ] [-Property] <tab>
  172. ## Select-Object -ExcludeProperty <tab>
  173. ## Select-Object -ExpandProperty <tab>
  174. ## gcm Get-Acl|select -exp Par<tab>
  175. ## ps |group na<tab>
  176. ## ls | ft A<tab>,M<tab>,L<tab>
  177.  
  178. ## #Hashtable key expansion in the variable name and '.<tab>'
  179. ## Get-Process | Get-Unique | % { $hash += @{$_.ProcessName=$_} }
  180. ## $hash.pow<tab>.pro<tab>
  181.  
  182. ## #Parameter expansion for function, filter and script
  183. ## man -f<tab>
  184. ## 'param([System.StringSplitOptions]$foo,[System.Management.Automation.ActionPreference]$bar,[System.Management.Automation.CommandTypes]$baz) {}' > foobar.ps1
  185. ## .\foobar.ps1 -<tab> -b<tab>
  186.  
  187. ## #Enum expansion for function, filter and scripts
  188. ## # this can do continuous enum expansion with comma and no spaces
  189. ## .\foobar.ps1 -foo rem<tab> -bar <tab><comma>c<tab><comma>sc<tab> -ea silent<tab> -wa con<tab>
  190.  
  191. ## #Enum expansion for assignment expression
  192. ## #needs space(s) after '=' and comma
  193. ## #strongly-typed with -as operator and space(s)
  194. ## $ErrorActionPreference =<space><tab>
  195. ## $cmdtypes = New-Object System.Management.Automation.CommandTypes[] 3
  196. ## $cmdtypes =<space><tab><comma><space>func<tab><comma><space>cmd<tab> -as<space><tab>
  197.  
  198. ## #Path expansion with variable and '\' or '/'
  199. ## $PWD\../../<tab>\<tab>
  200. ## "$env:SystemDrive/pro<tab>/<tab>
  201.  
  202. ## #Operator expansion which starts with '-'
  203. ## "Power","Shell" -m<tab> "Power" -r<tab> '(Pow)(er)','$1d$2'
  204. ## 1..9 -co<tab> 5
  205.  
  206. ### Generate ProgIDs list...
  207. if ($_ProgID -eq $null) {
  208.     $_HKCR = [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey("CLSID\")
  209.     [Object[]] $_ProgID = $null
  210.     foreach ( $_subkey in $_HKCR.GetSubKeyNames() )
  211.     {
  212.         foreach ( $_i in [Microsoft.Win32.Registry]::ClassesRoot.OpenSubKey("CLSID\$_subkey\ProgID") )
  213.         {
  214.             if ($_i -ne $null)
  215.             {
  216.                 $_ProgID += $_i.GetValue("")
  217.             }
  218.         }
  219.     }
  220.     '$_ProgID was updated...' | Out-Host
  221.     $_ProgID = $_ProgID|sort -Unique
  222.  
  223.     Set-Content -Value $_ProgID -Path $PSHOME\ProgIDs.txt
  224.     Add-Content -Path $PSHOME\profile.ps1 -Value ';$_ProgID = Get-Content -Path C:\WINDOWS\system32\windowspowershell\v1.0\ProgIDs.txt;'
  225. }
  226.  
  227. ### Generate TypeNames list...
  228.  
  229. if ( $_TypeNames -eq $null ) {
  230.     [Object[]] $_TypeNames = $null
  231.     foreach ( $_asm in [AppDomain]::CurrentDomain.GetAssemblies() )
  232.     {
  233.         foreach ( $_type in $_asm.GetTypes() )
  234.         {
  235.             $_TypeNames += $_type.FullName
  236.         }
  237.     }
  238.     '$_TypeNames was updated...' | Out-Host
  239.     $_TypeNames = $_TypeNames | sort -Unique
  240.  
  241.     Set-Content -Value $_TypeNames -Path $PSHOME\TypeNames.txt
  242.     Add-Content -Path $PSHOME\profile.ps1 -Value ';$_TypeNames = Get-Content -Path $PSHOME\TypeNames.txt;'
  243. }
  244.  
  245. if ( $_TypeNames_System -eq $null ) {
  246.     [Object[]] $_TypeNames_System = $null
  247.     foreach ( $_type in $_TypeNames -like "System.*" )
  248.     {
  249.         $_TypeNames_System += $_type.Substring(7)
  250.     }
  251.     '$_TypeNames_System was updated...' | Out-Host
  252.     Set-Content -Value $_TypeNames_System -Path $PSHOME\TypeNames_System.txt
  253.     Add-Content -Path $PSHOME\profile.ps1 -Value ';$_TypeNames_System = Get-Content -Path $PSHOME\TypeNames_System.txt;'
  254. }
  255.  
  256. ### Generate WMIClasses list...
  257. if ( $_WMIClasses -eq $null ) {
  258.     [Object[]] $_WMIClasses = $null
  259.     foreach ( $_class in gwmi -List )
  260.     {
  261.         $_WMIClasses += $_class.Name
  262.     }
  263.     $_WMIClasses = $_WMIClasses | sort -Unique
  264.     '$_WMIClasses was updated...' | Out-Host
  265.     Set-Content -Value $_WMIClasses -Path $PSHOME\WMIClasses.txt
  266.     Add-Content -Path $PSHOME\profile.ps1 -Value ';$_WMIClasses = Get-Content -Path $PSHOME\WMIClasses.txt;'
  267. }
  268. $global:_snapin = $null
  269.  
  270. # Load Get-PipeLineObject function for $_ and property name expansion.
  271. $_scriptpath = gi $MyInvocation.MyCommand.Path
  272. iex (". " + (Join-Path $_scriptpath.DirectoryName "Get-PipeLineObject.ps1"))
  273.  
  274. function TabExpansion {
  275.             # This is the default function to use for tab expansion. It handles simple
  276.             # member expansion on variables, variable name expansion and parameter completion
  277.             # on commands. It doesn't understand strings so strings containing ; | ( or { may
  278.             # cause expansion to fail.
  279.  
  280.             param($line, $lastWord)
  281.  
  282.             & {
  283.                 # Helper function to write out the matching set of members. It depends
  284.                 # on dynamic scoping to get $_base, _$expression and $_pat
  285.                 function Write-Members ($sep='.')
  286.                 {
  287.  
  288.                     # evaluate the expression to get the object to examine...
  289.                     Invoke-Expression ('$_val=' + $_expression)
  290.  
  291.                     if ( $_expression -match '^\$global:_dummy' )
  292.                     {
  293.                         $temp = $_expression -replace '^\$global:_dummy(.*)','$1'
  294.                         $_expression = '$_' + $temp
  295.                     }
  296.  
  297.  
  298.                     $_method = [Management.Automation.PSMemberTypes] `
  299.                         'Method,CodeMethod,ScriptMethod,ParameterizedProperty'
  300.  
  301.                     if ($sep -eq '.')
  302.                     {
  303.                         $members =
  304.                             (
  305.                                 [Object[]](Get-Member -InputObject $_val.PSextended $_pat) +
  306.                                 [Object[]](Get-Member -InputObject $_val.PSadapted $_pat) +
  307.                                 [Object[]](Get-Member -InputObject $_val.PSbase $_pat)
  308.                             )
  309.                         if ( $_val -is [Hashtable] )
  310.                         {
  311.                             [Microsoft.PowerShell.Commands.MemberDefinition[]]$_keys = $null
  312.                             foreach ( $_name in $_val.Keys )
  313.                             {
  314.                                 $_keys += `
  315.                                 New-Object Microsoft.PowerShell.Commands.MemberDefinition `
  316.                                 [int],$_name,"Property",0
  317.                             }
  318.  
  319.                             $members += [Object[]]$_keys | ? { $_.Name -like $_pat }
  320.                         }
  321.  
  322.                         foreach ($_m in $members | sort membertype,name -Unique)
  323.                             {
  324.                                 if ($_m.MemberType -band $_method)
  325.                                 {
  326.                                     # Return a method...
  327.                                     $_base + $_expression + $sep + $_m.name + '('
  328.                                 }
  329.                                 else {
  330.                                     # Return a property...
  331.                                     $_base + $_expression + $sep + $_m.name
  332.                                 }
  333.                             }
  334.                         }
  335.  
  336.                     else
  337.                     {
  338.                     foreach ($_m in Get-Member -Static -InputObject $_val $_pat |
  339.                         Sort-Object membertype,name)
  340.                        {
  341.                            if ($_m.MemberType -band $_method)
  342.                            {
  343.                                # Return a method...
  344.                                $_base + $_expression + $sep + $_m.name + '('
  345.                            }
  346.                            else {
  347.                                # Return a property...
  348.                                $_base + $_expression + $sep + $_m.name
  349.                            }
  350.                         }
  351.                     }
  352.                 }
  353.  
  354.                 switch -regex ($lastWord)
  355.                 {
  356.  
  357.                     # Handle property and method expansion at '$_'
  358.                     '(^.*)(\$_\.)(\w*)$' {
  359.                         $_base = $matches[1]
  360.                         $_expression = '$global:_dummy'
  361.                         $_pat = $matches[3] + '*'
  362.                         $global:_dummy = $null
  363.                         Get-PipeLineObject
  364.                         if ( $global:_dummy -eq $null )
  365.                         {
  366.  
  367.                             if ( $global:_exp -match '^\$.*\(.*$' )
  368.                             {
  369.                                 $type = ( iex $_exp.Split("(")[0] ).OverloadDefinitions[0].Split(" ")[0] -replace '\[[^\[\]]*\]$' -as [type]
  370.  
  371.                                 if ( $_expression -match '^\$global:_dummy' )
  372.                                 {
  373.                                     $temp = $_expression -replace '^\$global:_dummy(.*)','$1'
  374.                                     $_expression = '$_' + $temp
  375.                                 }
  376.  
  377.                                 foreach ( $_m in $type.GetMembers() | sort membertype,name | group name | ? { $_.Name -like $_pat } | % { $_.Group[0] } )
  378.                                 {
  379.                                    if ($_m.MemberType -eq "Method")
  380.                                    {
  381.                                        $_base + $_expression + '.' + $_m.name + '('
  382.                                    }
  383.                                    else {
  384.                                        $_base + $_expression + '.' + $_m.name
  385.                                    }
  386.                                 }
  387.                                 break;
  388.                             }
  389.                             elseif ( $global:_exp -match '^\[.*\:\:.*\(.*$' )
  390.                             {
  391.                                 $tname, $mname = $_exp.Split(":(", "RemoveEmptyEntries"-as [System.StringSplitOptions])[0,1]
  392.                                 $type = @(iex ($tname + '.GetMember("' + $mname + '")'))[0].ReturnType.FullName -replace '\[[^\[\]]*\]$' -as [type]
  393.  
  394.                                 if ( $_expression -match '^\$global:_dummy' )
  395.                                 {
  396.                                     $temp = $_expression -replace '^\$global:_dummy(.*)','$1'
  397.                                     $_expression = '$_' + $temp
  398.                                 }
  399.  
  400.                                 foreach ( $_m in $type.GetMembers() | sort membertype,name | group name | ? { $_.Name -like $_pat } | % { $_.Group[0] } )
  401.                                 {
  402.                                    if ($_m.MemberType -eq "Method")
  403.                                    {
  404.                                        $_base + $_expression + '.' + $_m.name + '('
  405.                                    }
  406.                                    else {
  407.                                        $_base + $_expression + '.' + $_m.name
  408.                                    }
  409.                                 }
  410.                                 break;
  411.                             }
  412.                             elseif ( $global:_exp -match '^(\$\w+(\[[0-9,\.]+\])*(\.\w+(\[[0-9,\.]+\])*)*)$' )
  413.                             {
  414.                                 $global:_dummy = @(iex $Matches[1])[0]
  415.                             }
  416.                             else
  417.                             {
  418.                                 $global:_dummy =  $global:_mix
  419.                             }
  420.                         }
  421.  
  422.                         Write-Members
  423.                         break;
  424.                     }
  425.  
  426.                     # Handle property and method expansion rooted at variables...
  427.                     # e.g. $a.b.<tab>
  428.                     '(^.*)(\$(\w|\.)+)\.(\w*)$' {
  429.                         $_base = $matches[1]
  430.                         $_expression = $matches[2]
  431.                         [void] ( iex "$_expression.IsDataLanguageOnly" ) # for [ScriptBlock]
  432.                         $_pat = $matches[4] + '*'
  433.                         if ( $_expression -match '^\$_\.' )
  434.                         {
  435.                             $_expression = $_expression -replace '^\$_(.*)',('$global:_dummy' + '$1')
  436.                         }
  437.                         Write-Members
  438.                         break;
  439.                     }
  440.  
  441.                     # Handle simple property and method expansion on static members...
  442.                     # e.g. [datetime]::n<tab>
  443.                     '(^.*)(\[(\w|\.)+\])\:\:(\w*)$' {
  444.                         $_base = $matches[1]
  445.                         $_expression = $matches[2]
  446.                         $_pat = $matches[4] + '*'
  447.                         Write-Members '::'
  448.                         break;
  449.                     }
  450.  
  451.                     # Handle complex property and method expansion on static members
  452.                     # where there are intermediate properties...
  453.                     # e.g. [datetime]::now.d<tab>
  454.                     '(^.*)(\[(\w|\.)+\]\:\:(\w+\.)+)(\w*)$' {
  455.                         $_base = $matches[1]  # everything before the expression
  456.                         $_expression = $matches[2].TrimEnd('.') # expression less trailing '.'
  457.                         $_pat = $matches[5] + '*'  # the member to look for...
  458.                         Write-Members
  459.                         break;
  460.                     }
  461.  
  462.                     # Handle variable name expansion...
  463.                     '(^.*\$)(\w+)$' {
  464.                         $_prefix = $matches[1]
  465.                         $_varName = $matches[2]
  466.                         foreach ($_v in Get-ChildItem ('variable:' + $_varName + '*'))
  467.                         {
  468.                             $_prefix + $_v.name
  469.                         }
  470.                         break;
  471.                     }
  472.  
  473.                     # Handle env&function drives variable name expansion...
  474.                     '(^.*\$)(.*\:)(\w+)$' {
  475.                         $_prefix = $matches[1]
  476.                         $_drive = $matches[2]
  477.                         $_varName = $matches[3]
  478.                         if ($_drive -eq "env:" -or $_drive -eq "function:")
  479.                         {
  480.                             foreach ($_v in Get-ChildItem ($_drive + $_varName + '*'))
  481.                             {
  482.                                 $_prefix + $_drive + $_v.name
  483.                             }
  484.                         }
  485.                         break;
  486.                     }
  487.  
  488.                     # Handle array's element property and method expansion
  489.                     # where there are intermediate properties...
  490.                     # e.g. foo[0].n.b<tab>
  491.                     '(^.*)(\$((\w+\.)|(\w+(\[(\w|,)+\])+\.))+)(\w*)$'
  492.                     {
  493.                         $_base = $matches[1]
  494.                         $_expression = $matches[2].TrimEnd('.')
  495.                         $_pat = $Matches[8] + '*'
  496.                         [void] ( iex "$_expression.IsDataLanguageOnly" ) # for [ScriptBlock]
  497.                         if ( $_expression -match '^\$_\.' )
  498.                         {
  499.                             $_expression = $_expression -replace '^\$_(.*)',('$global:_dummy' + '$1')
  500.                         }
  501.                         Write-Members
  502.                         break;
  503.                     }
  504.  
  505.                     # Handle property and method expansion rooted at type object...
  506.                     # e.g. [System.Type].a<tab>
  507.                     '(^\[(\w|\.)+\])\.(\w*)$'
  508.                     {
  509.                         if ( $(iex $Matches[1]) -isnot [System.Type] ) { break; }
  510.                         $_expression = $Matches[1]
  511.                         $_pat = $Matches[$matches.Count-1] + '*'
  512.                         Write-Members
  513.                         break;
  514.                     }
  515.  
  516.                     # Handle complex property and method expansion on type object members
  517.                     # where there are intermediate properties...
  518.                     # e.g. [datetime].Assembly.a<tab>
  519.                     '^(\[(\w|\.)+\]\.(\w+\.)+)(\w*)$' {
  520.                         $_expression = $matches[1].TrimEnd('.') # expression less trailing '.'
  521.                         $_pat = $matches[4] + '*'  # the member to look for...
  522.                         if ( $(iex $_expression) -eq $null ) { break; }
  523.                         Write-Members
  524.                         break;
  525.                     }
  526.  
  527.                     # Handle property and method expansion rooted at close parenthes...
  528.                     # e.g. (123).a<tab>
  529.                     '^(.*)\)((\w|\.)*)\.(\w*)$' {
  530.                         $_base = $Matches[1] + ")"
  531.                         if ( $matches[3] -eq $null) { $_expression = '[System.Type]' }
  532.                         else { $_expression = '[System.Type]' + $Matches[2] }
  533.                         $_pat = $matches[4] + '*'
  534.                         iex "$_expression | Get-Member $_pat | sort MemberType,Name" |
  535.                         % {
  536.                             if ( $_.MemberType -like "*Method*" -or $_.MemberType -like "*Parameterized*" ) { $parenthes = "(" }
  537.                             if ( $Matches[2] -eq "" ) { $_base + "." + $_.Name + $parenthes }
  538.                             else { $_base + $Matches[2] + "." + $_.Name + $parenthes }
  539.                           }
  540.                         break;
  541.                     }
  542.  
  543.                     # Handle .NET type name expansion ...
  544.                     # e.g. [Microsoft.PowerShell.Com<tab>
  545.                     '^\[((\w+\.?)+)$' {
  546.                         $_opt = $matches[1] + '*'
  547.                         foreach ( $_exp in $_TypeNames_System -like $_opt )
  548.                         {
  549.                             '[' + $_exp
  550.                         }
  551.                         foreach ( $_exp in $_TypeNames -like $_opt )
  552.                         {
  553.                             '[' + $_exp
  554.                         }
  555.                         break;
  556.                     }
  557.  
  558.                     # Handle file/directory name which contains $env: variable
  559.                     # e.g.  $env:windir\<tab>
  560.                     '^\$(env:)?\w+([\\/][^\\/]*)*$' {
  561.                         $path = iex ('"' + $Matches[0] + '"')
  562.                         if ( $Matches[2].Length -gt 1 )
  563.                         {
  564.                             $parent = Split-Path $path -Parent
  565.                             $leaf = (Split-Path $path -Leaf) + '*'
  566.                         }
  567.                         else
  568.                         {
  569.                             $parent = $path
  570.                             $leaf = '*'
  571.                         }
  572.                         if ( Test-Path $parent )
  573.                         {
  574.                             $i = $Matches[0].LastIndexOfAny("/\")
  575.                             $_base = $Matches[0].Substring(0,$i+1)
  576.                             [IO.Directory]::GetFileSystemEntries( $parent, $leaf ) | % { $_base + ($_.Split("\/")[-1] -replace '([\$\s&])','`$1' -replace '([[\]])', '````$1') }
  577.                         }
  578.                     }
  579.  
  580.                     # Do completion on parameters...
  581.                     '^-([\w0-9]*)' {
  582.                         $_pat = $matches[1] + '*'
  583.  
  584.                         # extract the command name from the string
  585.                         # first split the string into statements and pipeline elements
  586.                         # This doesn't handle strings however.
  587.                         $_cmdlet = [regex]::Split($line, '[|;=]')[-1]
  588.  
  589.                         #  Extract the trailing unclosed block e.g. ls | foreach { cp
  590.                         if ($_cmdlet -match '\{([^\{\}]*)$')
  591.                         {
  592.                             $_cmdlet = $matches[1]
  593.                         }
  594.  
  595.                         # Extract the longest unclosed parenthetical expression...
  596.                         if ($_cmdlet -match '\(([^()]*)$')
  597.                         {
  598.                             $_cmdlet = $matches[1]
  599.                         }
  600.  
  601.                         # take the first space separated token of the remaining string
  602.                         # as the command to look up. Trim any leading or trailing spaces
  603.                         # so you don't get leading empty elements.
  604.                         $_cmdlet = $_cmdlet.Trim().Split()[0]
  605.  
  606.                         # now get the info object for it...
  607.                         $_cmdlet = @(Get-Command -type 'cmdlet,alias,function,filter,ExternalScript' $_cmdlet)[0]
  608.  
  609.                         # loop resolving aliases...
  610.                         while ($_cmdlet.CommandType -eq 'alias')
  611.                         {
  612.                             $_cmdlet = @(Get-Command -type 'cmdlet,alias,function,filter,ExternalScript' $_cmdlet.Definition)[0]
  613.                         }
  614.  
  615.                         if ( $_cmdlet.CommandType -eq "Cmdlet" )
  616.                         {
  617.                             # expand the parameter sets and emit the matching elements
  618.                             foreach ($_n in $_cmdlet.ParameterSets |
  619.                                 Select-Object -expand parameters | Sort-Object -Unique name)
  620.                             {
  621.                                 $_n = $_n.name
  622.                                 if ($_n -like $_pat) { '-' + $_n }
  623.                             }
  624.                             break;
  625.                         }
  626.                         elseif ( "ExternalScript", "Function", "Filter" -contains $_cmdlet.CommandType )
  627.                         {
  628.                             if ( $_cmdlet.CommandType -eq "ExternalScript" )
  629.                             {
  630.                                 $_fsr = New-Object IO.StreamReader $_cmdlet.Definition
  631.                                 $_def = "Function _Dummy { $($_fsr.ReadToEnd()) }"
  632.                                 $_fsr.Close()
  633.                                 iex $_def
  634.                                 $_cmdlet = "_Dummy"
  635.                             }
  636.  
  637.                             if ( ((gi "Function:$_cmdlet").Definition -replace '\n').Split("{")[0] -match 'param\((.*\))\s*[;\.&a-zA-Z]*\s*$' )
  638.                             {
  639.                                 ( ( ( $Matches[1].Split('$', "RemoveEmptyEntries" -as [System.StringSplitOptions]) -replace `
  640.                                 '^(\w+)(.*)','$1' ) -notmatch '^\s+$' ) -notmatch '^\s*\[.*\]\s*$' ) -like $_pat | sort | % { '-' + $_ }
  641.                             }
  642.                             break;
  643.                         }
  644.                         elseif ( $_command -eq $null )
  645.                         {
  646.                             "-and", "-as", "-band", "-bnot", "-bor", "-bxor", "-ccontains", "-ceq", "-cge", "-cgt", "-cle", "-clike", "-clt",
  647.                             "-cmatch", "-cne", "-cnotcontains", "-cnotlike", "-cnotmatch", "-contains", "-creplace", "-csplit", "-eq", "-f", "-ge",
  648.                             "-gt", "-icontains", "-ieq", "-ige", "-igt", "-ile", "-ilike", "-ilt", "-imatch", "-ine", "-inotcontains", "-inotlike",
  649.                             "-inotmatch", "-ireplace", "-is", "-isnot", "-isplit", "-join", "-le", "-like", "-lt", "-match", "-ne", "-not", "-notcontains",
  650.                             "-notlike", "-notmatch", "-or", "-replace", "-split", "-xor" -like "-$_pat"
  651.                         }
  652.                         break;
  653.                     }
  654.  
  655.  
  656.                     # try to find a matching command...
  657.                     default {
  658.  
  659.                         $lastex =  [regex]::Split($line, '[|;]')[-1]
  660.                         if ( $lastex -match '^\s*(\$\w+(\[[0-9,]+\])*(\.\w+(\[[0-9,]+\])*)*)\s*=\s+(("\w+"\s*,\s+)*)"\w+"\s*-as\s+$' )
  661.                         {
  662.                             if ( $Matches[6] -ne $nul )
  663.                             {
  664.                             $brackets = "[]"
  665.                             }
  666.                             '['+ $global:_enum + $brackets + ']'
  667.                             break;
  668.                         }
  669.  
  670.  
  671.                         if ( $lastex -match '^\s*(\$\w+(\[[0-9,]+\])*(\.\w+(\[[0-9,]+\])*)*)\s*=\s+(("\w+"\s*,\s+)*)\s*(\w*)$' )
  672.                         {
  673.                             $_pat = $Matches[7] + '*'
  674.  
  675.                             $_type = @(iex $Matches[1])[0].GetType()
  676.                             if ( $_type.IsEnum )
  677.                             {
  678.                                 $global:_enum = $_type.FullName
  679.                                 [Enum]::GetValues($_type) -like $_pat -replace '^(.*)$','"$1"'
  680.                                 break;
  681.                             }
  682.                         }
  683.  
  684.                         $lastex =  [regex]::Split($line, '[|;=]')[-1]
  685.                         if ($lastex  -match '[[$].*\w+\(.*-as\s*$')
  686.                         {
  687.                             '['+ $global:_enum + ']'
  688.                         }
  689.                         elseif ( $lastex -match '([[$].*(\w+))\((.*)$' )
  690.                         #elseif ( $lastex -match '([[$].*(\w+))\(([^)]*)$' )
  691.                         {
  692.                             $_method = $Matches[1]
  693.  
  694.                             if ( $Matches[3] -match "(.*)((`"|')(\w+,)+(\w*))$" )
  695.                             {
  696.                                 $continuous = $true
  697.                                 $_opt =  $Matches[5] + '*'
  698.                                 $_base =  $Matches[2].TrimStart('"') -replace '(.*,)\w+$','$1'
  699.                                 $position = $Matches[1].Split(",").Length
  700.                             }
  701.                             else
  702.                             {
  703.                                 $continuous = $false
  704.                                 $_opt = ($Matches[3].Split(',')[-1] -replace '^\s*','') + "*"
  705.                                 $position = $Matches[3].Split(",").Length
  706.                             }
  707.  
  708.                             if ( ($_mdefs = iex ($_method + ".OverloadDefinitions")) -eq $null )
  709.                             {
  710.                                 $tname, $mname = $_method.Split(":", "RemoveEmptyEntries" -as [System.StringSplitOptions])
  711.                                 $_mdefs = iex ($tname + '.GetMember("' + $mname + '") | % { $_.ToString() }')
  712.                             }
  713.  
  714.                             foreach ( $def in $_mdefs )
  715.                             {
  716.                                 [void] ($def -match '\((.*)\)')
  717.                                 foreach ( $param in [regex]::Split($Matches[1], ', ')[$position-1] )
  718.                                 {
  719.                                     if ($param -eq $null -or $param -eq "")
  720.                                     {
  721.                                         continue;
  722.                                     }
  723.                                     $type = $param.split()[0]
  724.  
  725.                                     if ( $type -like '*`[*' -or $type -eq "Params" -or $type -eq "" )
  726.                                     {
  727.                                         continue;
  728.                                     }
  729.                                     $fullname  = @($_typenames -like "*$type*")
  730.                                     foreach ( $name in $fullname )
  731.                                     {
  732.                                         if ( $continuous -eq $true -and ( $name  -as [System.Type] ).IsEnum )
  733.                                         {
  734.                                             $output = [Enum]::GetValues($name) -like $_opt -replace '^(.*)$',($_base + '$1')
  735.                                             $output | sort
  736.                                         }
  737.                                         elseif ( ( $name  -as [System.Type] ).IsEnum )
  738.                                         {
  739.                                             $global:_enum = $name
  740.                                             $output = [Enum]::GetValues($name) -like $_opt -replace '^(.*)$','"$1"'
  741.                                             $output | sort
  742.                                         }
  743.                                     }
  744.                                 }
  745.                             }
  746.                             if ( $output -ne $null )
  747.                             {
  748.                                 break;
  749.                             }
  750.                         }
  751.  
  752.  
  753.                         if ( $line[-1] -eq " " )
  754.                         {
  755.                             $_cmdlet = $line.TrimEnd(" ").Split(" |(;={")[-1]
  756.  
  757.                             # now get the info object for it...
  758.                             $_cmdlet = @(Get-Command -type 'cmdlet,alias' $_cmdlet)[0]
  759.  
  760.                             # loop resolving aliases...
  761.                             while ($_cmdlet.CommandType -eq 'alias')
  762.                             {
  763.                                 $_cmdlet = @(Get-Command -type 'cmdlet,alias' $_cmdlet.Definition)[0]
  764.                             }
  765.  
  766.                             if ( "Set-ExecutionPolicy" -eq $_cmdlet.Name )
  767.                             {
  768.                                 "Unrestricted", "RemoteSigned", "AllSigned", "Restricted", "Default" | sort
  769.                                 break;
  770.                             }
  771.  
  772.                             if ( "Trace-Command","Get-TraceSource","Set-TraceSource" -contains $_cmdlet.Name )
  773.                             {
  774.                                Get-TraceSource | % { $_.Name } | sort -Unique
  775.                                break;
  776.                             }
  777.  
  778.                             if ( "New-Object" -eq $_cmdlet.Name )
  779.                             {
  780.                                  $_TypeNames_System
  781.                                  $_TypeNames
  782.                                  break;
  783.                             }
  784.  
  785.                             if ( $_cmdlet.Noun -like "*WMI*" )
  786.                             {
  787.                                 $_WMIClasses
  788.                                 break;
  789.                             }
  790.  
  791.                             if ( "Get-Process" -eq $_cmdlet.Name )
  792.                             {
  793.                                  Get-Process | % { $_.Name } | sort
  794.                                  break;
  795.                             }
  796.  
  797.                             if ( "Add-PSSnapin", "Get-PSSnapin", "Remove-PSSnapin" -contains $_cmdlet.Name )
  798.                             {
  799.                                 if ( $global:_snapin -ne $null )
  800.                                 {
  801.                                     $global:_snapin
  802.                                     break;
  803.                                 }
  804.                                 else
  805.                                 {
  806.                                     $global:_snapin = $(Get-PSSnapIn -Registered;Get-PSSnapIn)| sort Name -Unique;
  807.                                     $global:_snapin
  808.                                     break;
  809.                                 }
  810.                             }
  811.  
  812.                             if ( "Get-PSDrive", "New-PSDrive", "Remove-PSDrive" `
  813.                                  -contains $_cmdlet.Name -and "Name" )
  814.                             {
  815.                                 Get-PSDrive | sort
  816.                                 break;
  817.                             }
  818.  
  819.                             if ( "Get-Eventlog" -eq $_cmdlet.Name )
  820.                             {
  821.                                  Get-EventLog -List | % { $_base + ($_.Log -replace '\s','` ') }
  822.                                  break;
  823.                             }
  824.  
  825.                             if ( "Get-Help" -eq $_cmdlet.Name )
  826.                             {
  827.                                 Get-Help -Category all | % { $_.Name } | sort -Unique
  828.                                      break;
  829.                             }
  830.  
  831.                             if ( "Get-Service", "Restart-Service", "Resume-Service",
  832.                                  "Start-Service", "Stop-Service", "Suspend-Service" `
  833.                                  -contains $_cmdlet.Name )
  834.                             {
  835.                                 Get-Service | sort Name  | % { $_base + ($_.Name -replace '\s','` ') }
  836.                                 break;
  837.                             }
  838.  
  839.                             if ( "Get-Command" -eq $_cmdlet.Name )
  840.                             {
  841.                                  Get-Command -CommandType All | % { $_base + ($_.Name -replace '\s','` ') }
  842.                                  break;
  843.                             }
  844.  
  845.                             if ( "Format-List", "Format-Custom", "Format-Table", "Format-Wide", "Compare-Object",
  846.                                  "ConvertTo-Html", "Measure-Object", "Select-Object", "Group-Object", "Sort-Object" `
  847.                                   -contains $_cmdlet.Name )
  848.                             {
  849.                                  Get-PipeLineObject
  850.                                  $_dummy | Get-Member -MemberType Properties,ParameterizedProperty | sort membertype | % { $_base + ($_.Name -replace '\s','` ') }
  851.                                  break;
  852.                             }
  853.  
  854.                         }
  855.  
  856.                         if ( $line[-1] -eq " " )
  857.                         {
  858.                             # extract the command name from the string
  859.                             # first split the string into statements and pipeline elements
  860.                             # This doesn't handle strings however.
  861.                             $_cmdlet = [regex]::Split($line, '[|;=]')[-1]
  862.  
  863.                             #  Extract the trailing unclosed block e.g. ls | foreach { cp
  864.                             if ($_cmdlet -match '\{([^\{\}]*)$')
  865.                             {
  866.                                 $_cmdlet = $matches[1]
  867.                             }
  868.  
  869.                             # Extract the longest unclosed parenthetical expression...
  870.                             if ($_cmdlet -match '\(([^()]*)$')
  871.                             {
  872.                                 $_cmdlet = $matches[1]
  873.                             }
  874.  
  875.                             # take the first space separated token of the remaining string
  876.                             # as the command to look up. Trim any leading or trailing spaces
  877.                             # so you don't get leading empty elements.
  878.                             $_cmdlet = $_cmdlet.Trim().Split()[0]
  879.  
  880.                             # now get the info object for it...
  881.                             $_cmdlet = @(Get-Command -type 'Application' $_cmdlet)[0]
  882.  
  883.                             if ( $_cmdlet.Name -eq "powershell.exe" )
  884.                             {
  885.                                 "-PSConsoleFile", "-Version", "-NoLogo", "-NoExit", "-Sta", "-NoProfile", "-NonInteractive",
  886.                                 "-InputFormat", "-OutputFormat", "-EncodedCommand", "-File", "-Command" | sort
  887.                                 break;
  888.                             }
  889.                             if ( $_cmdlet.Name -eq "fsutil.exe" )
  890.                             {
  891.                                 "behavior query", "behavior set", "dirty query", "dirty set",
  892.                                 "file findbysid", "file queryallocranges", "file setshortname", "file setvaliddata", "file setzerodata", "file createnew",
  893.                                 "fsinfo drives", "fsinfo drivetype", "fsinfo volumeinfo", "fsinfo ntfsinfo", "fsinfo statistics",
  894.                                 "hardlink create", "objectid query", "objectid set", "objectid delete", "objectid create",
  895.                                 "quota disable", "quota track", "quota enforce", "quota violations", "quota modify", "quota query",
  896.                                 "reparsepoint query", "reparsepoint delete", "sparse setflag", "sparse queryflag", "sparse queryrange", "sparse setrange",
  897.                                 "usn createjournal", "usn deletejournal", "usn enumdata", "usn queryjournal", "usn readdata", "volume dismount", "volume diskfree" | sort
  898.                                 break;
  899.                             }
  900.                             if ( $_cmdlet.Name -eq "net.exe" )
  901.                             {
  902.                                 "ACCOUNTS ", " COMPUTER ", " CONFIG ", " CONTINUE ", " FILE ", " GROUP ", " HELP ",
  903.                                 "HELPMSG ", " LOCALGROUP ", " NAME ", " PAUSE ", " PRINT ", " SEND ", " SESSION ",
  904.                                 "SHARE ", " START ", " STATISTICS ", " STOP ", " TIME ", " USE ", " USER ", " VIEW" | sort
  905.                                 break;
  906.                             }
  907.                             if ( $_cmdlet.Name -eq "ipconfig.exe" )
  908.                             {
  909.                                 "/?", "/all", "/renew", "/release", "/flushdns", "/displaydns",
  910.                                 "/registerdns", "/showclassid", "/setclassid"
  911.                                 break;
  912.                             }
  913.                         }
  914.  
  915.                         if ( $line -match '\w+\s+(\w+(\.|[^\s\.])*)$' )
  916.                         {
  917.                             #$_opt = $Matches[1] + '*'
  918.                             $_cmdlet = $line.TrimEnd(" ").Split(" |(;={")[-2]
  919.  
  920.                             $_opt = $Matches[1].Split(" ,")[-1] + '*'
  921.                             $_base = $Matches[1].Substring(0,$Matches[1].Length-$Matches[1].Split(" ,")[-1].length)
  922.  
  923.  
  924.                             # now get the info object for it...
  925.                             $_cmdlet = @(Get-Command -type 'cmdlet,alias' $_cmdlet)[0]
  926.  
  927.                             # loop resolving aliases...
  928.                             while ($_cmdlet.CommandType -eq 'alias')
  929.                             {
  930.                                 $_cmdlet = @(Get-Command -type 'cmdlet,alias' $_cmdlet.Definition)[0]
  931.                             }
  932.  
  933.                             if ( "Set-ExecutionPolicy" -eq $_cmdlet.Name )
  934.                             {
  935.                                 "Unrestricted", "RemoteSigned", "AllSigned", "Restricted", "Default" -like $_opt | sort
  936.                                 break;
  937.                             }
  938.  
  939.                             if ( "Trace-Command","Get-TraceSource","Set-TraceSource" -contains $_cmdlet.Name )
  940.                             {
  941.                                Get-TraceSource -Name $_opt | % { $_.Name } | sort -Unique | % { $_base + ($_ -replace '\s','` ') }
  942.                                break;
  943.                             }
  944.  
  945.                             if ( "New-Object" -eq $_cmdlet.Name )
  946.                             {
  947.                                  $_TypeNames_System -like $_opt
  948.                                  $_TypeNames -like $_opt
  949.                                  break;
  950.                             }
  951.  
  952.                             if ( $_cmdlet.Name -like "*WMI*" )
  953.                             {
  954.                                 $_WMIClasses -like $_opt
  955.                                 break;
  956.                             }
  957.  
  958.                             if ( "Get-Process" -eq $_cmdlet.Name )
  959.                             {
  960.                                  Get-Process $_opt | % { $_.Name } | sort | % { $_base + ($_ -replace '\s','` ') }
  961.                                  break;
  962.                             }
  963.  
  964.                             if ( "Add-PSSnapin", "Get-PSSnapin", "Remove-PSSnapin" -contains $_cmdlet.Name )
  965.                             {
  966.                                 if ( $global:_snapin -ne $null )
  967.                                 {
  968.                                     $global:_snapin -like $_opt | % { $_base + ($_ -replace '\s','` ') }
  969.                                     break;
  970.                                 }
  971.                                 else
  972.                                 {
  973.                                     $global:_snapin = $(Get-PSSnapIn -Registered;Get-PSSnapIn)| sort Name -Unique;
  974.                                     $global:_snapin -like $_opt | % { $_base + ($_ -replace '\s','` ') }
  975.                                     break;
  976.                                 }
  977.                             }
  978.  
  979.                             if ( "Get-PSDrive", "New-PSDrive", "Remove-PSDrive" `
  980.                                  -contains $_cmdlet.Name -and "Name" )
  981.                             {
  982.                                 Get-PSDrive -Name $_opt | sort | % { $_base + ($_ -replace '\s','` ') }
  983.                                 break;
  984.                             }
  985.  
  986.                             if ( "Get-PSProvider" -eq $_cmdlet.Name )
  987.                             {
  988.                                 Get-PSProvider -PSProvider $_opt | % { $_.Name } | sort | % { $_base + ($_ -replace '\s','` ') }
  989.                                 break;
  990.                             }
  991.  
  992.  
  993.                             if ( "Get-Eventlog" -eq $_cmdlet.Name )
  994.                             {
  995.                                  Get-EventLog -List | ? { $_.Log -like $_opt } | % { $_base + ($_.Log -replace '\s','` ') }
  996.                                  break;
  997.                             }
  998.  
  999.                             if ( "Get-Help" -eq $_cmdlet.Name )
  1000.                             {
  1001.                                 Get-Help -Category all -Name $_opt | % { $_.Name } | sort -Unique
  1002.                                      break;
  1003.                             }
  1004.  
  1005.                             if ( "Get-Service", "Restart-Service", "Resume-Service",
  1006.                                  "Start-Service", "Stop-Service", "Suspend-Service" `
  1007.                                  -contains $_cmdlet.Name )
  1008.                             {
  1009.                                 Get-Service -Name $_opt | sort Name  | % { $_base + ($_.Name -replace '\s','` ') }
  1010.                                 break;
  1011.                             }
  1012.  
  1013.                             if ( "Get-Command" -eq $_cmdlet.Name )
  1014.                             {
  1015.                                  Get-Command -CommandType All -Name $_opt | % { $_base + ($_.Name -replace '\s','` ') }
  1016.                                  break;
  1017.                             }
  1018.  
  1019.                             if ( "Format-List", "Format-Custom", "Format-Table", "Format-Wide", "Compare-Object",
  1020.                                  "ConvertTo-Html", "Measure-Object", "Select-Object", "Group-Object", "Sort-Object" `
  1021.                                   -contains $_cmdlet.Name )
  1022.                             {
  1023.                                  Get-PipeLineObject
  1024.                                  $_dummy | Get-Member -Name $_opt -MemberType Properties,ParameterizedProperty | sort membertype | % { $_base + ($_.Name -replace '\s','` ') }
  1025.                                  break;
  1026.                             }
  1027.                         }
  1028.  
  1029.                         if ( $line -match '(-(\w+))\s+([^-]*$)' )
  1030.                         {
  1031.  
  1032.                             $_param = $matches[2] + '*'
  1033.                             $_opt = $Matches[3].Split(" ,")[-1] + '*'
  1034.                             $_base = $Matches[3].Substring(0,$Matches[3].Length-$Matches[3].Split(" ,")[-1].length)
  1035.  
  1036.                             # extract the command name from the string
  1037.                             # first split the string into statements and pipeline elements
  1038.                             # This doesn't handle strings however.
  1039.                             $_cmdlet = [regex]::Split($line, '[|;=]')[-1]
  1040.  
  1041.                             #  Extract the trailing unclosed block e.g. ls | foreach { cp
  1042.                             if ($_cmdlet -match '\{([^\{\}]*)$')
  1043.                             {
  1044.                                 $_cmdlet = $matches[1]
  1045.                             }
  1046.  
  1047.                             # Extract the longest unclosed parenthetical expression...
  1048.                             if ($_cmdlet -match '\(([^()]*)$')
  1049.                             {
  1050.                                 $_cmdlet = $matches[1]
  1051.                             }
  1052.  
  1053.                             # take the first space separated token of the remaining string
  1054.                             # as the command to look up. Trim any leading or trailing spaces
  1055.                             # so you don't get leading empty elements.
  1056.                             $_cmdlet = $_cmdlet.Trim().Split()[0]
  1057.  
  1058.                             # now get the info object for it...
  1059.                             $_cmdlet = @(Get-Command -type 'cmdlet,alias,ExternalScript,Filter,Function' $_cmdlet)[0]
  1060.  
  1061.                             # loop resolving aliases...
  1062.                             while ($_cmdlet.CommandType -eq 'alias')
  1063.                             {
  1064.                                 $_cmdlet = @(Get-Command -type 'cmdlet,alias,ExternalScript,Filter,Function' $_cmdlet.Definition)[0]
  1065.                             }
  1066.  
  1067.                             if ( $_param.TrimEnd("*") -eq "ea" -or $_param.TrimEnd("*") -eq "wa" )
  1068.                             {
  1069.                                "SilentlyContinue", "Stop", "Continue", "Inquire" |
  1070.                                ? { $_ -like $_opt } | sort -Unique
  1071.                                break;
  1072.                             }
  1073.  
  1074.                             if ( "Out-File","Export-CSV","Select-String","Export-Clixml" -contains $_cmdlet.Name `
  1075.                                  -and "Encoding" -like $_param)
  1076.                             {
  1077.                                 "Unicode",  "UTF7", "UTF8", "ASCII", "UTF32", "BigEndianUnicode", "Default", "OEM" |
  1078.                                 ? { $_ -like $_opt } | sort -Unique
  1079.                                 break;
  1080.                             }
  1081.  
  1082.                             if ( "Trace-Command","Get-TraceSource","Set-TraceSource" -contains $_cmdlet.Name `
  1083.                                 -and "Name" -like $_param)
  1084.                             {
  1085.                                Get-TraceSource -Name $_opt | % { $_.Name } | sort -Unique | % { $_base + ($_ -replace '\s','` ') }
  1086.                                break;
  1087.                             }
  1088.  
  1089.                             if ( "New-Object" -like $_cmdlet.Name )
  1090.                             {
  1091.                                 if ( "ComObject" -like $_param )
  1092.                                 {
  1093.                                     $_ProgID -like $_opt  | % { $_ -replace '\s','` ' }
  1094.                                     break;
  1095.                                 }
  1096.  
  1097.                                 if ( "TypeName" -like $_param )
  1098.                                 {
  1099.                                     $_TypeNames_System -like $_opt
  1100.                                     $_TypeNames -like $_opt
  1101.                                     break;
  1102.                                 }
  1103.                             }
  1104.  
  1105.                             if ( "New-Item" -eq $_cmdlet.Name )
  1106.                             {
  1107.                                 if ( "ItemType" -like $_param )
  1108.                                 {
  1109.                                     "directory", "file" -like $_opt
  1110.                                     break;
  1111.                                 }
  1112.                             }
  1113.  
  1114.                             if ( "Get-Location", "Get-PSDrive", "Get-PSProvider", "New-PSDrive", "Remove-PSDrive" `
  1115.                                  -contains $_cmdlet.Name `
  1116.                                  -and "PSProvider" -like $_param )
  1117.                             {
  1118.                                 Get-PSProvider -PSProvider $_opt | % { $_.Name } | sort  | % { $_base + ($_ -replace '\s','` ') }
  1119.                                 break;
  1120.                             }
  1121.  
  1122.                             if ( "Get-Location" -eq $_cmdlet.Name -and "PSDrive" -like $_param )
  1123.                             {
  1124.                                 Get-PSDrive -Name $_opt | sort | % { $_base + ($_ -replace '\s','` ') }
  1125.                                 break;
  1126.                             }
  1127.  
  1128.                             if ( "Get-PSDrive", "New-PSDrive", "Remove-PSDrive" `
  1129.                                  -contains $_cmdlet.Name -and "Name" -like $_param )
  1130.                             {
  1131.                                 Get-PSDrive -Name $_opt | sort | % { $_base + ($_ -replace '\s','` ') }
  1132.                                 break;
  1133.                             }
  1134.  
  1135.                             if ( "Get-Command" -eq $_cmdlet.Name -and  "PSSnapin" -like $_param)
  1136.                             {
  1137.                                 if ( $global:_snapin -ne $null )
  1138.                                 {
  1139.                                     $global:_snapin -like $_opt  | % { $_base + $_ }
  1140.                                     break;
  1141.                                 }
  1142.                                 else
  1143.                                 {
  1144.                                     $global:_snapin = $(Get-PSSnapIn -Registered;Get-PSSnapIn)| sort Name -Unique;
  1145.                                     $global:_snapin -like $_opt  | % { $_base + ($_ -replace '\s','` ') }
  1146.                                     break;
  1147.                                 }
  1148.                             }
  1149.  
  1150.                             if ( "Add-PSSnapin", "Get-PSSnapin", "Remove-PSSnapin" `
  1151.                                  -contains $_cmdlet.Name -and "Name" -like $_param )
  1152.                             {
  1153.                                 if ( $global:_snapin -ne $null )
  1154.                                 {
  1155.                                     $global:_snapin -like $_opt | % { $_base + ($_ -replace '\s','` ') }
  1156.                                     break;
  1157.                                 }
  1158.                                 else
  1159.                                 {
  1160.                                     $global:_snapin = $(Get-PSSnapIn -Registered;Get-PSSnapIn)| sort Name -Unique;
  1161.                                     $global:_snapin -like $_opt | % { $_base + $_ }
  1162.                                     break;
  1163.                                 }
  1164.                             }
  1165.  
  1166.                             if ( "Clear-Variable", "Export-Alias", "Get-Alias", "Get-PSDrive", "Get-Variable", "Import-Alias",
  1167.                                  " New-Alias", "New-PSDrive", "New-Variable", "Remove-Variable", "Set-Alias", "Set-Variable" `
  1168.                                  -contains $_cmdlet.Name -and "Scope" -like $_param )
  1169.                             {
  1170.                                 "Global", "Local", "Script" -like $_opt
  1171.                                 break;
  1172.                             }
  1173.  
  1174.                             if ( "Get-Process", "Stop-Process", "Wait-Process" -contains $_cmdlet.Name -and "Name" -like $_param )
  1175.                             {
  1176.                                  Get-Process $_opt | % { $_.Name } | sort | % { $_base + ($_ -replace '\s','` ') }
  1177.                                  break;
  1178.                             }
  1179.  
  1180.                             if ( "Get-Eventlog" -eq $_cmdlet.Name -and "LogName" -like $_param )
  1181.                             {
  1182.                                  Get-EventLog -List | ? { $_.Log -like $_opt } | % { $_base + ($_.Log -replace '\s','` ') }
  1183.                                  break;
  1184.                             }
  1185.  
  1186.                             if ( "Get-Help" -eq $_cmdlet.Name )
  1187.                             {
  1188.                                  if ( "Name" -like $_param )
  1189.                                  {
  1190.                                      Get-Help -Category all -Name $_opt | % { $_.Name } | sort -Unique
  1191.                                      break;
  1192.                                  }
  1193.                                  if ( "Category" -like $_param )
  1194.                                  {
  1195.                                      "Alias", "Cmdlet", "Provider", "General", "FAQ",
  1196.                                      "Glossary", "HelpFile", "All" -like $_opt | sort | % { $_base + $_ }
  1197.                                      break;
  1198.                                  }
  1199.                             }
  1200.  
  1201.                             if ( "Get-Service", "Restart-Service", "Resume-Service",
  1202.                                  "Start-Service", "Stop-Service", "Suspend-Service" `
  1203.                                  -contains $_cmdlet.Name )
  1204.                             {
  1205.                                  if ( "Name" -like $_param )
  1206.                                  {
  1207.                                      Get-Service -Name $_opt | sort Name  | % { $_base + ($_.Name -replace '\s','` ') }
  1208.                                      break;
  1209.                                  }
  1210.                                  if ( "DisplayName" -like $_param )
  1211.                                  {
  1212.                                      Get-Service -Name $_opt | sort DisplayName | % { $_base + ($_.DisplayName -replace '\s','` ') }
  1213.                                      break;
  1214.                                  }
  1215.                             }
  1216.  
  1217.                             if ( "New-Service" -eq $_cmdlet.Name -and "dependsOn" -like $_param )
  1218.                             {
  1219.                                  Get-Service -Name $_opt | sort Name | % { $_base + ($_.Name -replace '\s','` ') }
  1220.                                  break;
  1221.                             }
  1222.  
  1223.                             if ( "Get-EventLog" -eq $_cmdlet.Name -and "EntryType" -like $_param )
  1224.                             {
  1225.                                  "Error", "Information", "FailureAudit", "SuccessAudit", "Warning" -like $_opt | sort | % { $_base + $_ }
  1226.                                  break;
  1227.                             }
  1228.  
  1229.                             if ( "Get-Command" -eq $_cmdlet.Name -and "Name" -like $_param )
  1230.                             {
  1231.                                  Get-Command -CommandType All -Name $_opt | % { $_base + ($_.Name -replace '\s','` ') }
  1232.                                  break;
  1233.                             }
  1234.  
  1235.                             if ( $_cmdlet.Noun -like "*WMI*" )
  1236.                             {
  1237.                                 if ( "Class" -like $_param )
  1238.                                 {
  1239.                                     $_WMIClasses -like $_opt
  1240.                                     break;
  1241.                                 }
  1242.                             }
  1243.  
  1244.                             if ( "Format-List", "Format-Custom", "Format-Table", "Format-Wide", "Compare-Object",
  1245.                                  "ConvertTo-Html", "Measure-Object", "Select-Object", "Group-Object", "Sort-Object" `
  1246.                                   -contains $_cmdlet.Name -and "Property" -like $_param )
  1247.                             {
  1248.                                  Get-PipeLineObject
  1249.                                  $_dummy | Get-Member -Name $_opt -MemberType Properties,ParameterizedProperty | sort membertype | % { $_base + ($_.Name -replace '\s','` ') }
  1250.                                  break;
  1251.                             }
  1252.  
  1253.                             if ( "Select-Object" -eq $_cmdlet.Name )
  1254.                             {
  1255.                                 if ( "ExcludeProperty" -like $_param )
  1256.                                 {
  1257.                                  Get-PipeLineObject
  1258.                                  $_dummy | Get-Member -Name $_opt -MemberType Properties,ParameterizedProperty | sort membertype | % { $_base + ($_.Name -replace '\s','` ') }
  1259.                                  break;
  1260.                                 }
  1261.  
  1262.                                 if ( "ExpandProperty" -like $_param )
  1263.                                 {
  1264.                                  Get-PipeLineObject
  1265.                                  $_dummy | Get-Member -Name $_opt -MemberType Properties,ParameterizedProperty | sort membertype | % { $_.Name }
  1266.                                  break;
  1267.                                 }
  1268.                             }
  1269.  
  1270.                         if ( "ExternalScript", "Function", "Filter" -contains $_cmdlet.CommandType )
  1271.                         {
  1272.                             if ( $_cmdlet.CommandType -eq "ExternalScript" )
  1273.                             {
  1274.                                 $_fsr = New-Object IO.StreamReader $_cmdlet.Definition
  1275.                                 $_def = "Function _Dummy { $($_fsr.ReadToEnd()) }"
  1276.                                 $_fsr.Close()
  1277.                                 iex $_def
  1278.                                 $_cmdlet = "_Dummy"
  1279.                             }
  1280.  
  1281.                             if ( ((gi "Function:$_cmdlet").Definition -replace '\n').Split("{")[0] -match 'param\((.*\))\s*[;\.&a-zA-Z]*\s*$' )
  1282.                             {
  1283.                                 $Matches[1].Split(',', "RemoveEmptyEntries" -as [System.StringSplitOptions]) -like "*$_param" |
  1284.                                 % { $_.Split("$ )`r`n", "RemoveEmptyEntries" -as [System.StringSplitOptions])[0] -replace '^\[(.*)\]$','$1' -as "System.Type" } |
  1285.                                 ? { $_.IsEnum } | % { [Enum]::GetNames($_) -like $_opt | sort } | % { $_base + $_ }
  1286.                             }
  1287.                             break;
  1288.                         }
  1289.  
  1290.                             select -InputObject $_cmdlet -ExpandProperty ParameterSets | select -ExpandProperty Parameters |
  1291.                             ? { $_.Name -like $_param } | ? { $_.ParameterType.IsEnum } |
  1292.                             % { [Enum]::GetNames($_.ParameterType) } | ? { $_ -like $_opt } | sort -Unique | % { $_base + $_ }
  1293.  
  1294.                         }
  1295.  
  1296.  
  1297.                                if ( $line[-1] -match "\s" ) { break; }
  1298.        
  1299.                                if ( $lastWord -ne $null -and $lastWord.IndexOfAny('/\') -eq -1 ) {
  1300.                                   $command = $lastWord.Substring( ($lastWord -replace '([^\|\(;={]*)$').Length )
  1301.                                   $_base = $lastWord.Substring( 0, ($lastWord -replace '([^\|\(;={]*)$').Length )
  1302.                                   $pattern = $command + "*"
  1303.                                   gcm -Name $pattern -CommandType All | % { $_base + $_.Name } | sort -Unique
  1304.                                }
  1305.                     }
  1306.                 }
  1307.             }
  1308.        
  1309. }

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