One of the features I'd like in PowerShell is the ability to tab-expand
standard aliases - e.g., when I have this
PS> gci<TAB>
get this:
PS> Get-ChildItem
There are several ways to do this; my personal quick-and-dirty approach is
outlined below. This is a static approach; I could make it more dynamic and
even faster by generating a lookup function on-the-fly (or periodically),
but this works well enough in general for my needs.
Step 1: Dump the standard TabExpansion function by redirecting to an
external script.
I did this by just redirecting to a separate script I use, named
Expand-Tab.ps1. To do this, I have the following line in my profile script:
function TabExpansion{param($line, $lastWord);Expand-Tab $line $lastWord}
Step 2: Custom script
The only other bit is using the following custom script.
#Expand-Tab.ps1
param($line, $lastWord)
& {
switch -regex ($lastWord)
{
'^[^\-\.]+$'
{
switch ($lastWord)
{
'ac' { 'Add-Content'; break;}
'clc' { 'Clear-Content'; break;}
'cli' { 'Clear-Item'; break;}
'clp' { 'Clear-ItemProperty'; break;}
'clv' { 'Clear-Variable'; break;}
'cpi' { 'Copy-Item'; break;}
'cpp' { 'Copy-ItemProperty'; break;}
'cvpa' { 'Convert-Path'; break;}
'epal' { 'Export-Alias'; break;}
'epcsv' { 'Export-Csv'; break;}
'fc' { 'Format-Custom'; break;}
'fl' { 'Format-List'; break;}
'foreach' { 'ForEach-Object'; break;}
'%' { 'ForEach-Object'; break;}
'ft' { 'Format-Table'; break;}
'fw' { 'Format-Wide'; break;}
'gal' { 'Get-Alias'; break;}
'gc' { 'Get-Content'; break;}
'gci' { 'Get-ChildItem'; break;}
'gcm' { 'Get-Command'; break;}
'gdr' { 'Get-PSDrive'; break;}
'ghy' { 'Get-History'; break;}
'gi' { 'Get-Item'; break;}
'gl' { 'Get-Location'; break;}
'gm' { 'Get-Member'; break;}
'gp' { 'Get-ItemProperty'; break;}
'gps' { 'Get-Process'; break;}
'group' { 'Group-Object'; break;}
'gsv' { 'Get-Service'; break;}
'gsnp' { 'Get-PSSnapin'; break;}
'gu' { 'Get-Unique'; break;}
'gv' { 'Get-Variable'; break;}
'gwmi' { 'Get-WmiObject'; break;}
'iex' { 'Invoke-Expression'; break;}
'ihy' { 'Invoke-History'; break;}
'ii' { 'Invoke-Item'; break;}
'ipal' { 'Import-Alias'; break;}
'ipcsv' { 'Import-Csv'; break;}
'mi' { 'Move-Item'; break;}
'mp' { 'Move-ItemProperty'; break;}
'nal' { 'New-Alias'; break;}
'ndr' { 'New-PSDrive'; break;}
'ni' { 'New-Item'; break;}
'nv' { 'New-Variable'; break;}
'oh' { 'Out-Host'; break;}
'rdr' { 'Remove-PSDrive'; break;}
'ri' { 'Remove-Item'; break;}
'rni' { 'Rename-Item'; break;}
'rnp' { 'Rename-ItemProperty'; break;}
'rp' { 'Remove-ItemProperty'; break;}
'rsnp' { 'Remove-PSSnapin'; break;}
'rv' { 'Remove-Variable'; break;}
'rvpa' { 'Resolve-Path'; break;}
'sal' { 'Set-Alias'; break;}
'sasv' { 'Start-Service'; break;}
'sc' { 'Set-Content'; break;}
'select' { 'Select-Object'; break;}
'si' { 'Set-Item'; break;}
'sl' { 'Set-Location'; break;}
'sleep' { 'Start-Sleep'; break;}
'sort' { 'Sort-Object'; break;}
'sp' { 'Set-ItemProperty'; break;}
'spps' { 'Stop-Process'; break;}
'spsv' { 'Stop-Service'; break;}
'sv' { 'Set-Variable'; break;}
'tee' { 'Tee-Object'; break;}
'where' { 'Where-Object'; break;}
'?' { 'Where-Object'; break;}
};
break;
}
###############
# Handle property and method expansion...
'(^.*)(\$(\w|\.)+)\.(\w*)$' {
$method = [Management.Automation.PSMemberTypes] `
'Method,CodeMethod,ScriptMethod,ParameterizedProperty'
$base = $matches[1]
$expression = $matches[2]
Invoke-Expression ('$val=' + $expression)
$pat = $matches[4] + '*'
Get-Member -inputobject $val $pat | sort membertype,name |
where { $_.name -notmatch '^[gs]et_'} |
foreach {
if ($_.MemberType -band $method)
{
# Return a method...
$base + $expression + '.' + $_.name + '('
}
else {
# Return a property...
$base + $expression + '.' + $_.name
}
}
break;
}
###############
###############
# Handle variable name expansion...
'(^.*\$)(\w+)$' {
$prefix = $matches[1]
$varName = $matches[2]
foreach ($v in Get-Childitem ('variable:' + $varName + '*'))
{
$prefix + $v.name
}
break;
}
###############
###############
# Do completion on parameters...
'^-([\w0-9]*)' {
$pat = $matches[1] + '*'
# extract the command name from the string
# first split the string into statements and pipeline elements
# This doesn't handle strings however.
$cmdlet = [regex]::Split($line, '[|;]')[-1]
# Extract the trailing unclosed block e.g. ls | foreach { cp
if ($cmdlet -match '\{([^\{\}]*)$')
{
$cmdlet = $matches[1]
}
# Extract the longest unclosed parenthetical expression...
if ($cmdlet -match '\(([^()]*)$')
{
$cmdlet = $matches[1]
}
# take the first space separated token of the remaining string
# as the command to look up. Trim any leading or trailing spaces
# so you don't get leading empty elements.
$cmdlet = $cmdlet.Trim().Split()[0]
# now get the info object for it...
$cmdlet = @(Get-Command -type 'cmdlet,alias' $cmdlet)[0]
# loop resolving aliases...
while ($cmdlet.CommandType -eq 'alias') {
$cmdlet = @(
Get-Command -type 'cmdlet,alias' $cmdlet.Definition)[0]
}
# expand the parameter sets and emit the matching elements
foreach ($n in $cmdlet.ParameterSets | Select-Object -expand
parameters)
{
$n = $n.name
if ($n -like $pat) { '-' + $n }
}
break;
}
###############
}
}


?
ath?