This blog has moved to http://ThePowerShellGuy.com
Greetings /\/\o\/\/
I realy added a lot on my TabCompletion :
this function realy makes PowerShell fly for me :
***
*Edit* I made beter version of this script on my new
blog : The PowerShell Guy ( http://ThePowerShellGuy.com )
As it comes with an installer its much more easy to
setup,
and it uses one database for all data, it works mostly the
same as this one
Just download the PowerTab.ZIP file from the overview page here :
http://thepowershellguy.com/blogs/posh/pages/powertab.aspx
run PowetTabSetup.Ps1 and you are ready to go
***
I will Post my current TabCompletion below, I contains a lot of additions I realy like and the GUI selecting of items in a list I think is handy also as
- GUI support
- WMI Support
- Alias Support
- Function Support
- History support
- () Support (Take Care as all will be executed on Tab)
- Custom additions
- Loading and saving of Configuration
Some of the additions in this version might be to specific, could be constructed better or are not consistent, but this version is my own current version as it has grown I and might need some cleaning up, but I posted this version for trying out and to tweak it to your need or to get some ideas and to get you started on Custom tab completion, or just use it as is .
As I think*Note* this script is also on Codeplex in : PowerShell Utility scipts as my last version this works as is.
For this version to work you need some preparement as it needs some utility scripts and a XML file to work, the code to make the XML file is needed only once, the loading of it needs to be done every time a new shell is started, so it is best placed in your profile: (for testing if you past in all of the codeblocks your also ready to go),
Utility Functions (to be called in profile)
# Custom Tab Completion Helper Functions
Function add-tabCompletion ([string]$filter,[string]$Text,[string]$type){
$global:dsTabCompletion.Tables['CustomTabExpansion'].Rows.Add($filter,$text,$type)
}
Function Save-tabCompletion {
$global:dsTabCompletion.WriteXml("$PSHome\TabCompletion.xml")
}
Function Load-tabCompletion {
$global:dsTabCompletion = new-object data.dataset
$global:dsTabCompletion.ReadXml("$PSHome\TabCompletion.xml")
}
Function Get-tabCompletion {
$global:dsTabCompletion.tables['CustomTabExpansion']
}
Function New-tabCompletion {
$global:dsTabCompletion = new-object data.dataset
$global:dtCustomTabExpansion = new-Object data.datatable
[VOID]($global:dtCustomTabExpansion.Columns.add('Filter',[string]))
[VOID]($global:dtCustomTabExpansion.Columns.add('Text',[string]))
[VOID]($global:dtCustomTabExpansion.Columns.add('Type',[string]))
$global:dtCustomTabExpansion.tablename = 'CustomTabExpansion'
$global:dsTabCompletion.Tables.Add($global:dtCustomTabExpansion)
}
Function find-tabCompletion ([string]$filter) {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("filter like '$filter'") % {$_}
}
Function Refresh-TabCompletionAlias {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("Type = 'Alias'") % {$global:dsTabCompletion.Tables['CustomTabExpansion'].rows.remove($_)}
Get-Alias % {add-tabCompletion $_.name $_.Definition 'Alias'}
}
Function Refresh-TabCompletionFunction {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("Type = 'Function'") % {$global:dsTabCompletion.Tables['CustomTabExpansion'].rows.remove($_)}
Get-Command -commandType "Function"% {add-tabCompletion $_.name $_.name $_.CommandType}
}
Then you need to build the Tab Completion DataBase for first use.
Build XML file (one time only needed)
# Create Initial Tab-Completion DataBase
New-tabCompletion
Get-Alias % {add-tabCompletion $_.name $_.Definition 'Alias'}
Get-Command -commandType "Function, Filter, Cmdlet"% {add-tabCompletion $_.name $_.name $_.CommandType}
add-tabCompletion '%' ' foreach-object {}' 'Custom'
add-tabCompletion '?' ' Where-object {}' 'Custom'
Save-tabCompletion
Load-tabCompletion
as you can see here, after we did initial fill it we can use the functions to customize it and then save it again,.I also added 2 functions to update the Alias and Function list.
Also as te Tabcompletion function uses a GUI you need to load this help function also :
Out-DataGridView needed loaded for tabcompletion (profile)
*edit* needed formas library :
[void][System.Reflection.Assembly]::LoadWithPartialName("System.windows.forms")
# Function out-datagridView
#
# shows piplineinput in a GUI using a datagridView
# and returns the given field on double-Click or Enter
#
# /\/\o\/\/ 2006
# http:mow001.blogspot.com
Function out-dataGridView ([String]$ReturnField){
# Make DataTable from Input
$dt = new Data.datatable
$First = $true
foreach ($item in $input){
$DR = $DT.NewRow()
$Item.PsObject.get_properties() foreach {
If ($first) {
$Col = new-object Data.DataColumn
$Col.ColumnName = $_.Name.ToString()
$DT.Columns.Add($Col) }
if ($_.value -eq $null) {
$DR.Item($_.Name) = "[empty]"
}
ElseIf ($_.IsArray) {
$DR.Item($_.Name) =[string]::Join($_.value ,";")
}
Else {
$DR.Item($_.Name) = $_.value
}
}
$DT.Rows.Add($DR)
$First = $false
}
# show Datatable in Form
$form = new-object Windows.Forms.form
$form.Size = new-object System.Drawing.Size @(1000,600)
$DG = new-object windows.forms.DataGridView
$DG.DataSource = $DT.psObject.baseobject
$DG.Dock = [System.Windows.Forms.DockStyle]::Fill
$dg.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::AutoSize
$dg.SelectionMode = 'FullRowSelect'
$dg.add_DoubleClick({
$script:ret = $this.SelectedRows % {$_.DataboundItem["$ReturnField"]}
$form.Close()
})
$form.text = "$($myinvocation.line)"
$form.KeyPreview = $true
$form.Add_KeyDown({
if ($_.KeyCode -eq 'Enter') {
$script:ret = $DG.SelectedRows % {$_.DataboundItem["$ReturnField"]}
$form.Close()
}
ElseIf ($_.KeyCode -eq 'Escape'){
$form.Close()
}
})
$form.Controls.Add($DG)
$Form.Add_Shown({$form.Activate();$dg.AutoResizeColumns()})
$script:ret = $null
[void]$form.showdialog()
$script:ret
}
And after that ofcourse load the TabCompletion replacement :
TabCompletion Function (load in profile)# TabExpansion.ps1
# RC2 Version 0.5
# Replacement of default TabExpansion function
# /\/\o\/\/ 2006
# www.ThePowerShellGuy.com
#$global:dtAssemblies = $null
#$global:dtWmiClasses = $null
function TabExpansion {
# This is the default function that gets called for tab expansion.
# Edited by /\/\o\/\/ from the original to handle :
# - Cached tab completion on types (janel / mow).
# - Methods and properties of types
# - shows get_ methods
# - MultiLevel variable Tab Completion
# - Bracet Removal
# Edited by DBMwS: Added Progressbar and Scoped variable name expansion
# /\/\o\/\/ added WMI Tab completion win32_[tab]/cim_[tab]/msft_[tab]
# expansion on aliases / custom aliases
# simple () expansion
# history expansion
# GUI Expansion
param($line, $lastWord)
$_Method = [Management.Automation.PSMemberTypes] 'Method,CodeMethod,ScriptMethod,ParameterizedProperty'
$_ScopeNames = @("global", "local", "script", "private")
switch -regex ($line) {
# Handle property and method expansion on simple () blocks( added /\/\o\/\/)...
'^\((.+)\)\.(.*)' {
$val = "($($matches[1]))"
invoke-expression "Get-Member -inputobject $val" ? {$_.name -like "$($matches[2])*"} foreach {
if ($_.MemberType -band $_method)
{
# Return a method...
$lastword.Substring(0,$lastword.LastIndexOf('.')) + '.' + $_.name + '('
}
else {
# Return a property...
$lastword.Substring(0,$lastword.LastIndexOf('.')) + '.' + $_.name
}
}
break;
}
}
switch -regex ($lastWord) {
# GUI Shortcuts
'w_(.*)' {$global:dtWmiClasses.Select("name like 'win32_$($matches[1])%'","name") out-dataGridView name}
'A_(.*)' {$global:dtAssemblies.Select("name like '%$($matches[1])%'","name") out-dataGridView name}
'f_' {ls function: select name out-dataGridView name}
'd_' {ls select Mode,LastWriteTime,Length,Name,fullname out-dataGridView fullname}
'e_' {"@{e={};Name=}"}
'h_(.*)' {Get-History -count 900 ? {$_.CommandLine -like "$($matches[1])*"} foreach-object {$_.CommandLine}}
'g_' {Get-History -Count 100 out-dataGridView Commandline}
'c_(.*)' {$global:dsTabCompletion.Tables['CustomTabExpansion'].select("filter like '$($matches[1])%'","text") out-dataGridView text}
# WMI completion
'(win32_.*cim_.*MSFT_.*)' {
# First time fill list
if (!($global:dtWmiClasses)) {
$global:dtWmiClasses = new data.datatable
[VOID]($global:dtWmiClasses.Columns.add('name',[string]))
[VOID]($global:dtWmiClasses.Columns.add('Description',[string]))
$WmiClass = [WmiClass]''
# Set Enumeration Options
$opt = new-object system.management.EnumerationOptions
$opt.EnumerateDeep = $True
$opt.UseAmendedQualifiers = $true
$i = 0 ; write-progress "Adding WMI Classes" "$i"
$WmiClass.psBase.GetSubclasses($opt) foreach {
$i++ ; if ($i%10 -eq 0) {write-progress "Adding WMI Classes" "$i"}
[void]$global:dtWmiClasses.rows.add($_.name,($_.psbase.Qualifiers ? {$_.Name -eq 'description'} % {$_.Value}))
}
write-progress "Adding WMI Classes" "$i" -Completed
}
$global:dtWmiClasses.select("name like '$($matches[1])%'") % {$_.name}
break;
}
# Handle property and method expansion on simple () blocks( added /\/\o\/\/)...
'^\((.+)\)\.(.*)' {
$val = "($($matches[1]))"
invoke-expression "Get-Member -inputobject $val" ? {$_.name -like "$($matches[2])*"} foreach {
if ($_.MemberType -band $_method)
{
# Return a method...
$val + '.' + $_.name + '('
}
else {
# Return a property...
$val + '.' + $_.name
}
}
break;
}
# Handle property and method expansion (MultiLevel added /\/\o\/\/)...
'\$(.+)\.(.*)' {
$variableName = $matches[1]
$val = '$' + $matches[1]
$level = $matches[2].split('.').count
if ($level -gt 1) {
$ofs = '.';$val = '$' + $variableName + ".$($matches[2].split('.')[0..($level -2)])"
}
$pat = $matches[2].split('.')[($level -1)] + '*'
# /\/\o\/\/ removed : -and $n -notmatch '^[ge]et_'
# to get get_ methods on WMI and AD objects
invoke-expression "Get-Member -inputobject $val" where {$n = $_.name; $n -like $pat } foreach {
if ($_.MemberType -band $_method)
{
# Return a method...
$val + '.' + $_.name + '('
}
else {
# Return a property...
$val + '.' + $_.name
}
}
break;
}
# Remove Brackets from typename (/\/\o\/\/)
'(\[.*\])=(\w*)' {
"new-Object $($matches[1].replace('[','').replace(']',''))"
break;
}
# Handle Static methods of Types (/\/\o\/\/)..
'(\[.*\])::(\w*)' {
invoke-expression "$($matches[1]) gm -static" where {$_.name -like "$($matches[2])*"} % {
if ($_.MemberType -band $_Method) {
"$($matches[1])::$($_.name)" + '('
} Else {
"$($matches[1])::$($_.name)"
}
}
break;
}
# Handle methods of Types (/\/\o\/\/)..
'^(\[.*\]).(\w*)' {
invoke-expression "$($matches[1]) gm" where {$_.name -like "$($matches[2])*"} % {
if ($_.MemberType -band $_Method) {
"$($matches[1]).$($_.name)" + '('
} Else {
"$($matches[1]).$($_.name)"
}
}
break;
}
# Cache and Handle namespace and TypeNames (/\/\o\/\/) ..
'^\[(.*)' {
$matched = $matches[1]
# only the first time Fill a DataTable with Typenames,namespaces and dotCount (level)
if (!($global:dtAssemblies)) {
$global:dtAssemblies = New-Object System.Data.Datatable
[VOID]($global:dtAssemblies.Columns.add('name',[string]))
[VOID]($global:dtAssemblies.Columns.add('DC',[int]))
[VOID]($global:dtAssemblies.Columns.add('NS',[string]))
$assemblies = [appdomain]::CurrentDomain.getassemblies()
[void] ($assemblies % {$i = 0} {
$i++;
[int]$assemblyProgress = ($i * 100) / $assemblies.Length
write-progress "Adding Assembly $($_.getName().name):" "$assemblyProgress" -perc $assemblyProgress
$types = $_.GetTypes() ? {$_.IsPublic -eq $true}
$types % {$j = 0} {
$j++;
if (($j % 200) -eq 0) {
[int]$typeProgress = ($j * 100) / $types.Length
write-progress "Adding types percent complete :" "$typeProgress" -perc $typeProgress -id 1
}
$dc = $_.fullName.split(".").count - 1
$ns = $_.namespace
$global:dtAssemblies.rows.add("$_",$dc,$ns)
}
# Stubs added
$dtAssemblies.rows.add('windows stub',2,'System.Windows')
write-progress "Adding types percent complete :" "100" -perc 100 -id 1
})
}
# actual tab completion
$dots = $matches[1].split(".").count - 1
switch ($dots) {
0 {"[System","[Microsoft","[IronPython"}
Default {
$res = @()
$res += $global:dtAssemblies.select("ns like '$($matched)%' and dc = $($dots + 1)")
select -uni ns % {"[$($_.ns)"};
$res += $global:dtAssemblies.select("name like '$($matched)%' and dc = $dots") % {"[$($_.name)]"}
$res
}
}
break;
}
# Handle expansions for both "Scope Variable Name" and "Type Variable Names" (DbmwS)
'(.*^\$)(\w+):(\w*)$' {
$type = $matches[2]; # function, variable, etc.. that are not scopes
$prefix = $matches[1] + $type; # $ + function
$typeName = $matches[3]; # e.g. in '$function:C', value will be 'C'
if ($_ScopeNames -contains $type) {
# Scope Variable Name Expansion
foreach ($scopeVariable in
(Get-Variable "$($typeName)*" -Scope $type Sort-Object name)) {
$prefix + ":" + $scopeVariable.Name
}
} else {
# Type name expansion($function:, $variable, $env: ,etc)
foreach ($t in (Get-ChildItem ($type + ":" + $typeName + '*') Sort-Object name)) {
$prefix + ":" + $t.Name
}
}
break;
}
# Handle variable name expansion (original)...
'(.*^\$)(\w+)$' {
$prefix = $matches[1]
$varName = $matches[2]
foreach ($v in Get-Childitem ('variable:' + $varName + '*')) {
$prefix + $v.name
}
break;
}
# Do completion on parameters (original) ...
'^-([\w0-9]*)' {
$pat = $matches[1] + '*'
# extract the command name from the string
# first split the string into statements and pipeline elements
# This doesnt handle strings however.
$cmdlet = [regex]::Split($line, '[;]')[-1]
# Extract the trailing unclosed block
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 dont 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;
}
# Custom additions
'(.*)' {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("filter like '$($matches[1])'") % {$_.text} # AND type = 'Alias'"
}
'(.*)%' {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("filter like '$($matches[1])%'","text") % {$_.text}
}
'(.*-.*)' {
$global:dsTabCompletion.Tables['CustomTabExpansion'].select("filter like '$($matches[1])%'","text") % {$_.text}
}
} # EO switch
}
now you are free to edit your tabcompletion
try this now
# Alias
PoSH> gwmi[tab]
PoSH> Get-WmiObject win32_sh[tab]
Posh> Get-WmiObject Win32_Share
# Function + CmdLet (on -)
PoSH> get-t[tab]
PoSH>Get-tabCompletion
# Function + CmdLet (on %)
PoSH>ref%[tab]
PoSH>Refresh-TabCompletionAlias
# GUI tabcompletion :
PoSH>w_sh[tab]
PoSH>f_[tab]
PoSH>w_ [tab]
# Custom
PoSH>ls %[tab]
PoSH>ls foreach-object {}
# () resolving
PoSH>(LS).[tab]
PoSH>(gwmi win32_share).[tab]
Enjoy,
Greetings, /\/\o\/\/
Tags : Monad PowerShell