├── .gitignore ├── test.bat ├── Modules ├── PsGet │ └── PsGet.psm1 ├── PowerTab │ ├── Shares.dll │ ├── Lerch.PowerShell.dll │ ├── Lib │ │ ├── NetworkShares_src.zip │ │ └── Lerch.PowerShell_src.zip │ ├── TabExpansion.ps1 │ ├── ColorThemes │ │ ├── ThemeBlue.csv │ │ ├── ThemeWhite.csv │ │ ├── ThemeDigital.csv │ │ ├── ThemeAdmin.csv │ │ ├── ThemeHotdogStand.csv │ │ ├── ThemeGreenBs.csv │ │ ├── ThemeGray.csv │ │ ├── ThemeDragon.csv │ │ ├── ThemeGreen.csv │ │ ├── ThemeOriginal.csv │ │ ├── ThemeSpace.csv │ │ ├── ThemeBlog.csv │ │ └── ThemeSimpleWhite.csv │ ├── ControlCharacters.txt │ ├── TabExpansionCustomLib.ps1 │ ├── PowerTab.psd1 │ ├── Handlers │ │ ├── PSClientManager.ps1 │ │ ├── Utilities.ps1 │ │ └── Robocopy.ps1 │ ├── about_PowerTab.help.txt │ ├── about_PowerTab_context.help.txt │ ├── en │ │ └── Resources.psd1 │ ├── en-US │ │ └── Resources.psd1 │ ├── about_PowerTab_usage.help.txt │ ├── TabExpansionCore-Help.xml │ ├── about_PowerTab_handlers.help.txt │ ├── TabExpansionResources.ps1 │ ├── PowerTab.psm1 │ ├── TabExpansionUtil.ps1 │ ├── ConsoleLib.ps1 │ └── TabExpansionCore.ps1 ├── ScriptBrowser │ ├── ScriptBrowser.psd1 │ ├── en-US │ │ └── ScriptBrowser.psd1 │ └── ScriptBrowser.psm1 ├── Aliases │ └── Aliases.psm1 ├── SyncMeUp │ └── SyncMeUp.psm1 └── PsUrl │ └── PsUrl.psm1 ├── .gitmodules ├── appveyor.yml ├── Microsoft.PowerShellISE_profile.ps1 ├── test.ps1 ├── README.md ├── Tests ├── Is-VCSRoot.Tests.ps1 ├── PathBuilding.Tests.ps1 └── Get-VcsStatus.Tests.ps1 ├── PowerTabConfig.xml └── Microsoft.PowerShell_profile.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | Modules/Work 2 | Scripts 3 | -------------------------------------------------------------------------------- /test.bat: -------------------------------------------------------------------------------- 1 | @Powershell -NonInteractive -NoProfile -ExecutionPolicy Bypass -File ".\test.ps1" 2 | -------------------------------------------------------------------------------- /Modules/PsGet/PsGet.psm1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/PsGet/PsGet.psm1 -------------------------------------------------------------------------------- /Modules/PowerTab/Shares.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/PowerTab/Shares.dll -------------------------------------------------------------------------------- /Modules/PowerTab/Lerch.PowerShell.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/PowerTab/Lerch.PowerShell.dll -------------------------------------------------------------------------------- /Modules/ScriptBrowser/ScriptBrowser.psd1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/ScriptBrowser/ScriptBrowser.psd1 -------------------------------------------------------------------------------- /Modules/PowerTab/Lib/NetworkShares_src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/PowerTab/Lib/NetworkShares_src.zip -------------------------------------------------------------------------------- /Modules/PowerTab/Lib/Lerch.PowerShell_src.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chrisbenti/PS-Config/HEAD/Modules/PowerTab/Lib/Lerch.PowerShell_src.zip -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansion.ps1: -------------------------------------------------------------------------------- 1 | 2 | Function global:TabExpansion { 3 | param($Line, $LastWord) 4 | 5 | Invoke-TabExpansion -Line $Line -LastWord $LastWord 6 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Modules/posh-git"] 2 | path = Modules/posh-git 3 | url = https://github.com/dahlbyk/posh-git.git 4 | [submodule "Modules/Pester"] 5 | path = Modules/Pester 6 | url = https://github.com/pester/Pester.git 7 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeBlue.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,Gray 3 | BorderBackColor,DarkBlue 4 | BorderColor,Blue 5 | BorderTextColor,Cyan 6 | FilterColor,yellow 7 | SelectedBackColor,Green 8 | SelectedTextColor,Blue 9 | TextColor,Blue -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeWhite.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,white 3 | BorderBackColor,white 4 | BorderColor,Black 5 | BorderTextColor,Black 6 | FilterColor,Gray 7 | SelectedBackColor,Blue 8 | SelectedTextColor,white 9 | TextColor,Black -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeDigital.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,Black 3 | BorderBackColor,Black 4 | BorderColor,Green 5 | BorderTextColor,Green 6 | FilterColor,Gray 7 | SelectedBackColor,Red 8 | SelectedTextColor,Black 9 | TextColor,Green -------------------------------------------------------------------------------- /Modules/ScriptBrowser/en-US/ScriptBrowser.psd1: -------------------------------------------------------------------------------- 1 | ConvertFrom-StringData @' 2 | # English strings 3 | MissingRegValue = Cannot get install directory from registry. 4 | RequiresISE = {0} is only available in Windows PowerShell ISE console pane. 5 | '@ -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeAdmin.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,DarkRed 3 | BorderBackColor,DarkRed 4 | BorderColor,Black 5 | BorderTextColor,Yellow 6 | FilterColor,Gray 7 | SelectedBackColor,Yellow 8 | SelectedTextColor,black 9 | TextColor,Green -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeHotdogStand.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,DarkRed 3 | BorderBackColor,Yellow 4 | BorderColor,Red 5 | BorderTextColor,Black 6 | FilterColor,red 7 | SelectedBackColor,yellow 8 | SelectedTextColor,Red 9 | TextColor,Yellow -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeGreenBs.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,Black 3 | BorderBackColor,Black 4 | BorderColor,Green 5 | BorderTextColor,Green 6 | FilterColor,Gray 7 | SelectedBackColor,DarkGreen 8 | SelectedTextColor,Green 9 | TextColor,DarkGreen -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeGray.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,Black 3 | BorderBackColor,DarkGray 4 | BorderColor,Gray 5 | BorderTextColor,Black 6 | FilterColor,Gray 7 | SelectedBackColor,DarkGray 8 | SelectedTextColor,White 9 | TextColor,Gray 10 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeDragon.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,DarkRed 3 | BorderBackColor,Red 4 | BorderColor,Green 5 | BorderTextColor,Yellow 6 | FilterColor,Gray 7 | SelectedBackColor,DarkGreen 8 | SelectedTextColor,Yellow 9 | TextColor,Green 10 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeGreen.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,Black 3 | BorderBackColor,Black 4 | BorderColor,Green 5 | BorderTextColor,Green 6 | FilterColor,Gray 7 | SelectedBackColor,DarkGreen 8 | SelectedTextColor,Green 9 | TextColor,DarkGreen 10 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeOriginal.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,DarkGray 3 | BorderBackColor,DarkBlue 4 | BorderColor,Blue 5 | BorderTextColor,Yellow 6 | FilterColor,Gray 7 | SelectedBackColor,DarkRed 8 | SelectedTextColor,Red 9 | TextColor,Yellow 10 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeSpace.csv: -------------------------------------------------------------------------------- 1 | Name,Color 2 | BackColor,DarkRed 3 | BorderBackColor,DarkBlue 4 | BorderColor,Blue 5 | BorderTextColor,Yellow 6 | FilterColor,DarkGray 7 | SelectedBackColor,DarkRed 8 | SelectedTextColor,Red 9 | TextColor,Yellow 10 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeBlog.csv: -------------------------------------------------------------------------------- 1 | #TYPE System.Management.Automation.PSCustomObject 2 | Name,Color 3 | BackColor,White 4 | BorderBackColor,Blue 5 | BorderColor,White 6 | BorderTextColor,Cyan 7 | FilterColor,Cyan 8 | SelectedBackColor,Cyan 9 | SelectedTextColor,Blue 10 | TextColor,Black 11 | -------------------------------------------------------------------------------- /Modules/PowerTab/ColorThemes/ThemeSimpleWhite.csv: -------------------------------------------------------------------------------- 1 | #TYPE System.Management.Automation.PSCustomObject 2 | Name,Color 3 | BackColor,Black 4 | BorderBackColor,Black 5 | BorderColor,White 6 | BorderTextColor,White 7 | FilterColor,Gray 8 | SelectedBackColor,Gray 9 | SelectedTextColor,Black 10 | TextColor,White 11 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | build: off 2 | 3 | install: 4 | - ps: (new-object Net.WebClient).DownloadString("http://psget.net/GetPsGet.ps1") | iex 5 | - ps: install-module pester 6 | - ps: $env:PSModulePath += ";c:\projects\ps-config\Modules\" 7 | 8 | test_script: 9 | - ps: (get-psprovider 'FileSystem').Home = "c:\User\" 10 | - ps: $PROFILE = "c:\projects\ps-config\Microsoft.PowerShell_profile.ps1" 11 | - ps: .\test.ps1 12 | -------------------------------------------------------------------------------- /Microsoft.PowerShellISE_profile.ps1: -------------------------------------------------------------------------------- 1 | 2 | 3 | #Script Browser Begin 4 | #Version: 1.3.1 5 | Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\System.Windows.Interactivity.dll' 6 | Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\ScriptBrowser.dll' 7 | Add-Type -Path 'C:\Program Files (x86)\Microsoft Corporation\Microsoft Script Browser\BestPractices.dll' 8 | $scriptBrowser = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Browser', [ScriptExplorer.Views.MainView], $true) 9 | $scriptAnalyzer = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Analyzer', [BestPractices.Views.BestPracticesView], $true) 10 | $psISE.CurrentPowerShellTab.VisibleVerticalAddOnTools.SelectedAddOnTool = $scriptBrowser 11 | #Script Browser End 12 | -------------------------------------------------------------------------------- /test.ps1: -------------------------------------------------------------------------------- 1 | trap #trap exceptions and force failure 2 | { 3 | write-output $_ 4 | exit 1 5 | } 6 | 7 | Import-Module Pester 8 | Set-StrictMode -Version Latest 9 | Import-Module agent-api -ErrorAction SilentlyContinue 10 | 11 | $Results = Invoke-Pester -PassThru .\Tests 12 | if (Get-Command "Add-AppveyorTest" -ErrorAction SilentlyContinue) { 13 | $failures = 0; 14 | foreach($test in $Results.TestResult) { 15 | $outcome = "Failed"; 16 | if ($test.Passed) { 17 | $outcome = "Passed"; 18 | } else { 19 | $failures++; 20 | } 21 | 22 | Add-AppveyorTest -Name $test.Name -Outcome $outcome -Duration $test.Time.TotalMilliseconds -ErrorMessage $test.FailureMessage -ErrorStackTrace $test.StackTrace 23 | } 24 | exit $failures; 25 | } else {} -------------------------------------------------------------------------------- /Modules/PowerTab/ControlCharacters.txt: -------------------------------------------------------------------------------- 1 | ^@ 0 NUL 2 | ^A 1 YES 3 | ^B 2 YES 4 | ^C 3 YES Copy 5 | ^D 4 YES 6 | ^E 5 YES 7 | ^F 6 YES 8 | ^G 7 BEL YES Alarm, avoid 9 | ^H 8 BS NO 10 | ^I 9 TAB NO 11 | ^J 10 LF NOT Adds a return without submitting command, but breaks backspacing 12 | ^K 11 VT YES 13 | ^L 12 FF YES 14 | ^M 13 CR NO 15 | ^N 14 YES 16 | ^O 15 YES 17 | ^P 16 YES 18 | ^Q 17 YES 19 | ^R 18 YES 20 | ^S 19 NOT 21 | ^T 20 NOT 22 | ^U 21 YES 23 | ^V 22 YES Paste 24 | ^W 23 YES 25 | ^X 24 YES Cut 26 | ^Y 25 YES 27 | ^Z 26 YES Cut word? 28 | ^[ 27 ESC YES 29 | ^\ 28 FS YES 30 | ^] 29 GS YES 31 | ^^ 30 RS YES 32 | ^_ 31 US YES -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansionCustomLib.ps1: -------------------------------------------------------------------------------- 1 | 2 | # Add Enum Functions 3 | [Void](Add-TabExpansion '|%' '| foreach {$_}' 'Alias') 4 | [Void](Add-TabExpansion '|?' '| where {$_}' 'Alias') 5 | [Void](Add-TabExpansion 'tqb' 'The quick brown fox jumps over the lazy dog') 6 | [Void](Add-TabExpansion 'Localhost' 'Localhost' 'Computer') 7 | 8 | # Help Shortcuts 9 | [Void](Add-TabExpansion 'h' 'Get-help $^ -Full') 10 | [Void](Add-TabExpansion 'h' 'Get-help $^ -Detailed') 11 | [Void](Add-TabExpansion 'h' 'Get-help $^ -Examples') 12 | 13 | # Font Selection 14 | #[Void]((New-Object System.Drawing.Text.InstalledFontCollection).Families | ForEach-Object { Add-TabExpansion 'FontFamily' $_.name }) 15 | 16 | # Invoke ShortCuts 17 | [Void](Add-TabExpansion 'now' 'Get-Date' 'Invoke') 18 | [Void](Add-TabExpansion 'date' 'Get-Date -date' 'Invoke') 19 | [Void](Add-TabExpansion 'time' 'Get-Date -time' 'Invoke') -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [*ps-config*](http://chrisbenti.github.io/PS-Config/) # 2 | [![Build status](https://ci.appveyor.com/api/projects/status/qvo0c6326965hv5m)](https://ci.appveyor.com/project/chrisbenti/ps-config) 3 | ## Screenshot ## 4 | ![Picture of my current console look and feel](http://i.imgur.com/YuyiD0M.png) 5 | 6 | ## Installation ## 7 | One Liner (run this in powershell as the current user context): 8 | ``` 9 | pushd "$env:USERPROFILE\Documents"; git clone --recursive https://github.com/chrisbenti/ps-config.git WindowsPowerShell; . $PROFILE; popd 10 | ``` 11 | 12 | You will also need ConEmu with one of the patched fonts 13 | 14 | ## Testing 15 | Testing is done with the [Pester](https://github.com/pester/Pester) framework. 16 | 17 | To execute tests, run "test.bat" from your profile root. 18 | 19 | ## Inspiration and Resources ## 20 | - [Oh-My-ZSH Theme](https://gist.github.com/agnoster/3712874) 21 | - [Patched Fonts](https://gist.github.com/qrush/1595572) 22 | -------------------------------------------------------------------------------- /Modules/PowerTab/PowerTab.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ## Module Info 3 | ModuleVersion = '0.99.6.0' 4 | Description = 'PowerTab Module' 5 | GUID = '64c85865-df87-4bd6-bccd-ea294dc335b3' 6 | 7 | ## Module Components 8 | ScriptsToProcess = @() 9 | ModuleToProcess = @("PowerTab.psm1") 10 | TypesToProcess = @() 11 | FormatsToProcess = @() 12 | ModuleList = @("PowerTab.psm1") 13 | FileList = @() 14 | 15 | ## Public Interface 16 | CmdletsToExport = '' 17 | FunctionsToExport = @('*-*') 18 | VariablesToExport = @('PowerTabConfig','PowerTabError') 19 | AliasesToExport = '*' 20 | 21 | ## Requirements 22 | PowerShellVersion = '2.0' 23 | PowerShellHostName = '' 24 | PowerShellHostVersion = '' 25 | RequiredModules = @() 26 | RequiredAssemblies = @() 27 | ProcessorArchitecture = 'None' 28 | DotNetFrameworkVersion = '2.0' 29 | CLRVersion = '2.0' 30 | 31 | ## Author 32 | Author = 'Marc "/\/\o\/\/" van Orsouw, Jason Archer' 33 | CompanyName = '' 34 | Copyright = '' 35 | 36 | ## Private Data 37 | PrivateData = '' 38 | } 39 | -------------------------------------------------------------------------------- /Modules/Aliases/Aliases.psm1: -------------------------------------------------------------------------------- 1 | 2 | 3 | function sudo 4 | { 5 | $file, [string]$arguments = $args; 6 | $psi = new-object System.Diagnostics.ProcessStartInfo $file; 7 | $psi.Arguments = $arguments; 8 | $psi.Verb = "runas"; 9 | $psi.WorkingDirectory = get-location; 10 | [System.Diagnostics.Process]::Start($psi); 11 | } 12 | 13 | 14 | function .. {cd ..} 15 | 16 | function psc {set-location "c:$($env:HOMEPATH)\Documents\WindowsPowershell"} 17 | function cec {set-location "c:$($env:HOMEPATH)\Documents\ConEmu"} 18 | 19 | function gst {git status} 20 | 21 | function cl {chocolatey version all -lo} 22 | 23 | function which($name){ 24 | Get-Command $name | Select-Object -ExpandProperty Definition 25 | } 26 | 27 | function ~ { cd ~ } 28 | 29 | function Get-ColorPairs { 30 | param( 31 | [string]$foreground="*", 32 | [string]$background="*" 33 | ) 34 | $colors = [ConsoleColor].DeclaredMembers | Where {$_.Name -ne "value__" } 35 | 36 | $fg = $colors | ? { $_.Name -like $foreground } 37 | $bg = $colors | ? { $_.Name -like $background } 38 | 39 | $fg | % { 40 | $a = $_.Name 41 | $bg | % { 42 | $b = $_.Name 43 | Write-Host " FG: $a | BG: $b " -f $a -b $b 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /Modules/PowerTab/Handlers/PSClientManager.ps1: -------------------------------------------------------------------------------- 1 | ## PSClientManager 2 | 3 | $ClientFeatureHandler = { 4 | param($Context, [ref]$TabExpansionHasOutput) 5 | $Argument = $Context.Argument 6 | switch -exact ($Context.Parameter) { 7 | 'Name' { 8 | $TabExpansionHasOutput.Value = $true 9 | Get-ClientFeature "$Argument*" | Select-Object -ExpandProperty Name | Sort-Object 10 | } 11 | } 12 | } 13 | $AddClientFeatureHandler = { 14 | param($Context, [ref]$TabExpansionHasOutput) 15 | $Argument = $Context.Argument 16 | switch -exact ($Context.Parameter) { 17 | 'Name' { 18 | $TabExpansionHasOutput.Value = $true 19 | Get-ClientFeature "$Argument*" | Where-Object {$_.State -eq "Disabled"} | Select-Object -ExpandProperty Name | Sort-Object 20 | } 21 | } 22 | } 23 | $RemoveClientFeatureHandler = { 24 | param($Context, [ref]$TabExpansionHasOutput) 25 | $Argument = $Context.Argument 26 | switch -exact ($Context.Parameter) { 27 | 'Name' { 28 | $TabExpansionHasOutput.Value = $true 29 | Get-ClientFeature "$Argument*" | Where-Object {$_.State -eq "Enabled"} | Select-Object -ExpandProperty Name | Sort-Object 30 | } 31 | } 32 | } 33 | 34 | Register-TabExpansion "Add-ClientFeature" $AddClientFeatureHandler -Type "Command" 35 | Register-TabExpansion "Get-ClientFeature" $ClientFeatureHandler -Type "Command" 36 | Register-TabExpansion "Get-ClientFeatureInfo" $ClientFeatureHandler -Type "Command" 37 | Register-TabExpansion "Remove-ClientFeature" $RemoveClientFeatureHandler -Type "Command" 38 | -------------------------------------------------------------------------------- /Modules/SyncMeUp/SyncMeUp.psm1: -------------------------------------------------------------------------------- 1 | function reload{ 2 | (Get-Location).Path > ~\.last 3 | $process = get-process | ?{$_.ID -eq $pid} 4 | if($process.MainWindowTitle.Equals("")){ 5 | # Console 6 | start "C:\Program Files\ConEmu\ConEmu64.exe" "-LoadCfgFile $($env:USERPROFILE)\Documents\ConEmu\ConEmu.xml" 7 | } else { 8 | # Powershell 9 | start "powershell.exe" 10 | } 11 | $process | kill -Force 12 | 13 | } 14 | 15 | function refresh{ 16 | . $PROFILE 17 | } 18 | 19 | function sync{ 20 | $Start = Get-Location 21 | $PowerShellConfig = "c:$($env:HOMEPATH)\Documents\WindowsPowershell" 22 | 23 | $Reload = $False 24 | 25 | $LookAt = ( 26 | ("Powershell Configuration", $PowerShellConfig) 27 | ) 28 | 29 | 30 | $LookAt | % { 31 | Set-Location $_[1] 32 | $status = (gst)[-1] 33 | $pull = "" 34 | if($status.Contains("working directory clean")){ 35 | Write-Host "No changes to: $($_[0])" -f Green 36 | $pull = (git pull) 37 | } else { 38 | Write-Host "Syncing: $($_[0])" -f Red 39 | git add -u 40 | git add . 41 | Write-Host "Diff Message: " -f Blue 42 | git diff 43 | git commit -m (Read-Host -Prompt "Commit Message") 44 | $pull = (git pull) 45 | git push 46 | } 47 | 48 | if (!$pull[0].GetType().Equals([System.Char]) -and $pull[0].Contains("Updating")){ 49 | $Reload = $True 50 | } 51 | } 52 | 53 | Set-Location $Start 54 | Write-Host "All Synced!" -f Green 55 | if ($Reload) {reload} 56 | } -------------------------------------------------------------------------------- /Tests/Is-VCSRoot.Tests.ps1: -------------------------------------------------------------------------------- 1 | $ROOT = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | . "$ROOT\..\Microsoft.PowerShell_profile.ps1" 3 | 4 | 5 | Describe "Version control repositories" { 6 | Context "whose root directories" { 7 | $rootdir = "C:/Temp/Is-Vcs/Test" 8 | 9 | It "Is-VCSRoot returns true at the root of a git repository" { 10 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 11 | $dir = "$rootdir/.git"; 12 | mkdir $dir -force 13 | 14 | Is-VCSRoot (Get-Item $rootdir) | Should be $true 15 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 16 | } 17 | 18 | It "Is-VCSRoot returns true at the root of a hg repository" { 19 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 20 | $dir = "$rootdir/.hg"; 21 | mkdir $dir -force 22 | 23 | Is-VCSRoot (Get-Item $rootdir) | Should be $true 24 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 25 | } 26 | 27 | It "Is-VCSRoot returns true at the root of a svn repository" { 28 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 29 | $dir = "$rootdir/.svn"; 30 | mkdir $dir -force 31 | 32 | Is-VCSRoot (Get-Item $rootdir) | Should be $true 33 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 34 | } 35 | 36 | It "Is-VCSRoot returns not true when not at the root of a repository" { 37 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 38 | mkdir $rootdir -force 39 | 40 | Is-VCSRoot (Get-Item $rootdir) | Should not be $true 41 | rm $rootdir -recurse -force -ErrorAction SilentlyContinue 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /Tests/PathBuilding.Tests.ps1: -------------------------------------------------------------------------------- 1 | $ROOT = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | . "$ROOT\..\Microsoft.PowerShell_profile.ps1" 3 | 4 | Describe "Get-Provider" { 5 | if ($env:CI) { 6 | Mock Get-Home { return "c:/User/" } 7 | } 8 | 9 | Context "Determining the provider" { 10 | It "Should handle the FileSystem" { 11 | Get-Provider "C:\Windows\System32" | Should Be "FileSystem" 12 | } 13 | 14 | It "Should handle Cert:" { 15 | Get-Provider "Cert:\CurrentUser\CA" | Should Be "Certificate" 16 | } 17 | 18 | It "Should handle SMB shares" { 19 | Get-Provider "\\localhost\c$\Windows\System32" | Should Be "FileSystem" 20 | } 21 | 22 | It "Should handle the registry" { 23 | Get-Provider "HKLM:\SOFTWARE\Microsoft" | Should Be "Registry" 24 | } 25 | } 26 | } 27 | 28 | Describe "UNC Shares" { 29 | if ($env:CI) { 30 | Mock Get-Home { return "c:/User/" } 31 | } 32 | 33 | Context "When navigated to a UNC share" { 34 | It "Get-Drive returns the name of the share" { 35 | Get-Drive "Microsoft.PowerShell.Core\FileSystem::\\localhost\c$\Windows\System32" | Should be "\\localhost\c$\" 36 | Get-Drive "Microsoft.PowerShell.Core\FileSystem::\\localhost\c$" | Should be "\\localhost\c$\" 37 | } 38 | It "Shorten-Path returns all parts after the share name" { 39 | Shorten-Path "\\localhost\c$" | Should Be "" 40 | Shorten-Path "\\localhost\c$\Windows" | Should be "Windows" 41 | Shorten-Path "\\localhost\c$\Windows\System32" | Should be "Win\System32" 42 | } 43 | } 44 | } 45 | 46 | Describe "Drive Directories" { 47 | if ($env:CI) { 48 | Mock Get-Home { return "c:/User/" } 49 | } 50 | 51 | Context "When in the C:\Windows\system32 directory" { 52 | It "Get-Drive returns C:\" { 53 | Get-Drive "C:\Windows\System32" | Should be "C:\" 54 | } 55 | It "Shorten-Path returns all parts after the C:\" { 56 | Shorten-Path "C:\Windows\System32" | Should Be "Win\System32" 57 | } 58 | } 59 | } 60 | 61 | Describe "PowerShell non-FileSystem Providers" { 62 | if ($env:CI) { 63 | Mock Get-Home { return "c:/User/" } 64 | } 65 | 66 | Context "When in the cert provider"{ 67 | It "Get-Drive should return something" { 68 | Get-Drive "Cert:\CurrentUser\CA" | Should Be "Cert:\" 69 | } 70 | It "Shorten-Path should return the rest of the directory" { 71 | Shorten-Path "Cert:\CurrentUser\CA" | Should Be "CurrentUser\CA" 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /Modules/PowerTab/about_PowerTab.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_PowerTab 3 | 4 | SHORT DESCRIPTION 5 | PowerTab extends the tab expansion feature of PowerShell to offer more 6 | productivity for PowerShell users. 7 | 8 | LONG DESCRIPTION 9 | Tab expansion is a productivity feature of PowerShell similar to 10 | intellisense. Pressing the TAB key will cause PowerTab to suggest full 11 | paths, command names or values based on the current context of the cursor. 12 | 13 | PowerTab offers handling for many common features of PowerShell, such as 14 | parameter names or enum values. PowerTab also contains extension points 15 | for adding specialized tab expansion support for third party applications 16 | and commands. 17 | 18 | 19 | GETTING STARTED 20 | PowerTab is packaged as a PowerShell module and can simply be imported 21 | after being saved to one of the locations of modules in 22 | $env:PSModulePath. 23 | 24 | Import-Module PowerTab 25 | 26 | With no arguments, PowerTab will offer to run the setup wizard which will 27 | help setup a location to save the PowerTab config file. The config file 28 | is required to persist configuration settings for PowerTab, and cached 29 | values for .NET type, WMI class and computer name expansion. 30 | 31 | 32 | LOAD POWERTAB WITH AN EXISTING CONFIG 33 | To load an existing conifig file into PowerTab, pass in the full path to 34 | the config file as the first argument when importing the PowerTab module. 35 | 36 | $Path = "C:\Users\Bob\Documents\WindowsPowerShell\PowerTabConfig.xml" 37 | Import-Module PowerTab -ArgumentList $Path 38 | 39 | 40 | FEEDBACK 41 | Please submit suggestions, bug reports or questions to the PowerTab 42 | website. 43 | 44 | http://powertab.codeplex.com 45 | 46 | 47 | CREDITS 48 | This is a list of people and/or groups who have directly or indirectly 49 | helped by offering significant suggestions, code or linkable binaries. 50 | In no particular order: 51 | 52 | Marc "/\/\o\/\/" van Orsouw, MVP 53 | https://mvp.support.microsoft.com/profile/van%20Orsouw 54 | http://thepowershellguy.com/ 55 | 56 | Xaegr 57 | http://xaegr.livejournal.com/ 58 | 59 | Jacques 60 | http://janel.spaces.live.com/blog/ 61 | 62 | Igor Dvorkin 63 | 64 | Aaron Lerch / Invoke-Intellisense / Lerch.PowerShell.dll 65 | http://www.aaronlerch.com/ 66 | 67 | Richard Deeming / Shares.dll 68 | http://www.codeproject.com/KB/IP/networkshares.aspx 69 | 70 | Jason Archer 71 | 72 | 73 | SEE ALSO 74 | 75 | about_PowerTab_usage 76 | http://powertab.codeplex.com/documentation 77 | -------------------------------------------------------------------------------- /Modules/PowerTab/Handlers/Utilities.ps1: -------------------------------------------------------------------------------- 1 | 2 | ## netsh 3 | & { 4 | Register-TabExpansion netsh.exe -Type Command { 5 | param($Context, [ref]$TabExpansionHasOutput) 6 | $Argument = $Context.Argument 7 | switch -exact ($Context.Parameter) { 8 | 'r' { 9 | $TabExpansionHasOutput.Value = $true 10 | Get-TabExpansion "$Argument*" Computer | New-TabItem -Value {$_.Text} -Text {$_.Text} -Type Computer 11 | } 12 | } 13 | }.GetNewClosure() 14 | 15 | Function netshexeparameters { 16 | param( 17 | [String]$a 18 | , 19 | [ValidateSet("advfirewall","branchcache","bridge","dhcpclient","dnsclient","firewall","http","interface","ipsec", 20 | "lan","mbn","namespace","nap","netio","p2p","ras","rpc","trace","wcn","wfp","winhttp","winsock","wlan")] 21 | [String]$c 22 | , 23 | [String]$r 24 | , 25 | [String]$u 26 | , 27 | [String]$p 28 | , 29 | [String]$f 30 | , 31 | [Parameter(Position = 0, ValueFromRemainingArguments = $true)] 32 | [String[]]$Commands 33 | ) 34 | } 35 | 36 | ## TODO: Handle commands and contexts 37 | 38 | $netshCommandInfo = Get-Command netshexeparameters 39 | Register-TabExpansion netsh.exe -Type CommandInfo { 40 | param($Context) 41 | $netshCommandInfo 42 | }.GetNewClosure() 43 | 44 | Register-TabExpansion netsh.exe -Type ParameterName { 45 | param($Context, $Parameter) 46 | $Parameters = "-a","-c","-r","-u","-p","-f" 47 | $Parameters | Where-Object {$_ -like "$Parameter*"} 48 | }.GetNewClosure() 49 | } 50 | 51 | ## reg 52 | & { 53 | Register-TabExpansion reg.exe -Type Command { 54 | param($Context, [ref]$TabExpansionHasOutput) 55 | $Argument = $Context.Argument 56 | <# 57 | switch -exact ($Context.Parameter) { 58 | 'r' { 59 | $TabExpansionHasOutput.Value = $true 60 | Get-TabExpansion "$Argument*" Computer | New-TabItem {$_.Text} {$_.Text} -Type Computer 61 | } 62 | } 63 | #> 64 | }.GetNewClosure() 65 | 66 | Function regexeparameters { 67 | param( 68 | [Parameter(Position = 0)] 69 | [ValidateSet("QUERY","ADD","DELETE","COPY","SAVE","RESTORE","LOAD","UNLOAD","COMPARE","EXPORT","IMPORT","FLAGS")] 70 | [String]$Command 71 | ) 72 | } 73 | 74 | ## TODO: Handle options 75 | 76 | $regCommandInfo = Get-Command regexeparameters 77 | Register-TabExpansion reg.exe -Type CommandInfo { 78 | param($Context) 79 | $regCommandInfo 80 | }.GetNewClosure() 81 | } 82 | -------------------------------------------------------------------------------- /Modules/PowerTab/about_PowerTab_context.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_PowerTab_context 3 | 4 | SHORT DESCRIPTION 5 | Describes how PowerTab understands the context of a tab expansion request. 6 | 7 | LONG DESCRIPTION 8 | [Repurposing this topic.] 9 | 10 | 11 | CONTEXT OBJECT 12 | The context object represents PowerTab's understanding of the current 13 | command line. 14 | 15 | Line : 16 | The full command line. 17 | 18 | LastWord : 19 | The last word, subject of the tab expansion. 20 | 21 | LastToken : 22 | The last token parsed from the command line, may not be a token of 23 | the last word. 24 | 25 | Command : 26 | The name of the command that PowerTab has identified as being the 27 | current context (see isCommandMode). 28 | 29 | Parameter : 30 | The name of the parameter that PowerTab has identified as being the 31 | current context of the last word (see isParameterValue). 32 | 33 | Argument : 34 | The value entered so far for the parameter, typically this is the 35 | last word. 36 | 37 | PositionalParameter : 38 | 39 | 40 | PositionalParameters : 41 | 42 | 43 | OtherParameters : 44 | A collection of the other identified parameters to the current 45 | command and their values, from the command line. 46 | 47 | isCommandMode : 48 | Identifies the current context as a command to be run. 49 | 50 | isAssignment : 51 | If the result of the commandline will be assigned to a variable 52 | (reserved for future functionality). 53 | 54 | isParameterValue : 55 | Identifies the current context of the last word as being a value 56 | to a parameter. 57 | 58 | 59 | Examples: 60 | 61 | Line : Get-Process d* -ComputerName 62 | LastWord : 63 | LastToken : CommandParameter 64 | Command : Get-Process 65 | Parameter : ComputerName 66 | Argument : 67 | PositionalParameter : 0 68 | PositionalParameters : {d*} 69 | OtherParameters : {} 70 | isCommandMode : True 71 | isAssignment : False 72 | isParameterValue : True 73 | 74 | 75 | Line : Get-Process -Name d* -ErrorVariable e 76 | LastWord : e 77 | LastToken : CommandArgument 78 | Command : Get-Process 79 | Parameter : ErrorVariable 80 | Argument : e 81 | PositionalParameter : -1 82 | PositionalParameters : {} 83 | OtherParameters : {Name} 84 | isCommandMode : True 85 | isAssignment : False 86 | isParameterValue : True 87 | 88 | 89 | SEE ALSO 90 | 91 | http://powertab.codeplex.com/documentation 92 | -------------------------------------------------------------------------------- /Modules/PowerTab/en/Resources.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ## en 3 | export_tabexpansionconfig_ver_success = "Configuration exported to '{0}'" 4 | export_tabexpansiondatabase_ver_success = "TabExpansion database exported to '{0}'" 5 | global_choice_no = "&No" 6 | global_choice_yes = "&Yes" 7 | import_tabexpansionconfig_ver_success = "Configuration imported from '{0}'" 8 | import_tabexpansiondatabase_ver_success = "TabExpansion database imported from '{0}'" 9 | invoke_tabactivityindicator_prog_status = "PowerTab is retrieving or displaying available tab expansion options." 10 | setup_wizard_add_to_profile = "Add the following text to the PowerShell profile to launch PowerTab with the saved configuration." 11 | setup_wizard_caption = "Launch the setup wizard to create a PowerTab configuration file and database?" 12 | setup_wizard_choice_appdata_directory = "&Application Data Directory" 13 | setup_wizard_choice_install_directory = "&Installation Directory" 14 | setup_wizard_choice_isostorage_directory = "Isolated &Storage" 15 | setup_wizard_choice_other_directory = "&Other Directory" 16 | setup_wizard_choice_profile_directory = "&Profile Directory" 17 | setup_wizard_config_location_caption = "Where should the PowerTab configuration file and database be saved?" 18 | setup_wizard_config_location_message = "Any existing PowerTab configuration will be overwritten." 19 | setup_wizard_err_path_not_valid = "The given path's format is not supported." 20 | setup_wizard_message = "PowerTab can be setup manually without the setup wizard." 21 | setup_wizard_other_directory_prompt = "Enter the directory path for storing the PowerTab configuration file and database" 22 | setup_wizard_upgrade_existing_database_caption = "Upgrade existing tab completion database?" 23 | setup_wizard_upgrade_existing_database_message = "An existing tab completion database has been detected." 24 | update_tabexpansiondatabase_com_activity = "Adding COM Classes" 25 | update_tabexpansiondatabase_com_conf_caption = "Update COM class list in tab completion database?" 26 | update_tabexpansiondatabase_com_conf_description = "Loading COM classes." 27 | update_tabexpansiondatabase_com_conf_inquire = "Loading COM classes." 28 | update_tabexpansiondatabase_computer_activity = "Adding computer names" 29 | update_tabexpansiondatabase_computer_conf_caption = "Update computer list in tab completion database from 'net view'?" 30 | update_tabexpansiondatabase_computer_conf_description = "Loading computer names." 31 | update_tabexpansiondatabase_computer_conf_inquire = "Loading computer names." 32 | update_tabexpansiondatabase_type_conf_caption = "Update .NET type list in tab completion database from currently loaded types?" 33 | update_tabexpansiondatabase_type_conf_description = "Loading .NET types." 34 | update_tabexpansiondatabase_type_conf_inquire = "Loading .NET types." 35 | update_tabexpansiondatabase_wmi_activity = "Adding WMI Classes" 36 | update_tabexpansiondatabase_wmi_conf_caption = "Update WMI class list in tab completion database?" 37 | update_tabexpansiondatabase_wmi_conf_description = "Loading WMI classes." 38 | update_tabexpansiondatabase_wmi_conf_inquire = "Loading WMI classes." 39 | } 40 | -------------------------------------------------------------------------------- /Modules/PowerTab/en-US/Resources.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | ## en-US 3 | export_tabexpansionconfig_ver_success = "Configuration exported to '{0}'" 4 | export_tabexpansiondatabase_ver_success = "TabExpansion database exported to '{0}'" 5 | global_choice_no = "&No" 6 | global_choice_yes = "&Yes" 7 | import_tabexpansionconfig_ver_success = "Configuration imported from '{0}'" 8 | import_tabexpansiondatabase_ver_success = "TabExpansion database imported from '{0}'" 9 | invoke_tabactivityindicator_prog_status = "PowerTab is retrieving or displaying available tab expansion options." 10 | setup_wizard_add_to_profile = "Add the following text to the PowerShell profile to launch PowerTab with the saved configuration." 11 | setup_wizard_caption = "Launch the setup wizard to create a PowerTab configuration file and database?" 12 | setup_wizard_choice_appdata_directory = "&Application Data Directory" 13 | setup_wizard_choice_install_directory = "&Installation Directory" 14 | setup_wizard_choice_isostorage_directory = "Isolated &Storage" 15 | setup_wizard_choice_other_directory = "&Other Directory" 16 | setup_wizard_choice_profile_directory = "&Profile Directory" 17 | setup_wizard_config_location_caption = "Where should the PowerTab configuration file and database be saved?" 18 | setup_wizard_config_location_message = "Any existing PowerTab configuration will be overwritten." 19 | setup_wizard_err_path_not_valid = "The given path's format is not supported." 20 | setup_wizard_message = "PowerTab can be setup manually without the setup wizard." 21 | setup_wizard_other_directory_prompt = "Enter the directory path for storing the PowerTab configuration file and database" 22 | setup_wizard_upgrade_existing_database_caption = "Upgrade existing tab completion database?" 23 | setup_wizard_upgrade_existing_database_message = "An existing tab completion database has been detected." 24 | update_tabexpansiondatabase_com_activity = "Adding COM Classes" 25 | update_tabexpansiondatabase_com_conf_caption = "Update COM class list in tab completion database?" 26 | update_tabexpansiondatabase_com_conf_description = "Loading COM classes." 27 | update_tabexpansiondatabase_com_conf_inquire = "Loading COM classes." 28 | update_tabexpansiondatabase_computer_activity = "Adding computer names" 29 | update_tabexpansiondatabase_computer_conf_caption = "Update computer list in tab completion database from 'net view'?" 30 | update_tabexpansiondatabase_computer_conf_description = "Loading computer names." 31 | update_tabexpansiondatabase_computer_conf_inquire = "Loading computer names." 32 | update_tabexpansiondatabase_type_conf_caption = "Update .NET type list in tab completion database from currently loaded types?" 33 | update_tabexpansiondatabase_type_conf_description = "Loading .NET types." 34 | update_tabexpansiondatabase_type_conf_inquire = "Loading .NET types." 35 | update_tabexpansiondatabase_wmi_activity = "Adding WMI Classes" 36 | update_tabexpansiondatabase_wmi_conf_caption = "Update WMI class list in tab completion database?" 37 | update_tabexpansiondatabase_wmi_conf_description = "Loading WMI classes." 38 | update_tabexpansiondatabase_wmi_conf_inquire = "Loading WMI classes." 39 | } 40 | -------------------------------------------------------------------------------- /Modules/PowerTab/Handlers/Robocopy.ps1: -------------------------------------------------------------------------------- 1 | ## Robocopy 2 | & { 3 | Register-TabExpansion "robocopy.exe" -Type "Command" { 4 | param($Context, [ref]$TabExpansionHasOutput) 5 | $Argument = $Context.Argument 6 | switch -exact ($Context.Parameter) { 7 | 'Options' { 8 | $TabExpansionHasOutput.Value = $true 9 | if ($Argument -notlike "/*") {$Argument = "/$Argument"} 10 | $RoboHelp = robocopy.exe /? | Select-String '::' 11 | $r = [regex]'(.*)::(.*)' 12 | $RoboHelpObject = $RoboHelp | Select-Object ` 13 | @{Name='Parameter';Expression={$r.Match($_).Groups[1].Value.Trim()}}, 14 | @{Name='Description';Expression={$r.Match($_).Groups[2].Value.Trim()}} 15 | 16 | <# ## For now, we don't need category 17 | $RoboHelpObject = $RoboHelpObject | ForEach-Object {$Cat = 'General'} { 18 | if ($_.Parameter -eq '') { 19 | if ($_.Description -ne '') {$cat = $_.Description -replace 'options :',''} 20 | } else { 21 | $_ | Select-Object @{Name='Category';Expression={$cat}},Parameter,Description 22 | } 23 | } 24 | #> 25 | $RoboHelpObject | Where-Object {$_.Parameter -like "$Argument*"} | Select-Object -ExpandProperty Parameter 26 | } 27 | } 28 | }.GetNewClosure() 29 | 30 | Function robocopyexeparameters { 31 | param( 32 | [Parameter(Position = 0)] 33 | [String]$Source 34 | , 35 | [Parameter(Position = 1)] 36 | [String]$Destination 37 | , 38 | [Parameter(Position = 2, ValueFromRemainingArguments = $true)] 39 | [String[]]$Options 40 | ) 41 | } 42 | 43 | $RobocopyCommandInfo = Get-Command "robocopyexeparameters" 44 | Register-TabExpansion "robocopy.exe" -Type "CommandInfo" { 45 | param($Context) 46 | $RobocopyCommandInfo 47 | }.GetNewClosure() 48 | } 49 | 50 | ## xcopy 51 | & { 52 | Register-TabExpansion "xcopy.exe" -Type "Command" { 53 | param($Context, [ref]$TabExpansionHasOutput) 54 | $Argument = $Context.Argument 55 | switch -exact ($Context.Parameter) { 56 | 'Options' { 57 | $TabExpansionHasOutput.Value = $true 58 | if ($Argument -notlike "/*") {$Argument = "/$Argument"} 59 | $r = [regex]'^\s\s(/\S+)*' 60 | xcopy.exe /? | ForEach-Object {$r.Match($_).Groups[1].Value.Trim()} | Where-Object {$_ -like "$Argument*"} 61 | } 62 | } 63 | }.GetNewClosure() 64 | 65 | Function xcopyexeparameters { 66 | param( 67 | [Parameter(Position = 0)] 68 | [String]$Source 69 | , 70 | [Parameter(Position = 1)] 71 | [String]$Destination 72 | , 73 | [Parameter(Position = 2, ValueFromRemainingArguments = $true)] 74 | [String[]]$Options 75 | ) 76 | } 77 | 78 | $xcopyCommandInfo = Get-Command "xcopyexeparameters" 79 | Register-TabExpansion "xcopy.exe" -Type "CommandInfo" { 80 | param($Context) 81 | $xcopyCommandInfo 82 | }.GetNewClosure() 83 | } 84 | 85 | ## cmdkey -------------------------------------------------------------------------------- /Tests/Get-VcsStatus.Tests.ps1: -------------------------------------------------------------------------------- 1 | $ROOT = Split-Path -Parent $MyInvocation.MyCommand.Path 2 | 3 | #Unload posh-hg/svn/git if they exist, and load in our own shims in their place 4 | Get-Module -Name posh-git | Remove-Module 5 | New-Module -Name posh-git -ScriptBlock { 6 | function Get-GitStatus {} 7 | function Start-SshAgent {} 8 | 9 | Export-ModuleMember -Function Get-GitStatus 10 | Export-ModuleMember -Function Start-SshAgent 11 | } | Import-Module -Force 12 | 13 | Get-Module -Name posh-hg | Remove-Module 14 | New-Module -Name posh-hg -ScriptBlock { 15 | function Get-HgStatus {} 16 | 17 | Export-ModuleMember -Function Get-HgStatus 18 | } | Import-Module -Force 19 | 20 | Get-Module -Name posh-svn | Remove-Module 21 | New-Module -Name posh-svn -ScriptBlock { 22 | function Get-SvnStatus {} 23 | 24 | Export-ModuleMember -Function Get-SvnStatus 25 | } | Import-Module -Force 26 | 27 | . "$ROOT\..\Microsoft.PowerShell_profile.ps1" 28 | 29 | Describe "When in a git repo with posh-git installed" { 30 | Mock Get-GitStatus { return $true; } 31 | 32 | Context "And neither posh-hg nor posh-svn are installed" { 33 | Get-HgStatus = $null 34 | Get-SvnStatus = $null 35 | 36 | It "Returns a positive status" { 37 | Get-VcsStatus | Should Be $true 38 | } 39 | } 40 | 41 | Context "And posh-hg is installed" { 42 | Mock Get-HgStatus { return $false; } 43 | Get-SvnStatus = $null 44 | 45 | It "Returns a positive status" { 46 | Get-VcsStatus | Should Be $true 47 | } 48 | } 49 | 50 | Context "And posh-svn is installed" { 51 | Mock Get-SvnStatus { return $false; } 52 | Get-HgStatus = $null 53 | 54 | It "Returns a positive status" { 55 | Get-VcsStatus | Should Be $true 56 | } 57 | } 58 | 59 | Context "And posh-hg and posh-svn are installed" { 60 | Mock Get-SvnStatus { return $false; } 61 | Mock Get-HgStatus { return $false; } 62 | 63 | It "Returns a positive status" { 64 | Get-VcsStatus | Should Be $true 65 | } 66 | } 67 | } 68 | 69 | Describe "When in a hg repo with posh-hg installed" { 70 | Mock Get-HgStatus { return $true; } 71 | 72 | Context "And neither posh-git nor posh-svn are installed" { 73 | Get-GitStatus = $null 74 | Get-SvnStatus = $null 75 | 76 | It "Returns a positive status" { 77 | Get-VcsStatus | Should Be $true 78 | } 79 | } 80 | 81 | Context "And posh-git is installed" { 82 | Mock Get-GitStatus { return $false; } 83 | Get-SvnStatus = $null 84 | 85 | It "Returns a positive status" { 86 | Get-VcsStatus | Should Be $true 87 | } 88 | } 89 | 90 | Context "And posh-svn is installed" { 91 | Mock Get-SvnStatus { return $false; } 92 | Get-GitStatus = $null 93 | 94 | It "Returns a positive status" { 95 | Get-VcsStatus | Should Be $true 96 | } 97 | } 98 | 99 | Context "And posh-git and posh-svn are installed" { 100 | Mock Get-SvnStatus { return $false; } 101 | Mock Get-GitStatus { return $false; } 102 | 103 | It "Returns a positive status" { 104 | Get-VcsStatus | Should Be $true 105 | } 106 | } 107 | } 108 | 109 | Describe "When in a svn repo with posh-svn installed" { 110 | Mock Get-SvnStatus { return $true; } 111 | 112 | Context "And neither posh-git nor posh-hg are installed" { 113 | Get-GitStatus = $null 114 | Get-HgStatus = $null 115 | 116 | It "Returns a positive status" { 117 | Get-VcsStatus | Should Be $true 118 | } 119 | } 120 | 121 | Context "And posh-git is installed" { 122 | Mock Get-GitStatus { return $false; } 123 | Get-HgStatus = $null 124 | 125 | It "Returns a positive status" { 126 | Get-VcsStatus | Should Be $true 127 | } 128 | } 129 | 130 | Context "And posh-hg is installed" { 131 | Mock Get-HgStatus { return $false; } 132 | Get-GitStatus = $null 133 | 134 | It "Returns a positive status" { 135 | Get-VcsStatus | Should Be $true 136 | } 137 | } 138 | 139 | Context "And posh-git and posh-hg are installed" { 140 | Mock Get-HgStatus { return $false; } 141 | Mock Get-GitStatus { return $false; } 142 | 143 | It "Returns a positive status" { 144 | Get-VcsStatus | Should Be $true 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /Modules/PowerTab/about_PowerTab_usage.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_PowerTab_usage 3 | 4 | SHORT DESCRIPTION 5 | Describes the uses of tab expansion that PowerTab offers. 6 | 7 | LONG DESCRIPTION 8 | PowerTab supports additional usage scenarios for tab expanding commands, 9 | references and code constructs. This topic describes the general set of 10 | uses built into PowerTab, with examples. To try the examples, enter the 11 | exact text of the example and press the [TAB] key. 12 | 13 | PowerTab also offers specific support for many important command 14 | parameters such as enums, process names, and other information that 15 | PowerTab can look up. If a parameter is directly support, it will take 16 | precedence over the usage patterns described in this topic. 17 | 18 | 19 | PATHS 20 | Paths are the basic usage that PowerTab can handle. Any PSDrive path 21 | will work and relative paths will be preserved. 22 | 23 | .\ 24 | HKLM:\ 25 | 26 | 27 | COMMANDS 28 | PowerTab can complete the name of Powershell cmdlets, functions and 29 | aliases given hints. PowerTab will look for the "-" pattern for 30 | commands. Adding a "%" character to the end of the search string will 31 | force PowerTab to search for any type of command (cmdlet, function, 32 | script, or application). 33 | 34 | Get- 35 | % 36 | add% 37 | 38 | 39 | COMMAND PARAMETERS 40 | Command parameter names can be expaned for cmdlets, functions and 41 | scripts. PowerTab will also detect the corresponding command to the 42 | current cursor location. 43 | 44 | Get-ChildItem - 45 | Get-Process | Format-Table - 46 | 47 | 48 | VARIABLE NAMES 49 | Powertab can expand the names of variables, including quoting with "{" 50 | and "}" as needed. 51 | 52 | $ 53 | $error 54 | 55 | 56 | VARIABLE PROPERTIES AND METHODS 57 | Properties and methods on objects stored in variables can be accessed 58 | with PowerTab. 59 | 60 | $error.g 61 | 62 | 63 | VARIABLE STATIC METHODS 64 | Static properties and methods of objects stored in variables can also be 65 | accessed. 66 | 67 | $error:: 68 | 69 | 70 | VARIABLES BY SCOPE 71 | PowerTab will respect scope when expanding variable names with a scope. 72 | 73 | $global: 74 | 75 | 76 | VARIABLES BY TYPE 77 | Variable references to items on other PSDrives can also be expanded in 78 | PowerTab. 79 | 80 | $alias: 81 | $function: 82 | 83 | 84 | NATIVE COMMANDS 85 | To tab expand the names of native commands and executables, add the "!" 86 | character to the end of the search string (that character will be removed 87 | from the results). 88 | 89 | ! 90 | net! 91 | 92 | 93 | HISTORY 94 | PowerTab supports expanding command history in the same way as the 95 | default tab expansion in PowerShell, using the "#" character to lead off 96 | the search string. Additionally, PowerTab supports wildcards in the 97 | search string. 98 | 99 | # 100 | #cd 101 | #12 102 | 103 | 104 | HELP TOPICS 105 | When looking up a help topic, PowerTab can assist by tab expanding the 106 | names of the available help topics. 107 | 108 | about_ 109 | Get-Help about_ 110 | 111 | 112 | TYPES 113 | Type name expansion can be accomplished if .NET type names have been 114 | cached in the tab expansion database. Use the following patterns. 115 | 116 | [ 117 | [System. 118 | [.DateTime 119 | .DateTime 120 | 121 | The last two examples will search for any namespace or type beginning 122 | with the entered string. 123 | 124 | To update the tab expansion database with a list of type names, run this 125 | command. 126 | 127 | Update-TabExpansionType 128 | 129 | 130 | TYPE STATIC MEMBERS 131 | Static properties and methods on .Net types are recognized by PowerTab. 132 | 133 | [System.DateTime]:: 134 | 135 | 136 | TYPE METHOD SIGNATURES 137 | By pressing [TAB] after the first parenthesis of a method, PowerTab will 138 | offer safe syntax for all the available overloads of the method. 139 | 140 | [System.DateTime]::Compare( 141 | $Date.ToString( 142 | 143 | 144 | ENUMS 145 | Enumeration values can also be expaned with PowerTab. 146 | 147 | [ConsoleColor]::B 148 | 149 | 150 | WMI CLASSES 151 | References to WMI class names can be expaned with PowerTab using these 152 | patterns. 153 | 154 | win32_ 155 | cim_ 156 | msft_ 157 | 158 | 159 | SEE ALSO 160 | 161 | http://powertab.codeplex.com/documentation 162 | -------------------------------------------------------------------------------- /Modules/ScriptBrowser/ScriptBrowser.psm1: -------------------------------------------------------------------------------- 1 | #requires -Version 3 2 | 3 | #Import Localized Data 4 | Import-LocalizedData -BindingVariable Messages 5 | 6 | # A variable that contains the install directory path of Script Browser and Script Analyzer. 7 | if ($env:PROCESSOR_ARCHITECTURE -eq "X86") 8 | { 9 | $installDir = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Script Browser\" -PSProperty "Install Directory" -ErrorAction:SilentlyContinue 10 | } 11 | else 12 | { 13 | $installDir = Get-ItemProperty -Path "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Script Browser\" -PSProperty "Install Directory" -ErrorAction:SilentlyContinue 14 | } 15 | 16 | if ($installDir -ne $null) 17 | { 18 | $installDir = $installDir.'Install Directory' 19 | } 20 | else 21 | { 22 | $errorMsg = $Messages.MissingRegValue 23 | throw $errorMsg 24 | } 25 | 26 | # Adds Script Browser to Windows PowerShell ISE. 27 | function Enable-ScriptBrowser 28 | { 29 | # This function is only available in Windows PowerShell ISE console pane. 30 | TestWindowsPowerShellISE -FunctionName "Enable-ScriptBrowser" 31 | 32 | try 33 | { 34 | Add-Type -Path "$installDir\System.Windows.Interactivity.dll" -ErrorAction:Stop 35 | Add-Type -Path "$installDir\ScriptBrowser.dll" -ErrorAction:Stop 36 | $scriptBrowser = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Browser', [ScriptExplorer.Views.MainView], $true) 37 | $psISE.CurrentPowerShellTab.VisibleVerticalAddOnTools.SelectedAddOnTool = $scriptBrowser 38 | } 39 | catch 40 | { 41 | Write-Error -ErrorRecord $PSItem 42 | } 43 | } # end Enable-ScriptBrowser. 44 | 45 | # Removes Script Browser from Windows PowerShell ISE. 46 | function Disable-ScriptBrowser 47 | { 48 | # This function is only available in Windows PowerShell ISE console pane. 49 | TestWindowsPowerShellISE -FunctionName "Disable-ScriptBrowser" 50 | 51 | try 52 | { 53 | $scriptBrowser = $psISE.CurrentPowerShellTab.VerticalAddOnTools | ` 54 | Where-Object -FilterScript {$PSItem.Control.ToString() -eq "ScriptExplorer.Views.MainView"} 55 | 56 | if ($scriptBrowser -ne $null) 57 | { 58 | [void]$psISE.CurrentPowerShellTab.VerticalAddOnTools.Remove($scriptBrowser) 59 | } 60 | } 61 | catch 62 | { 63 | Write-Error -ErrorRecord $PSItem 64 | } 65 | } # end Disable-ScriptBrowser. 66 | 67 | # Adds Script Analyzer to Windows PowerShell ISE. 68 | function Enable-ScriptAnalyzer 69 | { 70 | # This function is only available in Windows PowerShell ISE console pane. 71 | TestWindowsPowerShellISE -FunctionName "Enable-ScriptAnalyzer" 72 | 73 | try 74 | { 75 | Add-Type -Path "$installDir\System.Windows.Interactivity.dll" -ErrorAction:Stop 76 | Add-Type -Path "$installDir\BestPractices.dll" -ErrorAction:Stop 77 | $scriptAnalyzer = $psISE.CurrentPowerShellTab.VerticalAddOnTools.Add('Script Analyzer', [BestPractices.Views.BestPracticesView], $true) 78 | $psISE.CurrentPowerShellTab.VisibleVerticalAddOnTools.SelectedAddOnTool = $scriptAnalyzer 79 | } 80 | catch 81 | { 82 | Write-Error -ErrorRecord $PSItem 83 | } 84 | } # end Enable-ScriptAnalyzer. 85 | 86 | # Removes Script Analyzer from Windows PowerShell ISE. 87 | function Disable-ScriptAnalyzer 88 | { 89 | # This function is only available in Windows PowerShell ISE console pane. 90 | TestWindowsPowerShellISE -FunctionName "Disable-ScriptAnalyzer" 91 | 92 | try 93 | { 94 | $scriptAnalyzer = $psISE.CurrentPowerShellTab.VerticalAddOnTools | ` 95 | Where-Object -FilterScript {$PSItem.Control.ToString() -eq "BestPractices.Views.BestPracticesView"} 96 | 97 | if ($scriptAnalyzer -ne $null) 98 | { 99 | [void]$psISE.CurrentPowerShellTab.VerticalAddOnTools.Remove($scriptAnalyzer) 100 | } 101 | } 102 | catch 103 | { 104 | Write-Error -ErrorRecord $PSItem 105 | } 106 | } # end Disable-ScriptAnalyzer. 107 | 108 | # Start Script Browser desktop application. 109 | function Start-ScriptBrowserDesktop 110 | { 111 | try 112 | { 113 | Start-Process -FilePath "$installDir\ScriptBrowserDesktop.exe" -ErrorAction:Stop 114 | } 115 | catch 116 | { 117 | Write-Error -ErrorRecord $PSItem 118 | } 119 | } # end Start-ScriptBrowserApp. 120 | 121 | #region Helper function(s) 122 | 123 | # Some functions are only available in Windows PowerShell ISE console pane. 124 | function TestWindowsPowerShellISE 125 | { 126 | param ([string]$FunctionName) 127 | 128 | if ($Host.Name -ne "Windows PowerShell ISE Host") 129 | { 130 | $errorMsg = $Messages.RequiresISE -f $FunctionName 131 | throw $errorMsg 132 | } 133 | } 134 | #endregion 135 | 136 | Export-ModuleMember -Function "Enable-ScriptBrowser", "Disable-ScriptBrowser", "Enable-ScriptAnalyzer", "Disable-ScriptAnalyzer", "Start-ScriptBrowserDesktop" -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansionCore-Help.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Invoke-TabExpansion 6 | 7 | Invokes the tab expansion logic of PowerTab. 8 | 9 | 10 | Invoke 11 | TabExpansion 12 | 13 | 14 | 15 | TODO Add Long description 16 | 17 | 18 | 19 | Invoke-TabExpansion 20 | 21 | Line 22 | 23 | String 24 | 25 | 26 | LastWord 27 | 28 | String 29 | 30 | 31 | ForceList 32 | 33 | 34 | 35 | 36 | 37 | 38 | ForceList 39 | 40 | TODO Add ForceList Description 41 | 42 | SwitchParameter 43 | 44 | 45 | 46 | LastWord 47 | 48 | TODO Add LastWord Description 49 | 50 | String 51 | 52 | 53 | 54 | Line 55 | 56 | TODO Add Line Description 57 | 58 | String 59 | 60 | 61 | 62 | 63 | 64 | 65 | None 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | System.String 76 | 77 | 78 | 79 | 80 | 81 | Zero, one or more tab expansion options. 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | -------------------------- EXAMPLE 1 -------------------------- 97 | 98 | C:\PS> 99 | 100 | TODO Add Invoke-TabExpansion Example code 101 | 102 | TODO Add Invoke-TabExpansion Example Comment 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | about_PowerTab 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Modules/PowerTab/about_PowerTab_handlers.help.txt: -------------------------------------------------------------------------------- 1 | TOPIC 2 | about_PowerTab_handlers 3 | 4 | SHORT DESCRIPTION 5 | Tab expansion suppose in PowerTab can be extended with plug-ins by 6 | following the steps in this topic. 7 | 8 | LONG DESCRIPTION 9 | PowerTab provides a framework to enrich the tab expansion experience in 10 | PowerShell. It also provides extension points to add tab expansion support 11 | for additional cmdlets, functions and applications that are not already 12 | supported by PowerTab. This is done through tab expansion handlers that 13 | add logic to PowerTab. 14 | 15 | Tab expansion handlers are given first chance to decide what to do with 16 | the command line. Once a handler has signaled that it has decided on the 17 | appropriate output, processing halts and the output of that handler is 18 | pressented to the user according to their preferences or the limitations of 19 | the PowerShell host. 20 | 21 | Order of operation: 22 | 1: Command Handler (for the current command, if it exists) 23 | 2: Parameter Handler (for the current parameter, if it exists) 24 | 3: Enum Handler (internal to PowerTab, handles parameters with enum 25 | values) 26 | 4: Core Handler (general PowerTab logic) 27 | 28 | 29 | CREATING A COMMAND HANDLER 30 | Command handlers are called when the last word (location of the cursor) 31 | will be the value to a parameter of the command that the command handler 32 | is registered to. The handler will be given first chance at the user 33 | input as well as information on the current context. Because of this, 34 | command handlers can override default PowerTab behavior for parameters 35 | of the command. 36 | 37 | Command handlers must follow this contract. 38 | 39 | NOTE: This applies to command and parameter handlers 40 | 1: PowerTab WILL provide a context object that records what is known 41 | about the current command line, and a couple of reference variables 42 | (see about_PowerTab_context for details). 43 | 2: If the handler will provide the tab expansion options for the given 44 | context, it MUST set the variable $TabExpansionHasOutput.Value to 45 | $true, even if no results will be produced. This will stop PowerTab 46 | from interpreting the context any further. 47 | 3: The handler MUST output the options, as strings, to be displayed to 48 | the user, or no output at all. 49 | 4: The handler MAY set the variable $QuoteSpaces.Value to $false to 50 | prevent PowerTab from quoting output values from the handler that 51 | contain spaces. The default is $true. 52 | 53 | Example: 54 | 55 | Register-TabExpansion "Get-Service" -Type Command { 56 | # 1: 57 | param($Context, [ref]$TabExpansionHasOutput, [ref]$QuoteSpaces) 58 | 59 | $Argument = $Context.Argument 60 | switch -exact ($Context.Parameter) { 61 | 'DisplayName' { 62 | $TabExpansionHasOutput.Value = $true # 2: 63 | Get-Service -DisplayName "*$Argument*" | 64 | Select-Object -ExpandProperty DisplayName # 3: 65 | } 66 | 'Name' { 67 | $TabExpansionHasOutput.Value = $true # 2: 68 | Get-Service -Name "$Argument*" | 69 | Select-Object -ExpandProperty Name # 3: 70 | } 71 | } 72 | } 73 | 74 | 75 | CREATING A PARAMETER HANDLER 76 | Parameter handlers are called when the last word (location of the cursor) 77 | will be the value to the parameter that the parameter handler is 78 | registered to. This handler will be called for any command, but only if 79 | the registered parameter is the current context. 80 | 81 | Parameter handlers must follow this contract. 82 | 83 | NOTE: This applies to command and parameter handlers 84 | 1: PowerTab WILL provide a context object that records what is known 85 | about the current command line, and a couple of reference variables 86 | (see about_PowerTab_context for details). 87 | 2: If the handler will provide the tab expansion options for the given 88 | context, it MUST set the variable $TabExpansionHasOutput.Value to 89 | $true, even if no results will be produced. This will stop PowerTab 90 | from interpreting the context any further. 91 | 3: The handler MUST output the options, as strings, to be displayed to 92 | the user, or no output at all. 93 | 4: The handler MAY set the variable $QuoteSpaces.Value to $false to 94 | prevent PowerTab from quoting output values from the handler that 95 | contain spaces. The default is $true. 96 | 97 | Example: 98 | 99 | Register-TabExpansion "PSDrive" -Type Parameter { 100 | # 1: 101 | param($Argument, [ref]$TabExpansionHasOutput, [ref]$QuoteSpaces) 102 | 103 | if ($Argument -notlike '^\$') { 104 | $TabExpansionHasOutput.Value = $true # 2: 105 | Get-PSDrive "$Argument*" | 106 | Select-Object -ExpandProperty Name # 3: 107 | } 108 | } 109 | 110 | 111 | REGISTERING A HANDLER 112 | Once the hander's script block is defined, it must be registered with 113 | PowerTab. Here is the syntax of the registration command. 114 | 115 | Register-TabExpansion [-Name] [-Handler] 116 | [-Type ] [-Force] 117 | 118 | The name of the command or parameter to handle must be entered. There can 119 | only be one handler for a command name or parameter name. 120 | 121 | A command name can either be simple like "Get-FooBar" or fully qualified 122 | like "MyModule\Get-Foobar". Using the simple name will trigger on any 123 | module using that command name. 124 | 125 | A parameter name should only be the real name of the parameter like 126 | "ComputerName". Parameter name aliases will be resolved by PowerTab like 127 | "cn" or "comp". 128 | 129 | 130 | SEE ALSO 131 | 132 | about_PowerTab_context 133 | http://powertab.codeplex.com/documentation 134 | -------------------------------------------------------------------------------- /PowerTabConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Global 5 | DefaultHandler 6 | Dynamic 7 | String 8 | 9 | 10 | Global 11 | CustomUserFunction 12 | Write-Warning 13 | String 14 | 15 | 16 | Version 17 | Version 18 | 0.99.6.0 19 | String 20 | 21 | 22 | Global 23 | AlternateHandler 24 | Dynamic 25 | String 26 | 27 | 28 | Global 29 | CustomCompletionChars 30 | ]:) 31 | String 32 | 33 | 34 | Colors 35 | BorderColor 36 | Blue 37 | ConsoleColor 38 | 39 | 40 | Colors 41 | BorderBackColor 42 | DarkBlue 43 | ConsoleColor 44 | 45 | 46 | Colors 47 | BackColor 48 | DarkGray 49 | ConsoleColor 50 | 51 | 52 | Colors 53 | TextColor 54 | Yellow 55 | ConsoleColor 56 | 57 | 58 | Colors 59 | SelectedBackColor 60 | DarkRed 61 | ConsoleColor 62 | 63 | 64 | Colors 65 | SelectedTextColor 66 | Red 67 | ConsoleColor 68 | 69 | 70 | Colors 71 | BorderTextColor 72 | Yellow 73 | ConsoleColor 74 | 75 | 76 | Colors 77 | FilterColor 78 | DarkGray 79 | ConsoleColor 80 | 81 | 82 | ShortcutChars 83 | Invoke 84 | & 85 | String 86 | 87 | 88 | ShortcutChars 89 | Custom 90 | ^ 91 | String 92 | 93 | 94 | ShortcutChars 95 | Alias 96 | @ 97 | String 98 | 99 | 100 | ShortcutChars 101 | Partial 102 | % 103 | String 104 | 105 | 106 | ShortcutChars 107 | CustomFunction 108 | # 109 | String 110 | 111 | 112 | ShortcutChars 113 | Native 114 | ! 115 | String 116 | 117 | 118 | Setup 119 | ConfigurationPath 120 | C:\Users\chbentiv\Documents\WindowsPowerShell\PowerTabConfig.xml 121 | String 122 | 123 | 124 | Setup 125 | DatabasePath 126 | C:\Users\chbentiv\Documents\WindowsPowerShell\TabExpansion.xml 127 | String 128 | 129 | 130 | Global 131 | Enabled 132 | 1 133 | Bool 134 | 135 | 136 | Global 137 | DoubleBorder 138 | 1 139 | Bool 140 | 141 | 142 | Global 143 | BackSlashComplete 144 | 1 145 | Bool 146 | 147 | 148 | Global 149 | DotComplete 150 | 1 151 | Bool 152 | 153 | 154 | Global 155 | ShowBanner 156 | 0 157 | Bool 158 | 159 | 160 | Global 161 | SpaceComplete 162 | 1 163 | Bool 164 | 165 | 166 | Global 167 | DoubleTabLock 168 | 0 169 | Bool 170 | 171 | 172 | Global 173 | AutoExpandOnBackSlash 174 | 1 175 | Bool 176 | 177 | 178 | Global 179 | CustomFunctionEnabled 180 | 0 181 | Bool 182 | 183 | 184 | Global 185 | VisualStudioTabBehavior 186 | 0 187 | Bool 188 | 189 | 190 | Global 191 | FileSystemExpand 192 | 1 193 | Bool 194 | 195 | 196 | Global 197 | CloseListOnEmptyFilter 198 | 1 199 | Bool 200 | 201 | 202 | Global 203 | AliasQuickExpand 204 | 0 205 | Bool 206 | 207 | 208 | Global 209 | IgnoreConfirmPreference 210 | 0 211 | Bool 212 | 213 | 214 | Global 215 | DoubleTabEnabled 216 | 0 217 | Bool 218 | 219 | 220 | Global 221 | TabActivityIndicator 222 | 1 223 | Bool 224 | 225 | 226 | Global 227 | AutoExpandOnDot 228 | 1 229 | Bool 230 | 231 | 232 | Global 233 | ShowAccessorMethods 234 | 1 235 | Bool 236 | 237 | 238 | Global 239 | CustomComplete 240 | 1 241 | Bool 242 | 243 | 244 | Global 245 | MinimumListItems 246 | 2 247 | Int 248 | 249 | 250 | Global 251 | FastScrollItemcount 252 | 10 253 | Int 254 | 255 | -------------------------------------------------------------------------------- /Modules/PsUrl/PsUrl.psm1: -------------------------------------------------------------------------------- 1 | ## 2 | ## Inspired by curl, adds some commands to work with web. 3 | ## 4 | 5 | function Get-Url { 6 | [CmdletBinding()] 7 | Param( 8 | [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)] 9 | [String]$Url, 10 | [String]$ToFile, 11 | [Management.Automation.PSCredential]$Credential 12 | ) 13 | Write-Verbose "Get-Url is considered obsolete. Please use Get-WebContent instead" 14 | 15 | $client = (New-Object Net.WebClient) 16 | if ($Credential){ 17 | $ntwCred = $Credential.GetNetworkCredential() 18 | $client.Credentials = $ntwCred 19 | $auth = "Basic " + [Convert]::ToBase64String([Text.Encoding]::Default.GetBytes($ntwCred.UserName + ":" + $ntwCred.Password)) 20 | $client.Headers.Add("Authorization", $auth) 21 | } 22 | 23 | if ($ToFile -ne ""){ 24 | $client.DownloadFile($Url, $ToFile) 25 | } else { 26 | $client.DownloadString($Url) 27 | } 28 | <# 29 | .Synopsis 30 | Downloads from url as a string. 31 | .Description 32 | .Parameter Url 33 | URL to download 34 | .Parameter ToFile 35 | Optional parameter to download stuff to the file. 36 | .Example 37 | Get-Url http://chaliy.name 38 | 39 | Description 40 | ----------- 41 | Downloads content of the http://chaliy.name 42 | 43 | #> 44 | } 45 | 46 | function Get-WebContent { 47 | [CmdletBinding()] 48 | Param( 49 | [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)] 50 | [String]$Url, 51 | [Management.Automation.PSCredential]$Credential, 52 | $Encoding 53 | ) 54 | $client = (New-Object Net.WebClient) 55 | if ($Credential){ 56 | $ntwCred = $Credential.GetNetworkCredential() 57 | $client.Credentials = $ntwCred 58 | $auth = "Basic " + [Convert]::ToBase64String([Text.Encoding]::Default.GetBytes($ntwCred.UserName + ":" + $ntwCred.Password)) 59 | $client.Headers.Add("Authorization", $auth) 60 | } 61 | if ($Encoding){ 62 | if ($Encoding -is [string]){ 63 | $Encoding = [Text.Encoding]::GetEncoding($Encoding) 64 | } 65 | $client.Encoding = $Encoding 66 | } 67 | 68 | try { 69 | $client.DownloadString($Url) 70 | } catch [System.Net.WebException] { 71 | throw "Request failed: ""$($_.Exception.Message)""" 72 | } 73 | 74 | <# 75 | .Synopsis 76 | Downloads content from given url as a string. 77 | .Description 78 | .Parameter Url 79 | URL to download 80 | .Parameter Credential 81 | Optional parameter to specified basic authorization credentials 82 | .Parameter Encoding 83 | Optional parameter to specified encoding of the content(e.g. Utf-8) 84 | .Example 85 | Get-WebContent http://chaliy.name 86 | 87 | Description 88 | ----------- 89 | Downloads content of the http://chaliy.name 90 | 91 | .Example 92 | Get-WebContent http://chaliy.name -Encoding Utf-8 93 | 94 | Description 95 | ----------- 96 | Downloads content of the http://chaliy.name with UTF-8 encoding 97 | 98 | .Link 99 | Send-WebContent 100 | 101 | #> 102 | } 103 | 104 | function Write-Url { 105 | [CmdletBinding()] 106 | Param( 107 | [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)] 108 | [String]$Url, 109 | [HashTable]$Data, 110 | [String]$Content, 111 | [TimeSpan]$Timeout = [TimeSpan]::FromMinutes(1), 112 | [Management.Automation.PSCredential]$Credential, 113 | [String]$ContentType 114 | ) 115 | Write-Verbose "Write-Url is considered obsolete. Please use Send-WebContent instead" 116 | if ($Content -ne ""){ 117 | Send-WebContent -Url:$Url -Content:$Content -Timeout:$Timeout -Credential:$Credential -ContentType:$ContentType 118 | } else { 119 | Send-WebContent -Url:$Url -Data:$Data -Timeout:$Timeout -Credential:$Credential -ContentType:$ContentType 120 | } 121 | <# 122 | .Synopsis 123 | POST values to URL 124 | .Description 125 | .Parameter Url 126 | URL to POST 127 | .Parameter Data 128 | Hashtable of the data to post. 129 | .Parameter Timeout 130 | Optional timeout value, by default timeout is 1 minute. 131 | .Parameter ContentType 132 | Adds Content-Type header to request 133 | .Example 134 | Write-Url http://chaliy.name -Data @{"Foo" = "Bar" } 135 | 136 | Description 137 | ----------- 138 | POST's to the http://chaliy.name as application/x-www-form-urlencoded 139 | 140 | #> 141 | } 142 | 143 | 144 | function Send-WebContent { 145 | [CmdletBinding()] 146 | Param( 147 | [Parameter(ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, Mandatory=$true, Position=0)] 148 | [String]$Url, 149 | [Parameter(ParameterSetName='Data')] 150 | [HashTable]$Data, 151 | [Parameter(ParameterSetName='Content')] 152 | [String]$Content, 153 | [TimeSpan]$Timeout = [TimeSpan]::FromMinutes(1), 154 | [Management.Automation.PSCredential]$Credential, 155 | [String]$ContentType, 156 | [HashTable]$Headers 157 | ) 158 | 159 | 160 | try{ 161 | $req = [Net.WebRequest]::Create($Url) 162 | $req.Method = "POST" 163 | $req.Timeout = $Timeout.TotalMilliseconds 164 | if ($Credential){ 165 | $ntwCred = $Credential.GetNetworkCredential() 166 | $auth = "Basic " + [Convert]::ToBase64String([Text.Encoding]::Default.GetBytes($ntwCred.UserName + ":" + $ntwCred.Password)) 167 | $req.Headers.Add("Authorization", $auth) 168 | $req.Credentials = $ntwCred 169 | $req.PreAuthenticate = $true 170 | } 171 | 172 | if ($ContentType -ne ""){ 173 | $req.ContentType = $ContentType 174 | } 175 | 176 | if ($Headers -ne $Null){ 177 | foreach($headerName in $Headers.Keys){ 178 | $req.Headers.Add($headerName, $Headers[$headerName]) 179 | } 180 | } 181 | 182 | switch($PSCmdlet.ParameterSetName) { 183 | Content { 184 | $reqStream = $req.GetRequestStream() 185 | $reqBody = [Text.Encoding]::Default.GetBytes($Content) 186 | $reqStream.Write($reqBody, 0, $reqBody.Length) 187 | } 188 | Data { 189 | Add-Type -AssemblyName System.Web 190 | $formData = [Web.HttpUtility]::ParseQueryString("") 191 | foreach($key in $Data.Keys){ 192 | $formData.Add($key, $Data[$key]) 193 | } 194 | $reqBody = [Text.Encoding]::Default.GetBytes($formData.ToString()) 195 | 196 | $req.ContentType = "application/x-www-form-urlencoded" 197 | $reqStream = $req.GetRequestStream() 198 | $reqStream.Write($reqBody, 0, $reqBody.Length) 199 | } 200 | } 201 | 202 | $reqStream.Close() 203 | 204 | $Method = $req.Method 205 | Write-Verbose "Execute $Method request" 206 | foreach($header in $req.Headers.Keys){ 207 | Write-Verbose ("$header : " + $req.Headers[$header]) 208 | } 209 | 210 | $resp = $req.GetResponse() 211 | $respStream = $resp.GetResponseStream() 212 | $respReader = (New-Object IO.StreamReader($respStream)) 213 | $respReader.ReadToEnd() 214 | } 215 | catch [Net.WebException]{ 216 | if ($_.Exception -ne $null -and $_.Exception.Response -ne $null) { 217 | $errorResult = $_.Exception.Response.GetResponseStream() 218 | $errorText = (New-Object IO.StreamReader($errorResult)).ReadToEnd() 219 | Write-Error "The remote server response: $errorText" 220 | } 221 | throw $_ 222 | } 223 | 224 | <# 225 | .Synopsis 226 | POST values to URL 227 | .Description 228 | .Parameter Url 229 | URL to POST 230 | .Parameter Data 231 | Hashtable of the data to post. 232 | .Parameter Timeout 233 | Optional timeout value, by default timeout is 1 minute. 234 | .Parameter ContentType 235 | Adds Content-Type header to the request 236 | .Parameter Headers 237 | Adds arbitrary headers to the request 238 | .Example 239 | Send-WebContent http://chaliy.name -Data @{"Foo" = "Bar" } 240 | 241 | Description 242 | ----------- 243 | POST's to the http://chaliy.name as application/x-www-form-urlencoded 244 | 245 | .Link 246 | Get-WebContent 247 | #> 248 | } 249 | 250 | 251 | Export-ModuleMember Get-Url #Obsolete 252 | Export-ModuleMember Write-Url #Obsolete 253 | 254 | Set-Alias gwc Get-WebContent 255 | Set-Alias swc Send-WebContent 256 | Export-ModuleMember Get-WebContent 257 | Export-ModuleMember Send-WebContent 258 | Export-ModuleMember -Alias gwc 259 | Export-ModuleMember -Alias swc -------------------------------------------------------------------------------- /Microsoft.PowerShell_profile.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | ############################### Module Imports ############################### 3 | ############################################################################## 4 | Import-Module -Name PsGet 5 | Import-Module -Name PSUrl 6 | Import-Module -Name Aliases 7 | Import-Module -Name PowerTab 8 | Import-Module -Name SyncMeUp 9 | Import-Module -Name Work -ErrorAction SilentlyContinue 10 | Import-Module -Name posh-git -ErrorAction SilentlyContinue 11 | Import-Module -Name posh-hg -ErrorAction SilentlyContinue 12 | Import-Module -Name posh-svn -ErrorAction SilentlyContinue 13 | ############################################################################## 14 | ############################### Module Imports ############################### 15 | ############################################################################## 16 | 17 | 18 | 19 | 20 | 21 | ############################################################################## 22 | ################################## Constants ################################# 23 | ############################################################################## 24 | $FANCY_SPACER = [char]11136 25 | $GIT_BRANCH = [char]11104 26 | $FANCY_X = [char]10008 27 | 28 | $DRIVE_DEFAULT_COLOR = "gray" 29 | $GIT_COLOR_DEFAULT = "green" 30 | 31 | $SHORT_FOLDER_NAME_SIZE = 3 32 | 33 | $colors = @{} 34 | $colors["blue"] = ([ConsoleColor]::Cyan, [ConsoleColor]::DarkBlue) 35 | $colors["green"] = ([ConsoleColor]::Green, [ConsoleColor]::DarkGreen) 36 | $colors["cyan"] = ([ConsoleColor]::Cyan, [ConsoleColor]::DarkCyan) 37 | $colors["red"] = ([ConsoleColor]::Red, [ConsoleColor]::DarkRed) 38 | $colors["magenta"] = ([ConsoleColor]::Magenta, [ConsoleColor]::DarkMagenta) 39 | $colors["yellow"] = ([ConsoleColor]::Yellow, [ConsoleColor]::DarkYellow) 40 | $colors["gray"] = ([ConsoleColor]::White, [ConsoleColor]::DarkGray) 41 | ############################################################################## 42 | ################################## Constants ################################# 43 | ############################################################################## 44 | 45 | 46 | 47 | 48 | 49 | ############################################################################## 50 | ################################# Main Methods ############################### 51 | ############################################################################## 52 | <# 53 | .SYNOPSIS 54 | Method called at each launch of Powershell 55 | 56 | .DESCRIPTION 57 | Sets up things needed in each console session, asside from prompt 58 | #> 59 | function Start-Up{ 60 | if(Test-Path -Path ~\.last) { 61 | (Get-Content -Path ~\.last) | set-location 62 | Remove-Item -Path ~\.last 63 | } 64 | 65 | # Makes git diff work 66 | $env:TERM = "msys" 67 | 68 | if(Get-Module Posh-Git) { 69 | Start-SshAgent -Quiet 70 | } 71 | } 72 | 73 | $driveColor = $DRIVE_DEFAULT_COLOR 74 | 75 | <# 76 | .SYNOPSIS 77 | Generates the prompt before each line in the console 78 | #> 79 | function Prompt { 80 | $drive = (Get-Drive (Get-Location).Path) 81 | 82 | switch -wildcard ($drive){ 83 | "C:\" { $driveColor = "blue" } 84 | "~\" { $driveColor = "blue"} 85 | "\\*" { $driveColor = "magenta" } 86 | } 87 | 88 | $lastColor = $driveColor 89 | 90 | # PowerLine starts with a space 91 | if(-not (Vanilla-Window)){ Write-Colors $driveColor " "} 92 | 93 | # Writes the drive portion 94 | Write-Colors $driveColor "$drive" 95 | Write-Colors $driveColor (Shorten-Path (Get-Location).Path) 96 | Write-Colors $driveColor " " 97 | 98 | if(Vanilla-Window){ #use the builtin posh-output 99 | Write-VcsStatus 100 | } else { #get ~fancy~ 101 | $status = Get-VCSStatus 102 | if ($status) { 103 | $lastColor = Write-Fancy-Vcs-Branches($status); 104 | } 105 | } 106 | 107 | # Writes the postfix to the prompt 108 | if(Vanilla-Window) { 109 | Write-Host -Object ">" -n 110 | } else { 111 | Write-Colors $lastColor $FANCY_SPACER -invert -noB 112 | } 113 | 114 | return " " 115 | } 116 | ############################################################################## 117 | ################################# Main Methods ############################### 118 | ############################################################################## 119 | 120 | 121 | 122 | 123 | ############################################################################## 124 | ################################ Helper Methods ############################## 125 | ############################################################################## 126 | 127 | function Get-VCSStatus{ 128 | $status = $null 129 | $vcs_systems = @{"posh-git" = "Get-GitStatus"; 130 | "posh-hg" = "Get-HgStatus"; 131 | "posh-svn" = "Get-SvnStatus" 132 | } 133 | 134 | foreach ($key in $vcs_systems.Keys) { 135 | $module = Get-Module -Name $key; 136 | if($module -and @($module).Count -gt 0){ 137 | $status = (Invoke-Expression -Command ($vcs_systems[$key])); 138 | if ($status) { 139 | return $status 140 | } 141 | } 142 | } 143 | return $status 144 | } 145 | 146 | 147 | function Write-Fancy-Vcs-Branches($status) { 148 | if ($status) { 149 | $color = $GIT_COLOR_DEFAULT 150 | 151 | # Determine Colors 152 | $localChanges = ($status.HasIndex -or $status.HasUntracked -or $status.HasWorking); #Git flags 153 | $localChanges = $localChanges -or (($status.Untracked -gt 0) -or ($status.Added -gt 0) -or ($status.Modified -gt 0) -or ($status.Deleted -gt 0) -or ($status.Renamed -gt 0)); #hg/svn flags 154 | 155 | if($localChanges) { $color = "yellow"} 156 | if(-not ($localChanges) -and ($status.AheadBy -gt 0)){ $color = "cyan" } #only affects git 157 | 158 | Write-Host -Object $FANCY_SPACER -ForegroundColor $colors[$driveColor][1] -BackgroundColor $colors[$color][1] -NoNewline 159 | Write-Colors $color " $GIT_BRANCH $($status.Branch) " 160 | return $color 161 | } 162 | } 163 | 164 | function Write-Colors{ 165 | param( 166 | [Parameter(Mandatory=$True)][string]$color, 167 | [string]$message, 168 | [switch]$newLine, 169 | [switch]$invert, 170 | [switch]$noBackground 171 | ) 172 | 173 | if(-not $colors[$color]){ 174 | throw "Not a valid color: $color" 175 | } 176 | 177 | $noBackground = ($noBackground -or (Vanilla-Window)) 178 | 179 | $FG = 0 180 | $BG = 1 181 | if($invert){ 182 | $FG = 1 183 | $BG = 0 184 | } 185 | 186 | 187 | if(-not ($noBackground)){ 188 | Write-Host -Object $message -ForegroundColor $colors[$color][$FG] -BackgroundColor $colors[$color][$BG] -NoNewline 189 | } else { 190 | Write-Host -Object $message -ForegroundColor $colors[$color][$FG] -NoNewline 191 | } 192 | 193 | if($newLine) { Write-Host -Object "" } 194 | } 195 | 196 | 197 | 198 | function Vanilla-Window{ 199 | if($env:PROMPT -or $env:ConEmuANSI){ 200 | # Console 201 | return $false 202 | } else { 203 | # Powershell 204 | return $true 205 | } 206 | } 207 | 208 | function Get-Home 209 | { 210 | return $HOME; 211 | } 212 | 213 | 214 | function Get-Provider( [string] $path ){ 215 | return (Get-Item $path).PSProvider.Name 216 | } 217 | 218 | 219 | 220 | function Get-Drive( [string] $path ) { 221 | $provider = Get-Provider $path 222 | 223 | if($provider -eq "FileSystem"){ 224 | $homedir = Get-Home; 225 | if( $path.StartsWith( $homedir ) ) { 226 | return "~\" 227 | } elseif( $path.StartsWith( "Microsoft.PowerShell.Core" ) ){ 228 | $parts = $path.Replace("Microsoft.PowerShell.Core\FileSystem::\\","").Split("\") 229 | return "\\$($parts[0])\$($parts[1])\" 230 | } else { 231 | $root = (Get-Item $path).Root 232 | if($root){ 233 | return $root 234 | } else { 235 | return $path.Split(":\")[0] + ":\" 236 | } 237 | } 238 | } else { 239 | return (Get-Item $path).PSDrive.Name + ":\" 240 | } 241 | } 242 | 243 | function Is-VCSRoot( $dir ) { 244 | return (Get-ChildItem -Path $dir.FullName -force .git) ` 245 | -Or (Get-ChildItem -Path $dir.FullName -force .hg) ` 246 | -Or (Get-ChildItem -Path $dir.FullName -force .svn) ` 247 | } 248 | 249 | function Shorten-Path([string] $path) { 250 | $provider = Get-Provider $path 251 | 252 | if($provider -eq "FileSystem"){ 253 | $result = @() 254 | $dir = Get-Item $path 255 | 256 | while( ($dir.Parent) -And ($dir.FullName -ne $HOME) ) { 257 | 258 | if( (Is-VCSRoot $dir) -Or ($result.length -eq 0) ) { 259 | $result = ,$dir.Name + $result 260 | } else { 261 | $result = ,$dir.Name.Substring(0, $SHORT_FOLDER_NAME_SIZE) + $result 262 | } 263 | 264 | $dir = $dir.Parent 265 | } 266 | return $result -join "\" 267 | } else { 268 | return $path.Replace((Get-Drive $path), "") 269 | } 270 | 271 | } 272 | 273 | 274 | function Colors { 275 | Write-Host -Object "INDIVIDUAL COLORS" 276 | [ConsoleColor].DeclaredMembers | Select-Object -Property Name ` 277 | | Where-Object {$_.Name -ne "value__" } ` 278 | | ForEach-Object { 279 | Write-Host -Object $_.Name -ForegroundColor $_.Name 280 | } 281 | 282 | Write-Host 283 | Write-Host -Object "NAMED PAIRS" 284 | $colors.Keys | ForEach-Object { 285 | Write-Host -Object " $_ " ` 286 | -ForegroundColor $colors[$_][0] ` 287 | -BackgroundColor $colors[$_][1] 288 | } 289 | } 290 | ############################################################################## 291 | ################################ Helper Methods ############################## 292 | ############################################################################## 293 | 294 | 295 | 296 | 297 | 298 | Start-Up # Executes the Start-Up function, better encapsulation 299 | Set-Alias -Name subl -Value "C:\Program Files\Sublime Text 3\sublime_text.exe" 300 | -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansionResources.ps1: -------------------------------------------------------------------------------- 1 | 2 | Data Resources { 3 | @{ 4 | ## Default resources 5 | setup_wizard_caption = "Launch the setup wizard to create a PowerTab configuration file and database?" 6 | setup_wizard_message = "PowerTab can be setup manually without the setup wizard." 7 | setup_wizard_choice_profile_directory = "&Profile Directory" 8 | setup_wizard_choice_install_directory = "&Installation Directory" 9 | setup_wizard_choice_appdata_directory = "&Application Data Directory" 10 | setup_wizard_choice_isostorage_directory = "Isolated &Storage" 11 | setup_wizard_choice_other_directory = "&Other Directory" 12 | setup_wizard_config_location_caption = "Where should the PowerTab configuration file and database be saved?" 13 | setup_wizard_config_location_message = "Any existing PowerTab configuration will be overwritten." 14 | setup_wizard_other_directory_prompt = "Enter the directory path for storing the PowerTab configuration file and database" 15 | setup_wizard_err_path_not_valid = "The given path's format is not supported." 16 | setup_wizard_add_to_profile = "Add the following text to the PowerShell profile to launch PowerTab with the saved configuration." 17 | setup_wizard_upgrade_existing_database_caption = "Upgrade existing tab completion database?" 18 | setup_wizard_upgrade_existing_database_message = "An existing tab completion database has been detected." 19 | update_tabexpansiondatabase_type_conf_caption = "Update .NET type list in tab completion database from currently loaded types?" 20 | update_tabexpansiondatabase_type_conf_inquire = "Loading .NET types." 21 | update_tabexpansiondatabase_type_conf_description = "Loading .NET types." 22 | update_tabexpansiondatabase_wmi_conf_caption = "Update WMI class list in tab completion database?" 23 | update_tabexpansiondatabase_wmi_conf_inquire = "Loading WMI classes." 24 | update_tabexpansiondatabase_wmi_conf_description = "Loading WMI classes." 25 | update_tabexpansiondatabase_wmi_activity = "Adding WMI Classes" 26 | update_tabexpansiondatabase_com_conf_caption = "Update COM class list in tab completion database?" 27 | update_tabexpansiondatabase_com_conf_inquire = "Loading COM classes." 28 | update_tabexpansiondatabase_com_conf_description = "Loading COM classes." 29 | update_tabexpansiondatabase_com_activity = "Adding COM Classes" 30 | update_tabexpansiondatabase_computer_conf_caption = "Update computer list in tab completion database from 'net view'?" 31 | update_tabexpansiondatabase_computer_conf_inquire = "Loading computer names." 32 | update_tabexpansiondatabase_computer_conf_description = "Loading computer names." 33 | update_tabexpansiondatabase_computer_activity = "Adding computer names" 34 | import_tabexpansiondatabase_ver_success = "TabExpansion database imported from '{0}'" 35 | export_tabexpansiondatabase_ver_success = "TabExpansion database exported to '{0}'" 36 | import_tabexpansionconfig_ver_success = "Configuration imported from '{0}'" 37 | export_tabexpansionconfig_ver_success = "Configuration exported to '{0}'" 38 | invoke_tabactivityindicator_prog_status = "PowerTab is retrieving or displaying available tab expansion options." 39 | global_choice_yes = "&Yes" 40 | global_choice_no = "&No" 41 | } 42 | } 43 | 44 | $ResourceFiles = @( 45 | @{"FileName"="Resources";"Variable"="Resources";"Cultures"=@("en-US")} 46 | ) 47 | 48 | 49 | ############ 50 | 51 | Function Update-Resource { 52 | [CmdletBinding()] 53 | param( 54 | [Parameter(Position = 0, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] 55 | [String] 56 | $FileName 57 | , 58 | [Parameter(Position = 1, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] 59 | [String] 60 | $Variable 61 | , 62 | [Parameter(Position = 2, Mandatory = $true, ValueFromPipelineByPropertyName = $true)] 63 | [System.Globalization.CultureInfo[]] 64 | $Cultures 65 | ) 66 | 67 | process { 68 | [System.Globalization.CultureInfo]$ControlCulture = "en" 69 | $ResourceCollection = @{} 70 | $BaseResources = (Get-Variable $Variable).Value 71 | $BaseKeys = $BaseResources.Keys.GetEnumerator() | Sort-Object 72 | 73 | ## Update control resources 74 | [String[]]$ModifiedKeys = @() 75 | [Bool]$Modified = $false 76 | $ControlResources = Import-Resources $ControlCulture -FileName $FileName 77 | $ControlKeys = $ControlResources.Keys.GetEnumerator() | Sort-Object 78 | Compare-Object $BaseKeys $ControlKeys -IncludeEqual | ForEach-Object { 79 | $Key = $_.InputObject 80 | switch -exact ($_.SideIndicator) { 81 | '<=' { 82 | ## This key is new since last update, add to control 83 | $ControlResources[$Key] = $BaseResources[$Key] 84 | $Modified = $true 85 | Write-Host "A new key has been identified: $Key" # TODO: Improve message 86 | } 87 | '=>' { 88 | ## This key was removed since last update, remove from control 89 | $ControlResources.Remove($Key) 90 | $Modified = $true 91 | Write-Host "A key has been removed: $Key" # TODO: Improve message 92 | } 93 | '==' { 94 | ## Key still here, check if value has changed 95 | if ($BaseResources[$Key] -cne $ControlResources[$Key]) { 96 | ## Value changed, add key to changed list and update control 97 | $ModifiedKeys += $Key 98 | $ControlResources[$Key] = $BaseResources[$Key] 99 | $Modified = $true 100 | Write-Host "The value for key '$Key' has been modified." # TODO: Improve message 101 | } 102 | } 103 | } 104 | } 105 | if ($Modified) { 106 | Export-Resources $ControlCulture $ControlResources -FileName $FileName 107 | } 108 | 109 | ## Update localized languages 110 | foreach ($Culture in $Cultures) { 111 | $Modified = $false 112 | $CultureResources = Import-Resources $Culture -FileName $FileName 113 | $CultureKeys = $CultureResources.Keys.GetEnumerator() | Sort-Object 114 | Compare-Object $BaseKeys $CultureKeys -IncludeEqual | ForEach-Object { 115 | $Key = $_.InputObject 116 | switch -exact ($_.SideIndicator) { 117 | '<=' { 118 | ## This key is new since last update, add to culture 119 | $CultureResources[$Key] = $BaseResources[$Key] 120 | $Modified = $true 121 | Write-Host "Adding key '$Key' to '$($Culture.Name)'" # TODO: Improve message 122 | Write-Verbose " Value: '$($BaseResources[$Key])'" 123 | } 124 | '=>' { 125 | ## This key was removed since last update, remove from culture 126 | $CultureResources.Remove($Key) 127 | $Modified = $true 128 | Write-Host "Removing key '$Key' from '$($Culture.Name)'" # TODO: Improve message 129 | } 130 | '==' { 131 | ## Key still here, check if value has changed 132 | if ($ModifiedKeys -contains $Key) { 133 | ## Value changed, add key to changed list and update culture 134 | Write-Host "Key '$Key' has changed, updating value in '$($Culture.Name)' from base resources" # TODO: Improve message 135 | Write-Verbose " Old value: '$($CultureResources[$Key])'" 136 | Write-Verbose " New value: '$($BaseResources[$Key])'" 137 | $CultureResources[$Key] = $BaseResources[$Key] 138 | $Modified = $true 139 | } 140 | } 141 | } 142 | } 143 | 144 | ## Update culture resources 145 | if ($Modified) { 146 | Export-Resources $Culture $CultureResources -FileName $FileName 147 | } 148 | } 149 | } 150 | } 151 | 152 | 153 | Function Import-Resources { 154 | [CmdletBinding()] 155 | param( 156 | [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] 157 | [ValidateNotNull()] 158 | [System.Globalization.CultureInfo] 159 | $Culture 160 | , 161 | [ValidateNotNullOrEmpty()] 162 | [String] 163 | $FileName = "Resources" 164 | ) 165 | 166 | process { 167 | if (Test-Path "$PSScriptRoot\$($Culture.Name)\$FileName.psd1") { 168 | Import-LocalizedData -BindingVariable "TempResources" -FileName $FileName -UICulture $Culture -ErrorAction SilentlyContinue 169 | $TempResources 170 | } else { 171 | @{} 172 | } 173 | 174 | trap [System.Management.Automation.PipelineStoppedException] { 175 | ## Pipeline was stopped 176 | break 177 | } 178 | } 179 | } 180 | 181 | 182 | Function Export-Resources { 183 | [CmdletBinding()] 184 | param( 185 | [Parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)] 186 | [ValidateNotNull()] 187 | [System.Globalization.CultureInfo] 188 | $Culture 189 | , 190 | [Parameter(Position = 1, Mandatory = $true)] 191 | [ValidateNotNull()] 192 | [Hashtable] 193 | $Resources 194 | , 195 | [ValidateNotNullOrEmpty()] 196 | [String] 197 | $FileName = "Resources" 198 | ) 199 | 200 | process { 201 | $Contents = "`@{`n ## $($Culture.Name)`r`n" 202 | foreach ($Key in ($Resources.Keys | Sort-Object)) { 203 | $Contents += " {0} = `"{1}`"`r`n" -f $Key,$Resources[$Key] 204 | } 205 | $Contents += "}" 206 | 207 | Set-Content -Path "$PSScriptRoot\$($Culture.Name)\$FileName.psd1" -Value $Contents 208 | 209 | trap [System.Management.Automation.PipelineStoppedException] { 210 | ## Pipeline was stopped 211 | break 212 | } 213 | } 214 | } 215 | 216 | <# 217 | $mod = (get-module -All PowerTab)[0] 218 | & $mod Update-Resources -verbose 219 | #> 220 | 221 | 222 | $ResourceFiles | ForEach-Object {Update-Resource @_} -------------------------------------------------------------------------------- /Modules/PowerTab/PowerTab.psm1: -------------------------------------------------------------------------------- 1 | param() 2 | 3 | ## Load forms library when not loaded 4 | if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object {$_.ManifestModule -like "System.Windows.Forms*"})) { 5 | [Void][System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 6 | } 7 | 8 | ## Load shares library 9 | if (-not ([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object {$_.ManifestModule -like "Shares.*"})) { 10 | [Void][System.Reflection.Assembly]::LoadFile((Join-Path $PSScriptRoot "Shares.dll")) 11 | } 12 | 13 | ######################### 14 | ## Cleanup 15 | ######################### 16 | 17 | $OldTabExpansion = Get-Content Function:TabExpansion 18 | $Module = $MyInvocation.MyCommand.ScriptBlock.Module 19 | $Module.OnRemove = { 20 | Set-Content Function:\TabExpansion -Value $OldTabExpansion 21 | } 22 | 23 | 24 | ######################### 25 | ## Private properties 26 | ######################### 27 | 28 | $dsTabExpansionDatabase = New-Object System.Data.DataSet 29 | 30 | $dsTabExpansionConfig = New-Object System.Data.DataSet 31 | 32 | $TabExpansionCommandRegistry = @{} 33 | 34 | $TabExpansionParameterRegistry = @{} 35 | 36 | $TabExpansionCommandInfoRegistry = @{} 37 | 38 | $TabExpansionParameterNameRegistry = @{} 39 | 40 | $ConfigFileName = "PowerTabConfig.xml" 41 | 42 | 43 | ######################### 44 | ## Public properties 45 | ######################### 46 | 47 | $PowerTabConfig = New-Object System.Management.Automation.PSObject 48 | 49 | $PowerTabError = New-Object System.Collections.ArrayList 50 | 51 | 52 | ######################### 53 | ## Functions 54 | ######################### 55 | 56 | Import-Module (Join-Path $PSScriptRoot "Lerch.PowerShell.dll") 57 | . (Join-Path $PSScriptRoot "TabExpansionResources.ps1") 58 | Import-LocalizedData -BindingVariable "Resources" -FileName "Resources" -ErrorAction SilentlyContinue 59 | . (Join-Path $PSScriptRoot "TabExpansionCore.ps1") 60 | . (Join-Path $PSScriptRoot "TabExpansionLib.ps1") 61 | . (Join-Path $PSScriptRoot "TabExpansionUtil.ps1") 62 | . (Join-Path $PSScriptRoot "TabExpansionHandlers.ps1") 63 | . (Join-Path $PSScriptRoot "ConsoleLib.ps1") 64 | . (Join-Path $PSScriptRoot "Handlers\PSClientManager.ps1") 65 | . (Join-Path $PSScriptRoot "Handlers\Robocopy.ps1") 66 | . (Join-Path $PSScriptRoot "Handlers\Utilities.ps1") 67 | 68 | 69 | ######################### 70 | ## Initialization code 71 | ######################### 72 | 73 | $ConfigurationPathParam = "" 74 | 75 | . { 76 | [CmdletBinding(SupportsShouldProcess = $false, 77 | SupportsTransactions = $false, 78 | ConfirmImpact = "None", 79 | DefaultParameterSetName = "")] 80 | param( 81 | [Parameter(Position = 0)] 82 | [String] 83 | $ConfigurationPath = "" 84 | ) 85 | 86 | if ($ConfigurationPath) { 87 | $script:ConfigurationPathParam = $ConfigurationPath 88 | } elseif ($PrivateData = (Parse-Manifest).PrivateData) { 89 | $script:ConfigurationPathParam = $PrivateData 90 | } elseif (Test-Path (Join-Path (Split-Path $Profile) $ConfigFileName)) { 91 | $script:ConfigurationPathParam = (Join-Path (Split-Path $Profile) $ConfigFileName) 92 | } elseif (Test-Path (Join-Path $PSScriptRoot $ConfigFileName)) { 93 | $script:ConfigurationPathParam = (Join-Path $PSScriptRoot $ConfigFileName) 94 | } 95 | } @args 96 | 97 | if ($ConfigurationPathParam) { 98 | if ((Test-Path $ConfigurationPathParam) -or ( 99 | ($ConfigurationPathParam -eq "IsolatedStorage") -and (Test-IsolatedStoragePath "PowerTab\$ConfigFileName"))) { 100 | Initialize-PowerTab $ConfigurationPathParam 101 | } else { 102 | ## Config specified, but does not exist 103 | Write-Warning "Configuration File does not exist: '$ConfigurationPathParam'" ## TODO: localize 104 | 105 | ## Create config and database 106 | New-TabExpansionConfig $ConfigurationPathParam 107 | CreatePowerTabConfig 108 | New-TabExpansionDatabase 109 | 110 | ## Update database 111 | Update-TabExpansionDataBase -Confirm 112 | 113 | ## Export changes 114 | Export-TabExpansionConfig 115 | Export-TabExpansionDatabase 116 | } 117 | } else { 118 | $Yes = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.global_choice_yes 119 | $No = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.global_choice_no 120 | $YesNoChoices = [System.Management.Automation.Host.ChoiceDescription[]]($No,$Yes) 121 | 122 | ## Launch setup wizard? 123 | $Answer = $Host.UI.PromptForChoice($Resources.setup_wizard_caption, $Resources.setup_wizard_message, $YesNoChoices, 1) 124 | if ($Answer) { 125 | ## Ask for location to place config and database 126 | $ProfileDir = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.setup_wizard_choice_profile_directory 127 | $InstallDir = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.setup_wizard_choice_install_directory 128 | $AppDataDir = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.setup_wizard_choice_appdata_directory 129 | $IsoStorageDir = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.setup_wizard_choice_isostorage_directory 130 | $OtherDir = New-Object System.Management.Automation.Host.ChoiceDescription $Resources.setup_wizard_choice_other_directory 131 | $LocationChoices = [System.Management.Automation.Host.ChoiceDescription[]]($ProfileDir,$InstallDir,$AppDataDir,$IsoStorageDir,$OtherDir) 132 | $Answer = $Host.UI.PromptForChoice($Resources.setup_wizard_config_location_caption, $Resources.setup_wizard_config_location_message, $LocationChoices, 0) 133 | $SetupConfigurationPath = switch ($Answer) { 134 | 0 {Split-Path $Profile} 135 | 1 {$PSScriptRoot} 136 | 2 {Join-Path ([System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData)) "PowerTab"} 137 | 3 {"IsolatedStorage"} 138 | 4 { 139 | $Path = Read-Host $Resources.setup_wizard_other_directory_prompt 140 | while ((-not $Path) -or -not (Test-Path -IsValid $Path)) { 141 | ## TODO: Maybe write-error instead? 142 | Write-Host $Resources.setup_wizard_err_path_not_valid -ForegroundColor $Host.PrivateData.ErrorForegroundColor ` 143 | -BackgroundColor $Host.PrivateData.ErrorBackgroundColor 144 | $Path = Read-Host $Resources.setup_wizard_other_directory_prompt 145 | } 146 | $Path 147 | } 148 | } 149 | 150 | ## Create config in chosen location 151 | if ($SetupConfigurationPath -eq "IsolatedStorage") { 152 | New-TabExpansionConfig $SetupConfigurationPath 153 | } else { 154 | New-TabExpansionConfig (Join-Path $SetupConfigurationPath $ConfigFileName) 155 | } 156 | CreatePowerTabConfig 157 | 158 | ## Profile text 159 | ## TODO: Ask to update profile 160 | $ProfileText = @" 161 | 162 | <############### Start of PowerTab Initialization Code ######################## 163 | Added to profile by PowerTab setup for loading of custom tab expansion. 164 | Import other modules after this, they may contain PowerTab integration. 165 | #> 166 | 167 | Import-Module "PowerTab" -ArgumentList "$(Join-Path $SetupConfigurationPath $ConfigFileName)" 168 | ################ End of PowerTab Initialization Code ########################## 169 | 170 | "@ 171 | Write-Host "" 172 | Write-Host $Resources.setup_wizard_add_to_profile 173 | Write-Host $ProfileText 174 | 175 | ## Create new database or load existing database 176 | if ($SetupConfigurationPath -eq "IsolatedStorage") { 177 | $SetupDatabasePath = $SetupConfigurationPath 178 | if (Test-IsolatedStoragePath "PowerTab\TabExpansion.xml") { 179 | $Answer = $Host.UI.PromptForChoice($Resources.setup_wizard_upgrade_existing_database_caption, $Resources.setup_wizard_upgrade_existing_database_message, $YesNoChoices, 1) 180 | } else { 181 | $Answer = 0 182 | } 183 | } else { 184 | $SetupDatabasePath = Join-Path $SetupConfigurationPath "TabExpansion.xml" 185 | if (Test-Path $SetupDatabasePath) { 186 | $Answer = $Host.UI.PromptForChoice($Resources.setup_wizard_upgrade_existing_database_caption, $Resources.setup_wizard_upgrade_existing_database_message, $YesNoChoices, 1) 187 | } else { 188 | $Answer = 0 189 | } 190 | } 191 | if ($Answer) { 192 | Import-TabExpansionDataBase $SetupDatabasePath 193 | } else { 194 | New-TabExpansionDatabase 195 | } 196 | 197 | ## Update database 198 | Update-TabExpansionDataBase -Confirm 199 | 200 | ## Export changes 201 | Export-TabExpansionConfig 202 | Export-TabExpansionDatabase 203 | Write-Host "" 204 | } else { 205 | New-TabExpansionConfig 206 | CreatePowerTabConfig 207 | New-TabExpansionDatabase 208 | } 209 | } 210 | 211 | if ($PowerTabConfig.Enabled) { 212 | . "$PSScriptRoot\TabExpansion.ps1" 213 | } 214 | 215 | if ($PowerTabConfig.ShowBanner) { 216 | $CurVersion = (Parse-Manifest).ModuleVersion 217 | Write-Host -ForegroundColor 'Yellow' "PowerTab version ${CurVersion} PowerShell TabExpansion Library" 218 | Write-Host -ForegroundColor 'Yellow' "Host: $($Host.Name)" 219 | Write-Host -ForegroundColor 'Yellow' "PowerTab Enabled: $($PowerTabConfig.Enabled)" 220 | } 221 | 222 | 223 | ## Exported functions, variables, etc. 224 | $ExcludedFuctions = @("Initialize-TabExpansion") 225 | $Functions = Get-Command "*-TabExpansion*","New-TabItem" | Where-Object {$ExcludedFuctions -notcontains $_.Name} 226 | #$Functions = Get-Command "*-*" | Where-Object {$ExcludedFuctions -notcontains $_.Name} 227 | Export-ModuleMember -Function $Functions -Variable PowerTabConfig, PowerTabError -Alias * 228 | 229 | <# 230 | TODOs 231 | - Support variables in path: $test = "C:"; $test\ 232 | ~ Expand items in a list: Get-Command -CommandType Cm,Fun 233 | - Assignment to strongly type variables: $ErrorActionPreference = 234 | - Alias and Variable replace: ls^A or $test^A 235 | 236 | Just ideas: 237 | - DateTime formats: ^D or 2008/01/20^D 238 | - Paste clipboard: ^V 239 | - Cut line: Get-Foo -Bar something^X --> 240 | - Cut word: Get-Foo -Bar something^Z --> Get-Foo -Bar 241 | 242 | - handle group start tokens ('{', '(', etc.) 243 | ~ Not detecting possitional parameters bound from pipeline 244 | #> 245 | -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansionUtil.ps1: -------------------------------------------------------------------------------- 1 | # TabExpansionUtil.ps1 2 | # 3 | # 4 | 5 | 6 | ######################### 7 | ## Private functions 8 | ######################### 9 | 10 | Function Out-DataGridView { 11 | [CmdletBinding()] 12 | param( 13 | [Parameter(Position = 0)] 14 | [String] 15 | $ReturnField 16 | , 17 | [Parameter(ValueFromPipeline = $true)] 18 | [Object[]] 19 | $InputObject 20 | ) 21 | 22 | begin { 23 | [Object[]]$Objects = @() 24 | } 25 | 26 | process { 27 | $Objects += $InputObject 28 | } 29 | 30 | end { 31 | # Make DataTable from Input 32 | $dt = New-Object System.Data.DataTable 33 | $First = $true 34 | foreach ($Item in $Objects) { 35 | $dr = $dt.NewRow() 36 | $Item.PSObject.get_Properties() | ForEach-Object { 37 | if ($first) { 38 | $col = New-Object System.Data.DataColumn 39 | $col.ColumnName = $_.Name.ToString() 40 | $dt.Columns.Add($col) 41 | } 42 | if ($_.Value -eq $null) { 43 | $dr.Item($_.Name) = "[empty]" 44 | } elseif ($_.IsArray) { 45 | $dr.Item($_.Name) =[String]::Join($_.Value ,";") 46 | } else { 47 | $dr.Item($_.Name) = $_.Value 48 | } 49 | } 50 | $dt.Rows.Add($dr) 51 | $First = $false 52 | } 53 | 54 | # Show Datatable in Form 55 | $form = New-Object System.Windows.Forms.Form 56 | $form.Size = new-Object System.Drawing.Size @(1000,600) 57 | $dg = New-Object System.Windows.Forms.DataGridView 58 | $dg.DataSource = $dt.PSObject.BaseObject 59 | $dg.Dock = [System.Windows.Forms.DockStyle]::Fill 60 | $dg.ColumnHeadersHeightSizeMode = [System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode]::AutoSize 61 | $dg.SelectionMode = 'FullRowSelect' 62 | $dg.add_DoubleClick({ 63 | $script:ret = $this.SelectedRows | ForEach-Object {$_.DataBoundItem["$ReturnField"]} 64 | $form.Close() 65 | }) 66 | 67 | $form.Text = "$($MyInvocation.Line)" 68 | $form.KeyPreview = $true 69 | $form.add_KeyDown({ 70 | if ($_.KeyCode -eq 'Enter') { 71 | $script:ret = $dg.SelectedRows | ForEach-Object {$_.DataBoundItem["$ReturnField"]} 72 | $form.Close() 73 | } elseif ($_.KeyCode -eq 'Escape') { 74 | $form.Close() 75 | } 76 | }) 77 | 78 | $form.Controls.Add($dg) 79 | $form.add_Shown({$form.Activate(); $dg.AutoResizeColumns()}) 80 | $script:ret = $null 81 | [Void]$form.ShowDialog() 82 | $script:ret 83 | } 84 | } 85 | 86 | ############ 87 | 88 | Function Resolve-Command { 89 | [CmdletBinding()] 90 | param( 91 | [Parameter(Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] 92 | [ValidateNotNullOrEmpty()] 93 | [String] 94 | $Name 95 | , 96 | [Switch] 97 | $CommandInfo 98 | ) 99 | 100 | process { 101 | $Command = "" 102 | 103 | ## Get command info, the where clause prevents problems with "?" wildcard 104 | if ($Name -match "\\") { 105 | ## Full name usage 106 | $Module = $Name.Substring(0, $Name.Indexof("\")) 107 | $CommandName = $Name.Substring($Name.Indexof("\") + 1, $Name.length - ($Name.Indexof("\") + 1)) 108 | if ($Module = Get-Module $Module) { 109 | $Command = @(Get-Command $CommandName -Module $Module -ErrorAction SilentlyContinue)[0] 110 | if (-not $Command) { 111 | ## Try to look up command with prefix 112 | $Prefix = Get-CommandPrefix $Module 113 | $Verb = $CommandName.Substring(0, $CommandName.Indexof("-")) 114 | $Noun = $CommandName.Substring($CommandName.Indexof("-") + 1, $CommandName.length - ($CommandName.Indexof("-") + 1)) 115 | $Command = @(Get-Command "$Verb-$Prefix$Noun" -ErrorAction SilentlyContinue)[0] 116 | } 117 | if (-not $Command) { 118 | ## Try looking in the module's exported command list 119 | $Command = $Module.ExportedCommands[$CommandName] 120 | } 121 | } 122 | } 123 | if (-not $Command) { 124 | if ($Name.Contains("?")) { 125 | $Command = @(Get-Command $Name | Where-Object {$_.Name -eq $Name})[0] 126 | } else { 127 | $Command = @(Get-Command $Name)[0] 128 | } 129 | } 130 | 131 | if ($Command.CommandType -eq "Alias") { 132 | $Command = $Command.ResolvedCommand 133 | } 134 | 135 | ## Return result 136 | if ($CommandInfo) { 137 | $Command 138 | } else { 139 | if ($Command.CommandType -eq "ExternalScript") { 140 | $Command.Path 141 | } else { 142 | $Command.Name 143 | } 144 | } 145 | 146 | trap [System.Management.Automation.PipelineStoppedException] { 147 | ## Pipeline was stopped 148 | break 149 | } 150 | } 151 | } 152 | 153 | Function Resolve-Parameter { 154 | [CmdletBinding(DefaultParameterSetName = "Command")] 155 | param( 156 | [Parameter(ParameterSetName = "Command", Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] 157 | [ValidateNotNullOrEmpty()] 158 | [String] 159 | $Command 160 | , 161 | [Parameter(ParameterSetName = "CommandInfo", Mandatory = $true, Position = 0)] 162 | [ValidateNotNull()] 163 | [System.Management.Automation.CommandInfo] 164 | $CommandInfo 165 | , 166 | [Parameter(Mandatory = $true, Position = 1, ValueFromPipelineByPropertyName = $true)] 167 | [ValidateNotNullOrEmpty()] 168 | [String] 169 | $Name 170 | , 171 | [Switch] 172 | $ParameterInfo 173 | ) 174 | 175 | process { 176 | ## Remove leading dash if it exists 177 | $Name = $Name -replace '^-' 178 | 179 | ## Get command info 180 | if ($PSCmdlet.ParameterSetName -eq "Command") { 181 | $CommandInfo = Resolve-Command $Command -CommandInfo 182 | } elseif ($PSCmdlet.ParameterSetName -eq "CommandInfo") { 183 | if ($CommandInfo -eq $null) {return} 184 | } 185 | 186 | ## Check if this is a real parameter name and not an alias 187 | if ($CommandInfo.Parameters["$Name"]) { 188 | $Parameter = $CommandInfo.Parameters["$Name"] 189 | } else { 190 | ## Possible alias 191 | $Parameter = @($CommandInfo.Parameters.Values | Where-Object {$_.Aliases -contains $Name})[0] 192 | } 193 | 194 | ## If no parameter found, it could be an abreviated name (-comp instead of -ComputerName) 195 | if (-not $Parameter) { 196 | $Parameter = @($CommandInfo.Parameters.Values | Where-Object {$_.Name -like "$Name*"})[0] 197 | } 198 | 199 | ## Return result 200 | if ($ParameterInfo) { 201 | $Parameter 202 | } else { 203 | $Parameter.Name 204 | } 205 | 206 | trap [System.Management.Automation.PipelineStoppedException] { 207 | ## Pipeline was stopped 208 | break 209 | } 210 | } 211 | } 212 | 213 | Function Resolve-PositionalParameter { 214 | param( 215 | [Parameter(Mandatory = $true, Position = 0)] 216 | [ValidateNotNull()] 217 | [Object] 218 | $Context 219 | ) 220 | 221 | process { 222 | if ($TabExpansionCommandInfoRegistry[$Context.Command]) { 223 | $ScriptBlock = $TabExpansionCommandInfoRegistry[$Context.Command] 224 | $CommandInfo = & $ScriptBlock $Context 225 | if (-not $CommandInfo) {throw "foo"} ## TODO 226 | } elseif ($Context.CommandInfo) { 227 | $CommandInfo = $Context.CommandInfo 228 | } else { 229 | return $Context 230 | } 231 | 232 | foreach ($ParameterSet in $CommandInfo.ParameterSets) { 233 | $PositionalParameters = @($ParameterSet.Parameters | 234 | Where-Object {($_.Position -ge 0) -and ($Context.OtherParameters.Keys -notcontains $_.Name)} | Sort-Object Position) 235 | 236 | if (($Context.PositionalParameter -ge 0) -and ($Context.PositionalParameter -lt $PositionalParameters.Count)) { 237 | ## TODO: Try to figure out a better parameter? 238 | $Context.Parameter = $PositionalParameters[$Context.PositionalParameter].Name 239 | #$Context.PositionalParameter -= 1 240 | break 241 | } elseif ($PositionalParameters[-1].ValueFromRemainingArguments) { 242 | $Context.Parameter = $PositionalParameters[-1].Name 243 | break 244 | } 245 | } 246 | 247 | $Context 248 | 249 | trap [System.Management.Automation.PipelineStoppedException] { 250 | ## Pipeline was stopped 251 | break 252 | } 253 | } 254 | } 255 | 256 | Function Resolve-InternalCommandName { 257 | [CmdletBinding(DefaultParameterSetName = "Command")] 258 | param( 259 | [Parameter(ParameterSetName = "Command", Mandatory = $true, Position = 0, ValueFromPipelineByPropertyName = $true)] 260 | [ValidateNotNullOrEmpty()] 261 | [String] 262 | $Command 263 | , 264 | [Parameter(ParameterSetName = "CommandInfo", Mandatory = $true, Position = 0)] 265 | [ValidateNotNull()] 266 | [System.Management.Automation.CommandInfo] 267 | $CommandInfo 268 | ) 269 | 270 | process { 271 | ## Get command info 272 | if ($PSCmdlet.ParameterSetName -eq "Command") { 273 | $CommandInfo = Resolve-Command $Command -CommandInfo 274 | } 275 | 276 | ## Return result 277 | if ($Prefix = Get-CommandPrefix $CommandInfo) { 278 | $Verb = $CommandInfo.Name.Substring(0, $CommandInfo.Name.Indexof("-")) 279 | $Noun = $CommandInfo.Name.Substring($CommandInfo.Name.Indexof("-") + 1, $CommandInfo.Name.length - ($CommandInfo.Name.Indexof("-") + 1)) 280 | $Noun = $Noun -replace [Regex]::Escape($Prefix) 281 | $InternalName = "$Verb-$Noun" 282 | } else { 283 | $InternalName = $CommandInfo.Name 284 | } 285 | 286 | New-Object PSObject -Property @{"InternalName"=$InternalName;"Module"=$CommandInfo.Module} 287 | 288 | trap [System.Management.Automation.PipelineStoppedException] { 289 | ## Pipeline was stopped 290 | break 291 | } 292 | } 293 | } 294 | 295 | Function Get-CommandPrefix { 296 | [CmdletBinding(DefaultParameterSetName = "Command")] 297 | param( 298 | [Parameter(ParameterSetName = "Command", Mandatory = $true, Position = 0)] 299 | [ValidateNotNull()] 300 | [String] 301 | $Command 302 | , 303 | [Parameter(ParameterSetName = "CommandInfo", Mandatory = $true, Position = 0)] 304 | [ValidateNotNull()] 305 | [System.Management.Automation.CommandInfo] 306 | $CommandInfo 307 | , 308 | [Parameter(ParameterSetName = "ModuleInfo", Mandatory = $true, Position = 0)] 309 | [ValidateNotNull()] 310 | [System.Management.Automation.PSModuleInfo] 311 | $ModuleInfo 312 | ) 313 | 314 | process { 315 | ## Get module info 316 | if ($PSCmdlet.ParameterSetName -eq "Command") { 317 | $ModuleInfo = (Resolve-Command $Command -CommandInfo).Module 318 | } elseif (($PSCmdlet.ParameterSetName -eq "CommandInfo") -and $CommandInfo.Module) { 319 | $ModuleInfo = Get-Module $CommandInfo.Module 320 | } 321 | 322 | if ($ModuleInfo) { 323 | $CommandGroups = $ModuleInfo.ExportedFunctions.Values + 324 | (Get-Command -Module $ModuleInfo -CommandType Function,Filter,Cmdlet) | Group-Object {$_.Definition} 325 | $Prefixes = foreach ($Group in $CommandGroups) { 326 | $Names = $Group.Group | Select-Object -ExpandProperty Name 327 | $TempNoun = (@($Names)[0] -split "-")[1] 328 | foreach($Name in $Names) { 329 | if ($Name -match "-") { 330 | $PossiblePrefix = $Name.SubString($Name.IndexOf("-") + 1, $Name.LastIndexOf($TempNoun) - $Name.IndexOf("-") - 1) 331 | if ($PossiblePrefix) { 332 | $PossiblePrefix 333 | } 334 | } 335 | } 336 | } 337 | 338 | if ($Prefixes.Count) { 339 | $Prefixes | Select-Object -Unique 340 | } else { 341 | $Prefixes 342 | } 343 | } 344 | 345 | trap [System.Management.Automation.PipelineStoppedException] { 346 | ## Pipeline was stopped 347 | break 348 | } 349 | } 350 | } 351 | 352 | ############ 353 | 354 | Function Resolve-TabExpansionParameterValue { 355 | param( 356 | [String]$Value 357 | ) 358 | 359 | switch -regex ($Value) { 360 | '^\$' { 361 | [String](Invoke-Expression $_) 362 | break 363 | } 364 | '^\(.*\)$' { 365 | [String](Invoke-Expression $_) 366 | break 367 | } 368 | Default {$Value} 369 | } 370 | } 371 | 372 | ############ 373 | 374 | ## Slightly modified from http://blog.sapien.com/index.php/2009/08/24/writing-form-centered-scripts-with-primalforms/ 375 | Function Get-GuiDate { 376 | param( 377 | [Int]$DisplayMode = 1, # number of months to show 378 | [Int]$SelectionCount = 0, # number of days that can be selected 379 | [DateTime]$TodayDate = $(Get-Date), # sets default selected date 380 | [DateTime]$DateSelected = $TodayDate, # sets default selected date 381 | [Int]$FirstDayofWeek = -1, # -1 used default - calendar dayofweek, NOT datetime 382 | [DateTime[]]$Bold = @(), # Array of bolded dates to add 383 | [DateTime[]]$YBold = @(), # annual bolded dates to add 384 | [DateTime[]]$MBold = @(), # monthly bolded dates to add 385 | [Int]$ScrollBy = $DisplayMode, # number of months to scroll by; 0 = screenfull 386 | [Switch]$WeekNumbers, # Show numeric week of year on the display 387 | [String]$Title = "Get-GuiDate", 388 | [Switch]$NoTodayCircle, 389 | [DateTime]$MinDate = "1753-01-01", 390 | [DateTime]$MaxDate = "9998-12-31" 391 | ) 392 | 393 | [System.Windows.Forms.Application]::EnableVisualStyles() 394 | # Is this voodoo code, or not? 395 | [System.Windows.Forms.Application]::DoEvents() 396 | 397 | $cal = New-Object Windows.Forms.MonthCalendar 398 | $cal.SetDate($DateSelected) 399 | $cal.TodayDate = $TodayDate 400 | if ($SelectionCount -lt 1) {$SelectionCount = [int]::MaxValue} 401 | $cal.MaxSelectionCount = $SelectionCount 402 | $cal.MinDate = $MinDate 403 | $cal.MaxDate = $MaxDate 404 | $cal.ScrollChange = $ScrollBy 405 | $cal.ShowTodayCircle = $true 406 | if ($FirstDayofWeek -eq -1) {$FirstDayofWeek = [System.Windows.Forms.Day]::Default} 407 | $cal.FirstDayofWeek = [System.Windows.Forms.Day]$FirstDayofWeek 408 | $cal.ShowWeekNumbers = $WeekNumbers 409 | if ($NoTodayCircle) {$cal.ShowTodayCircle = $False} 410 | 411 | # Provides clean display geometry 412 | switch -regex ($DisplayMode) { 413 | "^1$" {$cal.CalendarDimensions = "1,1"} 414 | "^2$" {$cal.CalendarDimensions = "2,1"} 415 | "^3$" { $cal.CalendarDimensions = "3,1"} 416 | "^4$" {$cal.CalendarDimensions = "2,2"} 417 | "^[56]$" {$cal.CalendarDimensions = "3,2"} 418 | "^[78]$" {$cal.CalendarDimensions = "4,2"} 419 | "^9$" {$cal.CalendarDimensions = "3,3"} 420 | "^1[012]$" {$cal.CalendarDimensions = "4,3"} 421 | default {$cal.CalendarDimensions = "4,4"} 422 | } 423 | 424 | if ($Bold) {$cal.BoldedDates = $Bold} 425 | if ($YBold) {$cal.AnnuallyBoldedDates = $YBold} 426 | if ($MBold) {$cal.MonthlyBoldedDates = $MBold} 427 | 428 | $form = New-Object Windows.Forms.Form 429 | $form.AutoSize = $form.TopMost = $form.KeyPreview = $True 430 | $form.MaximizeBox = $form.MinimizeBox = $False 431 | $form.AutoSizeMode = "GrowAndShrink" 432 | $form.Controls.Add($cal) 433 | $form.BackColor = [System.Drawing.Color]::White 434 | $form.Text = $Title 435 | 436 | # We'll handle escape or enter to get out. 437 | $Escaped = $False; 438 | $form.Add_KeyDown([System.Windows.Forms.KeyEventHandler]{ 439 | if ($_.KeyCode -eq "Escape") { 440 | $Escaped = $true; $form.Close() 441 | } elseif ($_.KeyCode -eq "Enter") { 442 | $form.Close() 443 | } 444 | }) 445 | 446 | # Ensures the form is on top, is active, and then shows it. 447 | # After calling ShowDialog(), the script is blocked until 448 | # the form is no longer visible. 449 | $form.Add_Shown({$form.Activate()}) 450 | [Void]$form.ShowDialog() 451 | 452 | # If they didn't press Escape, output the selection range 453 | # as a series of dates. 454 | if (!$Escaped) { 455 | for( 456 | $day = $cal.SelectionRange.Start; 457 | $day -le $cal.SelectionRange.End; 458 | $day = $day.AddDays(1) 459 | ) 460 | { 461 | $day 462 | } 463 | } 464 | 465 | # 2009-08-27 466 | # -initialized $Escaped and removed $ShowTodayCircle (thanks, tojo2000) 467 | # -modified $FirstDayOfWeek so casts don't occur until after Forms library loaded. 468 | } 469 | 470 | Function Test-IsolatedStoragePath { 471 | [CmdletBinding()] 472 | param( 473 | [Alias("LiteralPath")] 474 | [Parameter(Mandatory = $true, Position = 0)] 475 | [ValidateNotNullOrEmpty()] 476 | [String] 477 | $Path 478 | ) 479 | 480 | process { 481 | try { 482 | $UserIsoStorage = [System.IO.IsolatedStorage.IsolatedStorageFile]::GetUserStoreForAssembly() 483 | if ($UserIsoStorage.GetFileNames($Path)) { 484 | $true 485 | } else { 486 | $false 487 | } 488 | } catch { 489 | $false 490 | } 491 | } 492 | } 493 | 494 | Function Open-IsolatedStorageFile { 495 | [CmdletBinding()] 496 | param( 497 | [Alias("Path")] 498 | [Parameter(Mandatory = $true, Position = 0)] 499 | [ValidateNotNullOrEmpty()] 500 | [String] 501 | $LiteralPath 502 | , 503 | [Switch] 504 | $Writable 505 | ) 506 | 507 | process { 508 | if ($Writable) { 509 | $UserIsoStorage = [System.IO.IsolatedStorage.IsolatedStorageFile]::GetUserStoreForAssembly() 510 | if (Test-IsolatedStoragePath $LiteralPath) { 511 | New-Object System.IO.IsolatedStorage.IsolatedStorageFileStream($LiteralPath, [System.IO.FileMode]::Truncate, $UserIsoStorage) 512 | } else { 513 | New-Object System.IO.IsolatedStorage.IsolatedStorageFileStream($LiteralPath, [System.IO.FileMode]::Create, $UserIsoStorage) 514 | } 515 | } else { 516 | $UserIsoStorage = [System.IO.IsolatedStorage.IsolatedStorageFile]::GetUserStoreForAssembly() 517 | New-Object System.IO.IsolatedStorage.IsolatedStorageFileStream($LiteralPath, [System.IO.FileMode]::Open, $UserIsoStorage) 518 | } 519 | } 520 | } 521 | 522 | Function New-IsolatedStorageDirectory { 523 | [CmdletBinding()] 524 | param( 525 | [Alias("Path")] 526 | [Parameter(Mandatory = $true, Position = 0)] 527 | [ValidateNotNullOrEmpty()] 528 | [String] 529 | $LiteralPath 530 | ) 531 | 532 | process { 533 | $UserIsoStorage = [System.IO.IsolatedStorage.IsolatedStorageFile]::GetUserStoreForAssembly() 534 | if (-not $UserIsoStorage.GetDirectoryNames($LiteralPath)) {$UserIsoStorage.CreateDirectory($LiteralPath)} 535 | } 536 | } 537 | 538 | Function Get-IsolatedStorage { 539 | } 540 | 541 | 542 | ########## 543 | # Here there be hacks (from Jaykul) 544 | ########## 545 | 546 | Function Parse-Manifest { 547 | $Manifest = Get-Content "$PSScriptRoot\PowerTab.psd1" | Where-Object {$_ -notmatch '^\s*#'} 548 | $ModuleManifest = "Data {`n" + ($Manifest -join "`r`n") + "`n}" 549 | $ExecutionContext.SessionState.InvokeCommand.NewScriptBlock($ModuleManifest).Invoke()[0] 550 | } 551 | 552 | Function Find-Module { 553 | [CmdletBinding()] 554 | param( 555 | [String[]]$Name = "*" 556 | , 557 | [Switch]$All 558 | ) 559 | 560 | foreach ($n in $Name) { 561 | $folder = [System.IO.Path]::GetDirectoryName($n) 562 | $n = [System.IO.Path]::GetFileName($n) 563 | $ModulePaths = Get-ModulePath 564 | 565 | if ($folder) { 566 | $ModulePaths = Join-Path $ModulePaths $folder 567 | } 568 | 569 | ## Note: the order of these is important. They need to be in the order they'd be loaded by the system 570 | $Files = @(Get-ChildItem -Path $ModulePaths -Recurse -Filter "$n.ps?1" -EA 0; Get-ChildItem -Path $ModulePaths -Recurse -Filter "$n.dll" -EA 0) 571 | $Files | Where-Object { 572 | $parent = [System.IO.Path]::GetFileName( $_.PSParentPath ) 573 | return $all -or ($parent -eq $_.BaseName) -or ($folder -and ($parent -eq ([System.IO.Path]::GetFileName($folder))) -and ($n -eq $_.BaseName)) 574 | } | Group-Object PSParentPath | ForEach-Object {@($_.Group)[0]} 575 | } 576 | } 577 | 578 | # | Sort-Object {switch ($_.Extension) {".psd1"{1} ".psm1"{2}}}) 579 | Function Get-ModulePath { 580 | $Env:PSModulePath -split ";" | ForEach-Object {"{0}\" -f $_.TrimEnd('\','/')} | Select-Object -Unique | Where-Object {Test-Path $_} 581 | } -------------------------------------------------------------------------------- /Modules/PowerTab/ConsoleLib.ps1: -------------------------------------------------------------------------------- 1 | # ConsoleLib.ps1 2 | # 3 | # 4 | 5 | 6 | Function Out-ConsoleList { 7 | #[CmdletBinding()] 8 | param( 9 | [Parameter(Position = 1)] 10 | [ValidateNotNull()] 11 | [String] 12 | $LastWord = '' 13 | , 14 | [Parameter(Position = 2)] 15 | [ValidateNotNull()] 16 | [String] 17 | $ReturnWord = '' ## Text to return with filter if list closes without a selected item 18 | , 19 | [Parameter(ValueFromPipeline = $true)] 20 | [ValidateNotNull()] 21 | [Object[]] 22 | $InputObject = @() 23 | , 24 | [Switch] 25 | $ForceList 26 | ) 27 | 28 | begin { 29 | [Object[]]$Content = @() 30 | } 31 | 32 | process { 33 | $Content += $InputObject 34 | } 35 | 36 | end { 37 | if (-not $ReturnWord) {$ReturnWord = $LastWord} 38 | 39 | ## If contents contains less than minimum options, then forward contents without displaying console list 40 | if (($Content.Length -lt $PowerTabConfig.MinimumListItems) -and (-not $ForceList)) { 41 | $Content | Select-Object -ExpandProperty Value 42 | return 43 | } 44 | 45 | ## Create console list 46 | $Filter = '' 47 | $ListHandle = New-ConsoleList $Content $PowerTabConfig.Colors.BorderColor $PowerTabConfig.Colors.BorderBackColor ` 48 | $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 49 | 50 | ## Preview of current filter, shows up where cursor is at 51 | $PreviewBuffer = ConvertTo-BufferCellArray "$Filter " $PowerTabConfig.Colors.FilterColor $Host.UI.RawUI.BackgroundColor 52 | $Preview = New-Buffer $Host.UI.RawUI.CursorPosition $PreviewBuffer 53 | 54 | Function Add-Status { 55 | ## Title buffer, shows the last word in header of console list 56 | $TitleBuffer = ConvertTo-BufferCellArray " $LastWord" $PowerTabConfig.Colors.BorderTextColor $PowerTabConfig.Colors.BorderBackColor 57 | $TitlePosition = $ListHandle.Position 58 | $TitlePosition.X += 2 59 | $TitleHandle = New-Buffer $TitlePosition $TitleBuffer 60 | 61 | ## Filter buffer, shows the current filter after the last word in header of console list 62 | $FilterBuffer = ConvertTo-BufferCellArray "$Filter " $PowerTabConfig.Colors.FilterColor $PowerTabConfig.Colors.BorderBackColor 63 | $FilterPosition = $ListHandle.Position 64 | $FilterPosition.X += (3 + $LastWord.Length) 65 | $FilterHandle = New-Buffer $FilterPosition $FilterBuffer 66 | 67 | ## Status buffer, shows at footer of console list. Displays selected item index, index range of currently visible items, and total item count. 68 | $StatusBuffer = ConvertTo-BufferCellArray "[$($ListHandle.SelectedItem + 1)] $($ListHandle.FirstItem + 1)-$($ListHandle.LastItem + 1) [$($Content.Length)]" $PowerTabConfig.Colors.BorderTextColor $PowerTabConfig.Colors.BorderBackColor 69 | $StatusPosition = $ListHandle.Position 70 | $StatusPosition.X += 2 71 | $StatusPosition.Y += ($listHandle.ListConfig.ListHeight - 1) 72 | $StatusHandle = New-Buffer $StatusPosition $StatusBuffer 73 | 74 | } 75 | . Add-Status 76 | 77 | ## Select the first item in the list 78 | $SelectedItem = 0 79 | Set-Selection 1 ($SelectedItem + 1) ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 80 | 81 | ## Listen for first key press 82 | $Key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown') 83 | 84 | ## Process key presses 85 | $Continue = $true 86 | while ($Key.VirtualKeyCode -ne 27 -and $Continue -eq $true) { 87 | if (-not $HasChild) { 88 | if ($OldFilter -ne $Filter) { 89 | $Preview.Clear() 90 | $PreviewBuffer = ConvertTo-BufferCellArray "$Filter " $PowerTabConfig.Colors.FilterColor $Host.UI.RawUI.BackgroundColor 91 | $Preview = New-Buffer $Preview.Location $PreviewBuffer 92 | } 93 | $OldFilter = $Filter 94 | } 95 | $Shift = $Key.ControlKeyState.ToString() 96 | $HasChild = $false 97 | switch ($Key.VirtualKeyCode) { 98 | 9 { ## Tab 99 | ## In Visual Studio, Tab acts like Enter 100 | if ($PowerTabConfig.VisualStudioTabBehavior) { 101 | ## Expand with currently selected item 102 | $ListHandle.Items[$ListHandle.SelectedItem].Value 103 | $Continue = $false 104 | break 105 | } else { 106 | if ($Shift -match 'ShiftPressed') { 107 | Move-Selection -1 ## Up 108 | } else { 109 | Move-Selection 1 ## Down 110 | } 111 | break 112 | } 113 | } 114 | 38 { ## Up Arrow 115 | if ($Shift -match 'ShiftPressed') { 116 | ## Fast scroll selected 117 | if ($PowerTabConfig.FastScrollItemCount -gt ($ListHandle.Items.Count - 1)) { 118 | $Count = ($ListHandle.Items.Count - 1) 119 | } else { 120 | $Count = $PowerTabConfig.FastScrollItemCount 121 | } 122 | Move-Selection (- $Count) 123 | } else { 124 | Move-Selection -1 125 | } 126 | break 127 | } 128 | 40 { ## Down Arrow 129 | if ($Shift -match 'ShiftPressed') { 130 | ## Fast scroll selected 131 | if ($PowerTabConfig.FastScrollItemCount -gt ($ListHandle.Items.Count - 1)) { 132 | $Count = ($ListHandle.Items.Count - 1) 133 | } else { 134 | $Count = $PowerTabConfig.FastScrollItemCount 135 | } 136 | Move-Selection $Count 137 | } else { 138 | Move-Selection 1 139 | } 140 | break 141 | } 142 | 33 { ## Page Up 143 | $Count = $ListHandle.Items.Count 144 | if ($Count -gt $ListHandle.MaxItems) { 145 | $Count = $ListHandle.MaxItems 146 | } 147 | Move-Selection (-($Count - 1)) 148 | break 149 | } 150 | 34 { ## Page Down 151 | $Count = $ListHandle.Items.Count 152 | if ($Count -gt $ListHandle.MaxItems) { 153 | $Count = $ListHandle.MaxItems 154 | } 155 | Move-Selection ($Count - 1) 156 | break 157 | } 158 | 39 { ## Right Arrow 159 | ## Add a new character (the one right after the current filter string) from currently selected item 160 | $Char = $ListHandle.Items[$ListHandle.SelectedItem].Text[($LastWord.Length + $Filter.Length + 1)] 161 | $Filter += $Char 162 | 163 | $Old = $Items.Length 164 | $Items = $Content -match ([Regex]::Escape("$LastWord$Filter") + '.*') 165 | $New = $Items.Length 166 | if ($New -lt 1) { 167 | ## If new filter results in no items, sound error beep and remove character 168 | Write-Host "`a" -NoNewline 169 | $Filter = $Filter.SubString(0, $Filter.Length - 1) 170 | } else { 171 | if ($Old -ne $New) { 172 | ## Update console list contents 173 | $ListHandle.Clear() 174 | $ListHandle = New-ConsoleList $Items $PowerTabConfig.Colors.BorderColor $PowerTabConfig.Colors.BorderBackColor ` 175 | $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 176 | ## Update status buffers 177 | . Add-Status 178 | } 179 | ## Select first item of new list 180 | $SelectedItem = 0 181 | Set-Selection 1 ($SelectedItem + 1) ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 182 | $Host.UI.Write($PowerTabConfig.Colors.FilterColor, $Host.UI.RawUI.BackgroundColor, $Char) 183 | } 184 | break 185 | } 186 | {(8,37 -contains $_)} { # Backspace or Left Arrow 187 | if ($Filter) { 188 | ## Remove last character from filter 189 | $Filter = $Filter.SubString(0, $Filter.Length - 1) 190 | $Host.UI.Write([char]8) 191 | Write-Line ($Host.UI.RawUI.CursorPosition.X) ($Host.UI.RawUI.CursorPosition.Y - $Host.UI.RawUI.WindowPosition.Y) " " $PowerTabConfig.Colors.FilterColor $Host.UI.RawUI.BackgroundColor 192 | 193 | $Old = $Items.Length 194 | $Items = @($Content | Where-Object {$_.Text -match ([Regex]::Escape("$LastWord$Filter") + '.*')}) 195 | $New = $Items.Length 196 | if ($Old -ne $New) { 197 | ## If the item list changed, update the contents of the console list 198 | $ListHandle.Clear() 199 | $ListHandle = New-ConsoleList $Items $PowerTabConfig.Colors.BorderColor $PowerTabConfig.Colors.BorderBackColor ` 200 | $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 201 | ## Update status buffers 202 | . Add-Status 203 | } 204 | ## Select first item of new list 205 | $SelectedItem = 0 206 | Set-Selection 1 ($SelectedItem + 1) ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 207 | } else { 208 | if ($PowerTabConfig.CloseListOnEmptyFilter) { 209 | $Key.VirtualKeyCode = 27 210 | $Continue = $false 211 | } else { 212 | Write-Host "`a" -NoNewline 213 | } 214 | } 215 | break 216 | } 217 | 190 { ## Period 218 | if ($PowerTabConfig.DotComplete -and -not $PowerTabFileSystemMode) { 219 | if ($PowerTabConfig.AutoExpandOnDot) { 220 | ## Expand with currently selected item 221 | $Host.UI.Write($Host.UI.RawUI.ForegroundColor, $Host.UI.RawUI.BackgroundColor, ($ListHandle.Items[$ListHandle.SelectedItem].Value.SubString($LastWord.Length + $Filter.Length) + '.')) 222 | $ListHandle.Clear() 223 | $LinePart = $Line.SubString(0, $Line.Length - $LastWord.Length) 224 | 225 | ## Remove message handle ([Tab]) because we will be reinvoking tab expansion 226 | Remove-TabActivityIndicator 227 | 228 | ## Recursive tab expansion 229 | . TabExpansion ($LinePart + $ListHandle.Items[$ListHandle.SelectedItem].Value + '.') ($ListHandle.Items[$ListHandle.SelectedItem].Value + '.') -ForceList 230 | $HasChild = $true 231 | } else { 232 | $ListHandle.Items[$ListHandle.SelectedItem].Value 233 | } 234 | $Continue = $false 235 | break 236 | } 237 | } 238 | {'\','/' -contains $Key.Character} { ## Path Separators 239 | if ($PowerTabConfig.BackSlashComplete) { 240 | if ($PowerTabConfig.AutoExpandOnBackSlash) { 241 | ## Expand with currently selected item 242 | $Host.UI.Write($Host.UI.RawUI.ForegroundColor, $Host.UI.RawUI.BackgroundColor, ($ListHandle.Items[$ListHandle.SelectedItem].Value.SubString($LastWord.Length + $Filter.Length) + $Key.Character)) 243 | $ListHandle.Clear() 244 | if ($Line.Length -ge $LastWord.Length) { 245 | $LinePart = $Line.SubString(0, $Line.Length - $LastWord.Length) 246 | } 247 | 248 | ## Remove message handle ([Tab]) because we will be reinvoking tab expansion 249 | Remove-TabActivityIndicator 250 | 251 | ## Recursive tab expansion 252 | . Invoke-TabExpansion ($LinePart + $ListHandle.Items[$ListHandle.SelectedItem].Value + $Key.Character) ($ListHandle.Items[$ListHandle.SelectedItem].Value + $Key.Character) -ForceList 253 | $HasChild = $true 254 | } else { 255 | $ListHandle.Items[$ListHandle.SelectedItem].Value 256 | } 257 | $Continue = $false 258 | break 259 | } 260 | } 261 | 32 { ## Space 262 | ## True if "Space" and SpaceComplete is true, or "Ctrl+Space" and SpaceComplete is false 263 | if (($PowerTabConfig.SpaceComplete -and -not ($Key.ControlKeyState -match 'CtrlPressed')) -or (-not $PowerTabConfig.SpaceComplete -and ($Key.ControlKeyState -match 'CtrlPressed'))) { 264 | ## Expand with currently selected item 265 | $Item = $ListHandle.Items[$ListHandle.SelectedItem].Value 266 | if ((-not $Item.Contains(' ')) -and ($PowerTabFileSystemMode -ne $true)) {$Item += ' '} 267 | $Item 268 | $Continue = $false 269 | break 270 | } 271 | } 272 | {($PowerTabConfig.CustomCompletionChars.ToCharArray() -contains $Key.Character) -and $PowerTabConfig.CustomComplete} { ## Extra completions 273 | $Item = $ListHandle.Items[$ListHandle.SelectedItem].Value 274 | $Item = ($Item + $Key.Character) -replace "\$($Key.Character){2}$",$Key.Character 275 | $Item 276 | $Continue = $false 277 | break 278 | } 279 | 13 { ## Enter 280 | ## Expand with currently selected item 281 | $ListHandle.Items[$ListHandle.SelectedItem].Value 282 | $Continue = $false 283 | break 284 | } 285 | {$_ -ge 32 -and $_ -le 190} { ## Letter or digit or symbol (ASCII) 286 | ## Add character to filter 287 | $Filter += $Key.Character 288 | 289 | $Old = $Items.Length 290 | $Items = @($Content | Where-Object {$_.Text -match ('^' + [Regex]::Escape("$LastWord$Filter") + '.*')}) 291 | $New = $Items.Length 292 | if ($Items.Length -lt 1) { 293 | ## New filter results in no items 294 | if ($PowerTabConfig.CloseListOnEmptyFilter) { 295 | ## Close console list and return the return word with current filter (includes new character) 296 | $ListHandle.Clear() 297 | return "$ReturnWord$Filter" 298 | } else { 299 | ## Sound error beep and remove character 300 | Write-Host "`a" -NoNewline 301 | $Filter = $Filter.SubString(0, $Filter.Length - 1) 302 | } 303 | } else { 304 | if ($Old -ne $New) { 305 | ## If the item list changed, update the contents of the console list 306 | $ListHandle.Clear() 307 | $ListHandle = New-ConsoleList $Items $PowerTabConfig.Colors.BorderColor $PowerTabConfig.Colors.BorderBackColor ` 308 | $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 309 | ## Update status buffer 310 | . Add-Status 311 | ## Select first item of new list 312 | $SelectedItem = 0 313 | Set-Selection 1 ($SelectedItem + 1) ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 314 | } 315 | 316 | $Host.UI.Write($PowerTabConfig.Colors.FilterColor, $Host.UI.RawUI.BackgroundColor, $Key.Character) 317 | } 318 | break 319 | } 320 | } 321 | 322 | ## Listen for next key press 323 | if ($Continue) {$Key = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown')} 324 | } 325 | 326 | $ListHandle.Clear() 327 | if (-not $HasChild) { 328 | if ($Key.VirtualKeyCode -eq 27) { 329 | #Write-Line ($Host.UI.RawUI.CursorPosition.X - 1) ($Host.UI.RawUI.CursorPosition.Y - $Host.UI.RawUI.WindowPosition.Y) " " $PowerTabConfig.Colors.FilterColor $Host.UI.RawUI.BackgroundColor 330 | ## No items left and request that console list close, so return the return word with current filter 331 | return "$ReturnWord$Filter" 332 | } 333 | } 334 | } ## end of "end" block 335 | } 336 | 337 | 338 | Function New-Box { 339 | param( 340 | [System.Drawing.Size] 341 | $Size 342 | , 343 | [System.ConsoleColor] 344 | $ForegroundColor = $Host.UI.RawUI.ForegroundColor 345 | , 346 | [System.ConsoleColor] 347 | $BackgroundColor = $Host.UI.RawUI.BackgroundColor 348 | ) 349 | 350 | $Box = New-Object System.Management.Automation.PSObject -Property @{ 351 | 'HorizontalDouble' = ([char]9552).ToString() 352 | 'VerticalDouble' = ([char]9553).ToString() 353 | 'TopLeftDouble' = ([char]9556).ToString() 354 | 'TopRightDouble' = ([char]9559).ToString() 355 | 'BottomLeftDouble' = ([char]9562).ToString() 356 | 'BottomRightDouble' = ([char]9565).ToString() 357 | 'Horizontal' = ([char]9472).ToString() 358 | 'Vertical' = ([char]9474).ToString() 359 | 'TopLeft' = ([char]9484).ToString() 360 | 'TopRight' = ([char]9488).ToString() 361 | 'BottomLeft' = ([char]9492).ToString() 362 | 'BottomRight' = ([char]9496).ToString() 363 | 'Cross' = ([char]9532).ToString() 364 | 'HorizontalDoubleSingleUp' = ([char]9575).ToString() 365 | 'HorizontalDoubleSingleDown' = ([char]9572).ToString() 366 | 'VerticalDoubleLeftSingle' = ([char]9570).ToString() 367 | 'VerticalDoubleRightSingle' = ([char]9567).ToString() 368 | 'TopLeftDoubleSingle' = ([char]9554).ToString() 369 | 'TopRightDoubleSingle' = ([char]9557).ToString() 370 | 'BottomLeftDoubleSingle' = ([char]9560).ToString() 371 | 'BottomRightDoubleSingle' = ([char]9563).ToString() 372 | 'TopLeftSingleDouble' = ([char]9555).ToString() 373 | 'TopRightSingleDouble' = ([char]9558).ToString() 374 | 'BottomLeftSingleDouble' = ([char]9561).ToString() 375 | 'BottomRightSingleDouble' = ([char]9564).ToString() 376 | } 377 | 378 | if ($PowerTabConfig.DoubleBorder) { 379 | ## Double line box 380 | $LineTop = $Box.TopLeftDouble ` 381 | + $Box.HorizontalDouble * ($Size.width - 2) ` 382 | + $Box.TopRightDouble 383 | $LineField = $Box.VerticalDouble ` 384 | + ' ' * ($Size.width - 2) ` 385 | + $Box.VerticalDouble 386 | $LineBottom = $Box.BottomLeftDouble ` 387 | + $Box.HorizontalDouble * ($Size.width - 2) ` 388 | + $Box.BottomRightDouble 389 | } elseif ($false) { 390 | ## Mixed line box, double horizontal, single vertical 391 | $LineTop = $Box.TopLeftDoubleSingle ` 392 | + $Box.HorizontalDouble * ($Size.width - 2) ` 393 | + $Box.TopRightDoubleSingle 394 | $LineField = $Box.Vertical ` 395 | + ' ' * ($Size.width - 2) ` 396 | + $Box.Vertical 397 | $LineBottom = $Box.BottomLeftDoubleSingle ` 398 | + $Box.HorizontalDouble * ($Size.width - 2) ` 399 | + $Box.BottomRightDoubleSingle 400 | } elseif ($false) { 401 | ## Mixed line box, single horizontal, double vertical 402 | $LineTop = $Box.TopLeftDoubleSingle ` 403 | + $Box.HorizontalDouble * ($Size.width - 2) ` 404 | + $Box.TopRightDoubleSingle 405 | $LineField = $Box.Vertical ` 406 | + ' ' * ($Size.width - 2) ` 407 | + $Box.Vertical 408 | $LineBottom = $Box.BottomLeftDoubleSingle ` 409 | + $Box.HorizontalDouble * ($Size.width - 2) ` 410 | + $Box.BottomRightDoubleSingle 411 | } else { 412 | ## Single line box 413 | $LineTop = $Box.TopLeft ` 414 | + $Box.Horizontal * ($Size.width - 2) ` 415 | + $Box.TopRight 416 | $LineField = $Box.Vertical ` 417 | + ' ' * ($Size.width - 2) ` 418 | + $Box.Vertical 419 | $LineBottom = $Box.BottomLeft ` 420 | + $Box.Horizontal * ($Size.width - 2) ` 421 | + $Box.BottomRight 422 | } 423 | $Box = & {$LineTop; 1..($Size.Height - 2) | ForEach-Object {$LineField}; $LineBottom} 424 | $BoxBuffer = $Host.UI.RawUI.NewBufferCellArray($Box, $ForegroundColor, $BackgroundColor) 425 | ,$BoxBuffer 426 | } 427 | 428 | 429 | Function Get-ContentSize { 430 | param( 431 | [Object[]]$Content 432 | ) 433 | 434 | $MaxWidth = @($Content | Select-Object -ExpandProperty Text | Sort-Object Length -Descending)[0].Length 435 | New-Object System.Drawing.Size $MaxWidth, $Content.Length 436 | } 437 | 438 | 439 | Function New-Position { 440 | param( 441 | [Int]$X 442 | , 443 | [Int]$Y 444 | ) 445 | 446 | $Position = $Host.UI.RawUI.WindowPosition 447 | $Position.X += $X 448 | $Position.Y += $Y 449 | $Position 450 | } 451 | 452 | 453 | Function New-Buffer { 454 | param( 455 | [System.Management.Automation.Host.Coordinates] 456 | $Position 457 | , 458 | [System.Management.Automation.Host.BufferCell[,]] 459 | $Buffer 460 | ) 461 | 462 | $BufferBottom = $BufferTop = $Position 463 | $BufferBottom.X += ($Buffer.GetUpperBound(1)) 464 | $BufferBottom.Y += ($Buffer.GetUpperBound(0)) 465 | $Rectangle = New-Object System.Management.Automation.Host.Rectangle $BufferTop, $BufferBottom 466 | $OldBuffer = $Host.UI.RawUI.GetBufferContents($Rectangle) 467 | $Host.UI.RawUI.SetBufferContents($BufferTop, $Buffer) 468 | $Handle = New-Object System.Management.Automation.PSObject -Property @{ 469 | 'Content' = $Buffer 470 | 'OldContent' = $OldBuffer 471 | 'Location' = $BufferTop 472 | } 473 | Add-Member -InputObject $Handle -MemberType 'ScriptMethod' -Name 'Clear' -Value {$Host.UI.RawUI.SetBufferContents($This.Location, $This.OldContent)} 474 | Add-Member -InputObject $Handle -MemberType 'ScriptMethod' -Name 'Show' -Value {$Host.UI.RawUI.SetBufferContents($This.Location, $This.Content)} 475 | $Handle 476 | } 477 | 478 | 479 | Function ConvertTo-BufferCellArray { 480 | param( 481 | [String[]] 482 | $Content 483 | , 484 | [System.ConsoleColor] 485 | $ForegroundColor = $Host.UI.RawUI.ForegroundColor 486 | , 487 | [System.ConsoleColor] 488 | $BackgroundColor = $Host.UI.RawUI.BackgroundColor 489 | ) 490 | 491 | ,$Host.UI.RawUI.NewBufferCellArray($Content, $ForegroundColor, $BackgroundColor) 492 | } 493 | 494 | 495 | Function Parse-List { 496 | param( 497 | [System.Drawing.Size]$Size 498 | ) 499 | 500 | $WindowPosition = $Host.UI.RawUI.WindowPosition 501 | $WindowSize = $Host.UI.RawUI.WindowSize 502 | $Cursor = $Host.UI.RawUI.CursorPosition 503 | $Center = [Math]::Truncate([Float]$WindowSize.Height / 2) 504 | $CursorOffset = $Cursor.Y - $WindowPosition.Y 505 | $CursorOffsetBottom = $WindowSize.Height - $CursorOffset 506 | 507 | # Vertical Placement and size 508 | $ListHeight = $Size.Height + 2 509 | 510 | if (($CursorOffset -gt $Center) -and ($ListHeight -ge $CursorOffsetBottom)) {$Placement = 'Above'} 511 | else {$Placement = 'Below'} 512 | 513 | switch ($Placement) { 514 | 'Above' { 515 | $MaxListHeight = $CursorOffset 516 | if ($MaxListHeight -lt $ListHeight) {$ListHeight = $MaxListHeight} 517 | $Y = $CursorOffset - $ListHeight 518 | } 519 | 'Below' { 520 | $MaxListHeight = ($CursorOffsetBottom - 1) 521 | if ($MaxListHeight -lt $ListHeight) {$ListHeight = $MaxListHeight} 522 | $Y = $CursorOffSet + 1 523 | } 524 | } 525 | $MaxItems = $MaxListHeight - 2 526 | 527 | # Horizontal 528 | $ListWidth = $Size.Width + 4 529 | if ($ListWidth -gt $WindowSize.Width) {$ListWidth = $Windowsize.Width} 530 | $Max = $ListWidth 531 | if (($Cursor.X + $Max) -lt ($WindowSize.Width - 2)) { 532 | $X = $Cursor.X 533 | } else { 534 | if (($Cursor.X - $Max) -gt 0) { 535 | $X = $Cursor.X - $Max 536 | } else { 537 | $X = $windowSize.Width - $Max 538 | } 539 | } 540 | 541 | # Output 542 | $ListInfo = New-Object System.Management.Automation.PSObject -Property @{ 543 | 'Orientation' = $Placement 544 | 'TopX' = $X 545 | 'TopY' = $Y 546 | 'ListHeight' = $ListHeight 547 | 'ListWidth' = $ListWidth 548 | 'MaxItems' = $MaxItems 549 | } 550 | $ListInfo 551 | } 552 | 553 | 554 | Function New-ConsoleList { 555 | param( 556 | [Object[]] 557 | $Content 558 | , 559 | [System.ConsoleColor] 560 | $BorderForegroundColor 561 | , 562 | [System.ConsoleColor] 563 | $BorderBackgroundColor 564 | , 565 | [System.ConsoleColor] 566 | $ContentForegroundColor 567 | , 568 | [System.ConsoleColor] 569 | $ContentBackgroundColor 570 | ) 571 | 572 | $Size = Get-ContentSize $Content 573 | $MinWidth = ([String]$Content.Count).Length * 4 + 7 574 | if ($Size.Width -lt $MinWidth) {$Size.Width = $MinWidth} 575 | $Content = foreach ($Item in $Content) { 576 | $Item.DisplayText = " $($Item.Text) ".PadRight($Size.Width + 2) 577 | $Item 578 | } 579 | $ListConfig = Parse-List $Size 580 | $BoxSize = New-Object System.Drawing.Size $ListConfig.ListWidth, $ListConfig.ListHeight 581 | $Box = New-Box $BoxSize $BorderForegroundColor $BorderBackgroundColor 582 | 583 | $Position = New-Position $ListConfig.TopX $ListConfig.TopY 584 | $BoxHandle = New-Buffer $Position $Box 585 | 586 | # Place content 587 | $Position.X += 1 588 | $Position.Y += 1 589 | $ContentBuffer = ConvertTo-BufferCellArray ($Content[0..($ListConfig.ListHeight - 3)] | Select-Object -ExpandProperty DisplayText) $ContentForegroundColor $ContentBackgroundColor 590 | $ContentHandle = New-Buffer $Position $ContentBuffer 591 | $Handle = New-Object System.Management.Automation.PSObject -Property @{ 592 | 'Position' = (New-Position $ListConfig.TopX $ListConfig.TopY) 593 | 'ListConfig' = $ListConfig 594 | 'ContentSize' = $Size 595 | 'BoxSize' = $BoxSize 596 | 'Box' = $BoxHandle 597 | 'Content' = $ContentHandle 598 | 'SelectedItem' = 0 599 | 'SelectedLine' = 1 600 | 'Items' = $Content 601 | 'FirstItem' = 0 602 | 'LastItem' = ($Listconfig.ListHeight - 3) 603 | 'MaxItems' = $Listconfig.MaxItems 604 | } 605 | Add-Member -InputObject $Handle -MemberType 'ScriptMethod' -Name 'Clear' -Value {$This.Box.Clear()} 606 | Add-Member -InputObject $Handle -MemberType 'ScriptMethod' -Name 'Show' -Value {$This.Box.Show(); $This.Content.Show()} 607 | $Handle 608 | } 609 | 610 | 611 | Function Write-Line { 612 | param( 613 | [Int]$X 614 | , 615 | [Int]$Y 616 | , 617 | [String]$Text 618 | , 619 | [System.ConsoleColor] 620 | $ForegroundColor 621 | , 622 | [System.ConsoleColor] 623 | $BackgroundColor 624 | ) 625 | 626 | $Position = $Host.UI.RawUI.WindowPosition 627 | $Position.X += $X 628 | $Position.Y += $Y 629 | if ($Text -eq '') {$Text = '-'} 630 | $Buffer = $Host.UI.RawUI.NewBufferCellArray([String[]]$Text, $ForegroundColor, $BackgroundColor) 631 | $Host.UI.RawUI.SetBufferContents($Position, $Buffer) 632 | } 633 | 634 | 635 | Function Move-List { 636 | param( 637 | [Int]$X 638 | , 639 | [Int]$Y 640 | , 641 | [Int]$Width 642 | , 643 | [Int]$Height 644 | , 645 | [Int]$Offset 646 | ) 647 | 648 | $Position = $ListHandle.Position 649 | $Position.X += $X 650 | $Position.Y += $Y 651 | $Rectangle = New-Object System.Management.Automation.Host.Rectangle $Position.X, $Position.Y, ($Position.X + $Width), ($Position.Y + $Height - 1) 652 | $Position.Y += $OffSet 653 | $BufferCell = New-Object System.Management.Automation.Host.BufferCell 654 | $BufferCell.BackgroundColor = $PowerTabConfig.Colors.BackColor 655 | $Host.UI.RawUI.ScrollBufferContents($Rectangle, $Position, $Rectangle, $BufferCell) 656 | } 657 | 658 | 659 | Function Set-Selection { 660 | param( 661 | [Int]$X 662 | , 663 | [Int]$Y 664 | , 665 | [Int]$Width 666 | , 667 | [System.ConsoleColor] 668 | $ForegroundColor 669 | , 670 | [System.ConsoleColor] 671 | $BackgroundColor 672 | ) 673 | 674 | $Position = $ListHandle.Position 675 | $Position.X += $X 676 | $Position.Y += $Y 677 | $Rectangle = New-Object System.Management.Automation.Host.Rectangle $Position.X, $Position.Y, ($Position.X + $Width), $Position.Y 678 | $LineBuffer = $Host.UI.RawUI.GetBufferContents($Rectangle) 679 | $LineBuffer = $Host.UI.RawUI.NewBufferCellArray(@([String]::Join("", ($LineBuffer | ForEach-Object {$_.Character}))), 680 | $ForegroundColor, $BackgroundColor) 681 | $Host.UI.RawUI.SetBufferContents($Position, $LineBuffer) 682 | } 683 | 684 | 685 | Function Move-Selection { 686 | param( 687 | [Int]$Count 688 | ) 689 | 690 | $SelectedItem = $ListHandle.SelectedItem 691 | $Line = $ListHandle.SelectedLine 692 | if ($Count -eq ([Math]::Abs([Int]$Count))) { ## Down in list 693 | if ($SelectedItem -eq ($ListHandle.Items.Count - 1)) {return} 694 | $One = 1 695 | if ($SelectedItem -eq $ListHandle.LastItem) { 696 | $Move = $true 697 | if (($ListHandle.Items.Count - $SelectedItem - 1) -lt $Count) {$Count = $ListHandle.Items.Count - $SelectedItem - 1} 698 | } else { 699 | $Move = $false 700 | if (($ListHandle.MaxItems - $Line) -lt $Count) {$Count = $ListHandle.MaxItems - $Line} 701 | } 702 | } else { 703 | if ($SelectedItem -eq 0) {return} 704 | $One = -1 705 | if ($SelectedItem -eq $ListHandle.FirstItem) { 706 | $Move = $true 707 | if ($SelectedItem -lt ([Math]::Abs([Int]$Count))) {$Count = (-($SelectedItem))} 708 | } else { 709 | $Move = $false 710 | if ($Line -lt ([Math]::Abs([Int]$Count))) {$Count = (-$Line) + 1} 711 | } 712 | } 713 | 714 | if ($Move) { 715 | Set-Selection 1 $Line ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 716 | Move-List 1 1 ($ListHandle.ListConfig.ListWidth - 3) ($ListHandle.ListConfig.ListHeight - 2) (-$Count) 717 | $SelectedItem += $Count 718 | $ListHandle.FirstItem += $Count 719 | $ListHandle.LastItem += $Count 720 | 721 | $LinePosition = $ListHandle.Position 722 | $LinePosition.X += 1 723 | if ($One -eq 1) { 724 | $LinePosition.Y += $Line - ($Count - $One) 725 | $LineBuffer = ConvertTo-BufferCellArray ($ListHandle.Items[($SelectedItem - ($Count - $One)) .. $SelectedItem] | Select-Object -ExpandProperty Text) $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 726 | } else { 727 | $LinePosition.Y += 1 728 | $LineBuffer = ConvertTo-BufferCellArray ($ListHandle.Items[($SelectedItem..($SelectedItem - ($Count - $One)))] | Select-Object -ExpandProperty Text) $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 729 | } 730 | $LineHandle = New-Buffer $LinePosition $LineBuffer 731 | Set-Selection 1 $Line ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 732 | } else { 733 | Set-Selection 1 $Line ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.TextColor $PowerTabConfig.Colors.BackColor 734 | $SelectedItem += $Count 735 | $Line += $Count 736 | Set-Selection 1 $Line ($ListHandle.ListConfig.ListWidth - 3) $PowerTabConfig.Colors.SelectedTextColor $PowerTabConfig.Colors.SelectedBackColor 737 | } 738 | $ListHandle.SelectedItem = $SelectedItem 739 | $ListHandle.SelectedLine = $Line 740 | 741 | ## New status buffer 742 | $StatusHandle.Clear() 743 | $StatusBuffer = ConvertTo-BufferCellArray "[$($ListHandle.SelectedItem + 1)] $($ListHandle.FirstItem + 1)-$($ListHandle.LastItem + 1) [$($Content.Length)]" ` 744 | $PowerTabConfig.Colors.BorderTextColor $PowerTabConfig.Colors.BorderBackColor 745 | $StatusHandle = New-Buffer $StatusHandle.Location $StatusBuffer 746 | } 747 | 748 | -------------------------------------------------------------------------------- /Modules/PowerTab/TabExpansionCore.ps1: -------------------------------------------------------------------------------- 1 | # TabExpansionCore.ps1 2 | # 3 | # 4 | 5 | 6 | # .ExternalHelp TabExpansionCore-Help.xml 7 | Function Invoke-TabExpansion { 8 | [CmdletBinding()] 9 | param( 10 | [Parameter(Position = 0, Mandatory = $true)] 11 | [AllowEmptyString()] 12 | [String] 13 | $Line 14 | , 15 | [Parameter(Position = 1, Mandatory = $true)] 16 | [AllowEmptyString()] 17 | [String] 18 | $LastWord 19 | , 20 | [Switch] 21 | $ForceList 22 | ) 23 | 24 | try { 25 | ## Save global errors in the script scoped Error ( doesn't appear to be used ) 26 | # This also addresses the problem of $Error[0]. not working since it uses the script scoped $Error as well. 27 | $script:Error.Clear() 28 | $script:Error.AddRange($global:Error) 29 | $global:Error.Clear() 30 | $global:Error.AddRange($PowerTabError) 31 | 32 | if ($PowerTabConfig -eq $null) { 33 | ## Something happened to the PowerTabConfig object, recreate it 34 | CreatePowerTabConfig 35 | } 36 | 37 | $ParseErrors = $null 38 | $Tokens = [System.Management.Automation.PSParser]::Tokenize($Line, [ref]$ParseErrors) 39 | 40 | ## Figure out the context of this tab expansion request 41 | $_TokenTypes = [System.Management.Automation.PSTokenType] 42 | $ScopeStack = New-Object System.Collections.Stack 43 | $CurrentContext = New-TabContext 44 | $LastToken = $null 45 | $LastParameter = "" 46 | ## TODO: Save all values from a list for a parameter 47 | foreach ($Token in $Tokens) { 48 | if (($Token.Type -eq $_TokenTypes::Command) -and !($CurrentContext.Command)) { 49 | $CurrentContext.CommandInfo = try {Resolve-Command $Token.Content -CommandInfo -ErrorAction "Stop"} catch {} 50 | if ($CurrentContext.CommandInfo) { 51 | $CurrentContext.Command = $CurrentContext.CommandInfo.Name 52 | } else { 53 | $CurrentContext.Command = $Token.Content 54 | } 55 | $CurrentContext.isCommandMode = $true 56 | } elseif (($Token.Type -eq $_TokenTypes::Keyword) -and !($CurrentContext.Command) -and 57 | (@("function") -contains $Token.Content)) { 58 | $CurrentContext.Command = $Token.Content 59 | $CurrentContext.isCommandMode = $true 60 | } elseif ($Token.Type -eq $_TokenTypes::CommandParameter) { 61 | if ($CurrentContext.Parameter) { 62 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $CurrentContext.Argument 63 | } elseif ($CurrentContext.Argument) { 64 | while ($CurrentContext.PositionalParameters.Count -le $CurrentContext.PositionalParameter) { 65 | $CurrentContext.PositionalParameters += @("") 66 | } 67 | $CurrentContext.PositionalParameters[$CurrentContext.PositionalParameter] = $CurrentContext.Argument 68 | } 69 | $CurrentContext.Parameter = try { 70 | if ($TabExpansionCommandInfoRegistry[$CurrentContext.Command]) { 71 | $ScriptBlock = $TabExpansionCommandInfoRegistry[$CurrentContext.Command] 72 | $CommandInfo = & $ScriptBlock $CurrentContext 73 | if ($CommandInfo) { 74 | Resolve-Parameter $CommandInfo $Token.Content 75 | } else { 76 | Resolve-Parameter $CurrentContext.CommandInfo $Token.Content 77 | } 78 | } else { 79 | Resolve-Parameter $CurrentContext.CommandInfo $Token.Content 80 | } 81 | } catch {$Token.Content -replace '^-'} 82 | if (-not $CurrentContext.Parameter) {$CurrentContext.Parameter = $Token.Content -replace '^-'} 83 | $CurrentContext.Argument = "" 84 | $CurrentContext.isParameterValue = $false 85 | 86 | ## Check if parameter is a switch 87 | try { 88 | if ($TabExpansionCommandInfoRegistry[$CurrentContext.Command]) { 89 | $ScriptBlock = $TabExpansionCommandInfoRegistry[$CurrentContext.Command] 90 | $CommandInfo = & $ScriptBlock $CurrentContext 91 | if ($CommandInfo) { 92 | $Parameter = Resolve-Parameter $CommandInfo $CurrentContext.Parameter -ParameterInfo 93 | } else { 94 | ## TODO: 95 | throw "foo" 96 | } 97 | } else { 98 | $Parameter = Resolve-Parameter $CurrentContext.CommandInfo $CurrentContext.Parameter -ParameterInfo 99 | } 100 | if ($Parameter.ParameterType -eq [System.Management.Automation.SwitchParameter]) { 101 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $true 102 | $CurrentContext.Parameter = "" 103 | $CurrentContext.Argument = "" 104 | $CurrentContext.isParameterValue = $false 105 | } 106 | } catch {} 107 | } elseif (($Token.Type -eq $_TokenTypes::StatementSeparator) -or ($Token.Content -eq "|")) { 108 | $CurrentContext = New-TabContext 109 | } elseif (($Token.Type -eq $_TokenTypes::Operator) -and ($Token.Content -eq "=")) { 110 | $CurrentContext.isAssignment = $true 111 | } elseif ($CurrentContext.isCommandMode -and (($_TokenTypes::CommandArgument, $_TokenTypes::Member, 112 | $_TokenTypes::Number, $_TokenTypes::Operator, $_TokenTypes::String, $_TokenTypes::Variable) -contains $Token.Type)) { 113 | if (($Token.Type -eq $_TokenTypes::Operator) -and ("," -eq $Token.Content)) { 114 | ## TODO: Keep track of full list of values for a parameter? 115 | } 116 | 117 | if ($LastToken.EndColumn -ne $Token.StartColumn) { 118 | ## The parameter check is for the case of a switch appearing just befor a positional parameter: Func -Switch tex 119 | if ((-not $Token.Content.StartsWith("-")) -and (($CurrentContext.Argument -ne "") -or ($CurrentContext.Parameter -eq ""))) { 120 | if ($CurrentContext.Parameter) { 121 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $CurrentContext.Argument 122 | } elseif ($CurrentContext.Argument) { 123 | while ($CurrentContext.PositionalParameters.Count -le $CurrentContext.PositionalParameter) { 124 | $CurrentContext.PositionalParameters += @("") 125 | } 126 | $CurrentContext.PositionalParameters[$CurrentContext.PositionalParameter] = $CurrentContext.Argument 127 | } 128 | ## Found value for positional parameter 129 | $CurrentContext.Parameter = "" 130 | $CurrentContext.Argument = "" 131 | $CurrentContext.PositionalParameter += 1 132 | $CurrentContext.isParameterValue = $true 133 | } elseif ($Token.Content.StartsWith("-")) { 134 | if ($CurrentContext.Parameter) { 135 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $CurrentContext.Argument 136 | } elseif ($CurrentContext.Argument) { 137 | while ($CurrentContext.PositionalParameters.Count -le $CurrentContext.PositionalParameter) { 138 | $CurrentContext.PositionalParameters += @("") 139 | } 140 | $CurrentContext.PositionalParameters[$CurrentContext.PositionalParameter] = $CurrentContext.Argument 141 | } 142 | $CurrentContext.Parameter = "" 143 | $CurrentContext.Argument = "" 144 | $CurrentContext.isParameterValue = $false 145 | continue 146 | } 147 | } 148 | 149 | ## Decide if this token could be handed off to parameter tab completion 150 | if (($_TokenTypes::CommandArgument, $_TokenTypes::Number, $_TokenTypes::String) -contains $Token.Type) { 151 | $CurrentContext.Argument = $Token.Content 152 | $CurrentContext.isParameterValue = $true 153 | } elseif ($Token.Type -eq $_TokenTypes::Variable) { 154 | $CurrentContext.Argument = '$' + $Token.Content 155 | $CurrentContext.isParameterValue = $true 156 | } elseif (($Token.Type -eq $_TokenTypes::Operator) -and ("," -eq $Token.Content)) { 157 | $CurrentContext.Argument = "" 158 | $CurrentContext.isParameterValue = $true 159 | } else { 160 | $CurrentContext.Argument = "" 161 | $CurrentContext.isParameterValue = $false 162 | } 163 | } elseif ($Token.Type -eq $_TokenTypes::GroupStart) { 164 | $ScopeStack.Push($CurrentContext) 165 | $CurrentContext = New-TabContext 166 | } elseif ($Token.Type -eq $_TokenTypes::GroupEnd) { 167 | $CurrentContext = $ScopeStack.Pop() 168 | if ($CurrentContext.Parameter) { 169 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $CurrentContext.Argument 170 | } 171 | $CurrentContext.Parameter = "" 172 | $CurrentContext.Argument = "" 173 | $CurrentContext.isParameterValue = $false 174 | } 175 | 176 | $LastToken = $Token 177 | } 178 | ## Special case, last word is "@", this causes a parsing error so we don't see the token 179 | if ($LastWord -eq '@') { 180 | if (-not $CurrentContext.Parameter) { 181 | $CurrentContext.PositionalParameter += 1 182 | } 183 | $CurrentContext.Argument = $LastWord 184 | $CurrentContext.isParameterValue = $true 185 | } 186 | ## Special case, blank value for parameter 187 | if (-not $LastWord) { 188 | if ($LastToken.Content -eq ",") { 189 | ## Don't do anything, build on existing list 190 | } elseif ($CurrentContext.Argument -ne $LastWord) { 191 | ## Special case, blank value for positional parameter after another parameter (foo -bar "test" _) 192 | if ($CurrentContext.Parameter) { 193 | $CurrentContext.OtherParameters[$CurrentContext.Parameter] = $CurrentContext.Argument 194 | $CurrentContext.Parameter = "" 195 | } elseif ($CurrentContext.Argument) { 196 | while ($CurrentContext.PositionalParameters.Count -le $CurrentContext.PositionalParameter) { 197 | $CurrentContext.PositionalParameters += @("") 198 | } 199 | $CurrentContext.PositionalParameters[$CurrentContext.PositionalParameter] = $CurrentContext.Argument 200 | } 201 | if ($CurrentContext.Command) { 202 | $CurrentContext.PositionalParameter += 1 203 | } 204 | } else { 205 | if (-not $CurrentContext.Parameter) { 206 | $CurrentContext.PositionalParameter += 1 207 | } 208 | } 209 | 210 | if ($CurrentContext.Command) { 211 | $CurrentContext.Argument = "" 212 | $CurrentContext.isParameterValue = $true 213 | } 214 | } 215 | 216 | ## Resolve name of positional parameter 217 | if ((-not $CurrentContext.Parameter) -and ($LastWord -ne "-")) { 218 | try { 219 | $CurrentContext = Resolve-PositionalParameter $CurrentContext 220 | } catch {} 221 | } 222 | 223 | ## Add additional context information 224 | Add-Member -InputObject $CurrentContext -Name Line -Value $Line -MemberType NoteProperty 225 | Add-Member -InputObject $CurrentContext -Name LastWord -Value $LastWord -MemberType NoteProperty 226 | Add-Member -InputObject $CurrentContext -Name LastToken -Value $LastToken.Type -MemberType NoteProperty 227 | ## Special debug logging 228 | if ($PowerTabLog) { 229 | $CurrentContext | Select-Object Line,LastWord,LastToken,Command,Parameter,Argument,PositionalParameter, 230 | PositionalParameters,OtherParameters,isCommandMode,isAssignment,isParameterValue | Out-String | 231 | Add-Content (Join-Path $env:USERPROFILE "PowerTab.log") 232 | } 233 | 234 | ## Indicate we are busy 235 | Invoke-TabActivityIndicator 236 | 237 | try { 238 | ## Detect DoubleTab if enabled 239 | if ($PowerTabConfig.DoubleTabEnabled) { 240 | Start-Sleep -m 400 241 | $DoubleTab = ($Host.UI.RawUI.KeyAvailable) 242 | } else { 243 | $DoubleTab = $PowerTabConfig.DoubleTabLock 244 | } 245 | 246 | ## Check DoubleTab and set selection handler 247 | if ($DoubleTab) { 248 | $SelectionHandler = $PowerTabConfig.AlternateHandler 249 | } else { 250 | $SelectionHandler = $PowerTabConfig.DefaultHandler 251 | } 252 | 253 | ## Resolve internal (no prefix) and fully qualified command names 254 | $FullCommandName = "" 255 | try { 256 | $InternalCommand = Resolve-InternalCommandName $CurrentContext.CommandInfo 257 | $InternalCommandName = $InternalCommand.InternalName 258 | if ($InternalCommand.Module) { 259 | $FullCommandName = $InternalCommand.Module.Name + "\" + $InternalCommand.InternalName 260 | } 261 | } catch { 262 | $InternalCommandName = $CurrentContext.Command 263 | } 264 | 265 | [Bool]$TabExpansionHasOutput = $false 266 | [Bool]$QuoteSpaces = $true 267 | [Object[]]$PossibleValues = @() 268 | if ($CurrentContext.isParameterValue) { 269 | ## Tab complete parameter value 270 | 271 | ## Command registry 272 | if ((-not $TabExpansionHasOutput) -and $TabExpansionCommandRegistry[$FullCommandName]) { 273 | $ScriptBlock = $TabExpansionCommandRegistry[$FullCommandName] 274 | $PossibleValues = & $ScriptBlock $CurrentContext ([ref]$TabExpansionHasOutput) ([ref]$QuoteSpaces) 275 | } 276 | if ((-not $TabExpansionHasOutput) -and $TabExpansionCommandRegistry[$InternalCommandName]) { 277 | $ScriptBlock = $TabExpansionCommandRegistry[$InternalCommandName] 278 | $PossibleValues = & $ScriptBlock $CurrentContext ([ref]$TabExpansionHasOutput) ([ref]$QuoteSpaces) 279 | } 280 | 281 | ## Parameter registry 282 | if ((-not $TabExpansionHasOutput) -and $TabExpansionParameterRegistry[$CurrentContext.Parameter]) { 283 | $ScriptBlock = $TabExpansionParameterRegistry[$CurrentContext.Parameter] 284 | $PossibleValues = & $ScriptBlock $CurrentContext.Argument ([ref]$TabExpansionHasOutput) ([ref]$QuoteSpaces) 285 | } 286 | 287 | ## Enum and ValidateSet() support 288 | if (-not $TabExpansionHasOutput) { 289 | try { 290 | ## Get parameter info 291 | if ($TabExpansionCommandInfoRegistry[$InternalCommandName]) { 292 | $ScriptBlock = $TabExpansionCommandInfoRegistry[$InternalCommandName] 293 | $CommandInfo = & $ScriptBlock $CurrentContext 294 | if ($CommandInfo) { 295 | $ParameterInfo = Resolve-Parameter $CommandInfo $CurrentContext.Parameter -ParameterInfo 296 | } else { 297 | $ParameterInfo = Resolve-Parameter $CurrentContext.CommandInfo $CurrentContext.Parameter -ParameterInfo 298 | } 299 | } else { 300 | $ParameterInfo = Resolve-Parameter $CurrentContext.CommandInfo $CurrentContext.Parameter -ParameterInfo 301 | } 302 | 303 | ## Enum 304 | if ($ParameterInfo.ParameterType.BaseType -eq [System.Enum]) { 305 | $TabExpansionHasOutput = $true 306 | $PossibleValues = [Enum]::GetNames($ParameterInfo.ParameterType) | Where-Object {$_ -like ($CurrentContext.Argument + "*")} | 307 | New-TabItem -Value {$_} -Text {$_} -Type Enum 308 | } 309 | 310 | ## ValidateSet 311 | if (-not $TabExpansionHasOutput) { 312 | $ValidateSet = $ParameterInfo.Attributes | Where-Object {$_ -is [System.Management.Automation.ValidateSetAttribute]} 313 | if ($ValidateSet) { 314 | $TabExpansionHasOutput = $true 315 | $PossibleValues = $ValidateSet | Select-Object -ExpandProperty ValidValues | 316 | Where-Object {$_ -like ($CurrentContext.Argument + "*")} | 317 | New-TabItem -Value {$_} -Text {$_} -Type Enum 318 | } 319 | } 320 | } catch {} 321 | } 322 | 323 | ## Ensure that variables get handled 324 | if ($PossibleValues -eq $null) {$PossibleValues = @()} 325 | if ($TabExpansionHasOutput -and ($PossibleValues.Count -eq 0) -and ($LastWord -match '^[@\$]')) { 326 | $TabExpansionHasOutput = $false 327 | } 328 | } elseif (($LastWord -match "^-") -and $CurrentContext.isCommandMode) { 329 | ## Tab complete parameter name 330 | 331 | ## Parameter name registry 332 | if ((-not $TabExpansionHasOutput) -and $TabExpansionParameterNameRegistry[$FullCommandName]) { 333 | $ScriptBlock = $TabExpansionParameterNameRegistry[$FullCommandName] 334 | $PossibleValues = & $ScriptBlock $CurrentContext $LastWord | New-TabItem -Value {$_} -Text {$_} -Type Parameter 335 | if ($PossibleValues) { 336 | $TabExpansionHasOutput = $true 337 | } 338 | } 339 | if ((-not $TabExpansionHasOutput) -and $TabExpansionParameterNameRegistry[$InternalCommandName]) { 340 | $ScriptBlock = $TabExpansionParameterNameRegistry[$InternalCommandName] 341 | $PossibleValues = & $ScriptBlock $CurrentContext $LastWord | New-TabItem -Value {$_} -Text {$_} -Type Parameter 342 | if ($PossibleValues) { 343 | $TabExpansionHasOutput = $true 344 | } 345 | } 346 | 347 | ## Command info 348 | if (-not $TabExpansionHasOutput) { 349 | if ($CurrentContext.CommandInfo) { 350 | $ParameterName = $LastWord -replace "^-" 351 | $PossibleValues = foreach ($Parameter in $CurrentContext.CommandInfo.Parameters.Values) { 352 | if ($Parameter.Name -like "$ParameterName*") { 353 | $Value = "-" + $Parameter.Name 354 | New-TabItem -Value $Value -Text ("$Value [$($Parameter.ParameterType)]") -Type Parameter 355 | } 356 | } 357 | $TabExpansionHasOutput = $true 358 | } 359 | } 360 | } elseif ($LastToken.Type -eq $_TokenTypes::GroupStart) { 361 | ## Tab complete method signatures 362 | $MethodTokens = @([System.Management.Automation.PSParser]::Tokenize($LastWord, [ref]$ParseErrors)) 363 | if ($MethodTokens[-2].Type -eq $_TokenTypes::Member) { 364 | $MethodObject = $LastWord.SubString(0, $MethodTokens[-1].Start) 365 | $PossibleValues = foreach ($Overload in Invoke-Expression "$MethodObject.OverloadDefinitions") { 366 | $Parameters = $Overload -replace '^\S+ .+\((.+)?\)','$1' 367 | if ($Parameters) { 368 | $Parameters = foreach ($Parameter in ($Parameters -split ", ")) { 369 | $Type = ($Parameter -split " ")[0] 370 | $Name = ($Parameter -split " ")[1] 371 | '[{0}] ${1}' -f $Type,$Name 372 | } 373 | $Parameters = $Parameters -join ", " 374 | } 375 | $Value = "{0}{1})" -f $LastWord,$Parameters 376 | New-TabItem -Value $Value -Text $Value -Type MethodSignature 377 | } 378 | $TabExpansionHasOutput = $true 379 | } 380 | } 381 | 382 | if ($PowerTabConfig -eq $null) { 383 | ## Something happened to the PowerTabConfig object, recreate it 384 | CreatePowerTabConfig 385 | } 386 | 387 | if ($TabExpansionHasOutput) { 388 | $PossibleValues | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler | ForEach-Object { 389 | if ($_ -is [String]) { 390 | if ($QuoteSpaces -and ($_ -match " ") -and ($_ -notmatch "^[`"'].*[`"']`$") -and 391 | (($LastToken.Type -eq $_TokenTypes::CommandArgument) -or ($LastWord -eq ""))) { 392 | '"' + ($_ -replace '([\$"`])','`$1') + '"' 393 | } else { 394 | $_ 395 | } 396 | } else { 397 | if ($QuoteSpaces -and ($_.Value -match " ") -and ($_.Value -notmatch "^[`"'].*[`"']`$") -and 398 | (($LastToken.Type -eq $_TokenTypes::CommandArgument) -or ($LastWord -eq ""))) { 399 | $_.Value = '"' + ($_.Value -replace '([\$"`])','`$1') + '"' 400 | } else { 401 | $_ 402 | } 403 | } 404 | } 405 | if ($PossibleValues.Count -lt 1) { 406 | ## No values 407 | if ($LastWord) { 408 | ## Return what the user typed 409 | $LastWord 410 | } else { 411 | ## Send blank to prevent default PowerShell tab expansion 412 | "" 413 | } 414 | } 415 | } else { 416 | Invoke-PowerTab -Line $Line -LastWord $LastWord -Context $CurrentContext -ForceList:$ForceList 417 | } 418 | } catch { 419 | Invoke-TabActivityIndicator -Error 420 | "" 421 | } finally { 422 | ## Remove busy indication on ready or error 423 | Remove-TabActivityIndicator 424 | } 425 | 426 | } finally { 427 | ## Save PowerTab errors and replace global errors 428 | $script:PowerTabError = $global:Error.Clone() 429 | $global:Error.Clear() 430 | $global:Error.AddRange($script:Error) 431 | } 432 | } 433 | 434 | Function New-TabContext { 435 | $Properties = @{ 436 | "Command" = "" 437 | "CommandInfo" = $null 438 | "Parameter" = "" 439 | "Argument" = $null 440 | "ArgumentList" = @() 441 | "PositionalParameter" = -1 442 | "PositionalParameters" = @() 443 | "OtherParameters" = @{} 444 | "isCommandMode" = $false 445 | "isAssignment" = $false 446 | "isParameterValue" = $false 447 | } 448 | New-Object PSObject -Property $Properties 449 | } 450 | 451 | 452 | Function Invoke-PowerTab { 453 | param( 454 | $Line, 455 | $LastWord, 456 | $Context, 457 | [Switch]$ForceList 458 | ) 459 | 460 | &{ 461 | $TabExpansionHasOutput = $false 462 | 463 | if ($PowerTabConfig.IgnoreConfirmPreference) { 464 | $OriginalConfirmPreference = $ConfirmPreference 465 | $ConfirmPreference = 'High' 466 | } 467 | 468 | ## Helper variables 469 | $_Method = [System.Management.Automation.PSMemberTypes]'Method,CodeMethod,ScriptMethod,ParameterizedProperty' 470 | $_ScopeNames = @("global", "local", "script", "private") 471 | 472 | ## Parse commandline 473 | $LineBlocks = [Regex]::Split($Line, '[|;]') 474 | $LastBlock = $LineBlocks[-1] 475 | 476 | ## Helper Functions 477 | Function Resolve-Member { 478 | param( 479 | $Object, 480 | $Pattern 481 | ) 482 | 483 | ## Check for multilevel members 484 | $LevelCount = $Pattern.Split('.').Count 485 | if ($LevelCount -gt 1) { 486 | $OFS = '.'; $Object += ".$($Pattern.Split('.')[0..($LevelCount -2)])" 487 | } 488 | 489 | ## Resolve Members 490 | $val = $Object 491 | $pat = $Pattern.Split('.')[($Level -1)] + '*' 492 | . { 493 | if ('PSBase' -like $pat) {$val + '.PSBase'} 494 | Invoke-Expression "Get-Member -InputObject ($val)" | Where-Object { 495 | $n = $_.Name 496 | if (-not $PowerTabConfig.ShowAccessorMethods) { 497 | $n -like $pat -and $n -notmatch '^[gs]et_' 498 | } else { 499 | $n -like $pat 500 | } 501 | } | ForEach-Object { 502 | if ($_.MemberType -band $_Method) { 503 | ## Return a method... 504 | $Value = $val + '.' + $_.Name + '(' 505 | New-TabItem -Value $Value -Text $Value -Type Method 506 | } else { 507 | ## Return a property... 508 | $Value = $val + '.' + $_.Name 509 | New-TabItem -Value $Value -Text $Value -Type Property 510 | } 511 | } 512 | } 513 | } 514 | 515 | Function QuoteVariable { 516 | param( 517 | [String]$Name 518 | ) 519 | 520 | ## Escape certain characters 521 | $Name = $Name -replace '([{}`])','`$1' 522 | 523 | ## If a variable name contains any of these characters it needs to be in braces 524 | $_varsRequiringQuotes = ('-`&@''#{}()$,;|<> .\/' + "`t").ToCharArray() 525 | if ($Name.IndexOfAny($_varsRequiringQuotes) -ge 0) { 526 | "{$Name}" 527 | } else { 528 | $Name 529 | } 530 | } 531 | 532 | &{ 533 | ## Main tabcompletion , check line for patterns, select completion method and invoke handler 534 | 535 | ## Evaluate last block 536 | switch -regex ($LastBlock) { 537 | ## Handle multilevel property and method expansion on simple () Blocks 538 | '(^| )\((.+)\)\.(.*)' { 539 | &{ trap {continue} 540 | Resolve-Member -Object "($($Matches[2]))" -Pattern $Matches[3] | 541 | Invoke-TabItemSelector $LastBlock -SelectionHandler $SelectionHandler | ForEach-Object { 542 | $TabExpansionHasOutput = $true 543 | if ($_.IndexOf(' ') -ge 0 ) { 544 | ([Regex]::Split($_,' '))[-1].Trim() 545 | } else { 546 | $_ 547 | } 548 | } 549 | } 550 | if ($TabExpansionHasOutput) { 551 | ## Tab expansion handled, don't do anything more 552 | return 553 | } 554 | } 555 | } 556 | 557 | ## Evaluate last word 558 | switch -regex ($LastWord) { 559 | ## Handle inline type search, e.g. new-object .identityreference or .identityre (oisin) 560 | '^(\[*?)\.(\w+)$' { 561 | $TypeName = $Matches[2] 562 | Get-TabExpansion "*.${TypeName}*" Types | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Type | 563 | Invoke-TabItemSelector $LastWord.Replace('[', '') -SelectionHandler $SelectionHandler | 564 | ForEach-Object {if ($Matches[1] -eq '[') {"[$_]"} else {$_}} 565 | break 566 | } 567 | 568 | ## Members of script block 569 | '(.*\})\.([^\.]*)$' { 570 | $ScriptBlock = $Matches[1] 571 | $Member = $Matches[2] 572 | {} | Get-Member | Where-Object { 573 | $n = $_.Name 574 | if (-not $PowerTabConfig.ShowAccessorMethods) { 575 | $n -like "$Member*" -and $n -notmatch '^[gs]et_' 576 | } else { 577 | $n -like "$Member*" 578 | } 579 | } | ForEach-Object { 580 | if ($_.MemberType -band $_Method) { 581 | ## Return a method... 582 | $Value = $ScriptBlock + '.' + $_.Name + '(' 583 | New-TabItem -Value $Value -Text $Value -Type Method 584 | } else { 585 | ## Return a property... 586 | $Value = $ScriptBlock + '.' + $_.Name 587 | New-TabItem -Value $Value -Text $Value -Type Property 588 | } 589 | } | Invoke-TabItemSelector "$ScriptBlock.$Member" -SelectionHandler $SelectionHandler 590 | break 591 | } 592 | 593 | ## Completion on Shares (commented lines without DLL but need admin rights ) 594 | '^(\\\\|//)(?[^\\/]+)[\\/](?[^\\/]*)$' { 595 | #gwmi win32_share -computer $ComputerName -filter "name like '$($ShareName)%'" | Foreach-Object {"\\$($ComputerName)\$($_.name)"} 596 | #([adsi]"WinNT://$($ComputerName)/LanmanServer,FileService" ).psbase.children |? {$_.name -like "$($ShareName)*"} |% {$_.name} 597 | $ComputerName = $Matches.Computer 598 | $ShareName = $Matches.Share 599 | [Trinet.Networking.ShareCollection]::GetShares($ComputerName) | Where-Object {$_.NetName -like "$ShareName*"} | 600 | Sort-Object NetName | New-TabItem -Value {"\\$ComputerName\" + $_.NetName} -Text {"\\$ComputerName\" + $_.NetName} -Type Share | 601 | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 602 | break 603 | } 604 | 605 | ## Completion on computers in database 606 | '^(\\\\|//)(?[^\\/]*)$' { 607 | $Computers = foreach ($Computer in Get-TabExpansion "$($Matches.Computer)*" Computer) { 608 | $Value = "\\" + $Computer.Text 609 | New-TabItem -Value $Value -Text $Value -Type Computer 610 | } 611 | $Computers | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 612 | break 613 | } 614 | 615 | ## Variable "In-Place" expansion on \[tab] 616 | '.*(\$[^\\]+)\\$' { 617 | $val = $ExecutionContext.InvokeCommand.ExpandString($Matches[1]) 618 | ($Matches[0] -replace ([Regex]::Escape($Matches[1])), $val).TrimEnd('\') 619 | break 620 | } 621 | 622 | ## Replace -? with call to Get-Help 623 | '.*\-\?' {"Get-Help " + $LastWord.Replace('-?', ' -')} 624 | 625 | ## PSDrive expansion on :[tab] 626 | '^:$' { 627 | Get-PSDrive | New-TabItem -Value {$_.Name + ':'} -Text {$_.Name + ':'} -Type PSDrive | 628 | Invoke-TabItemSelector '' -SelectionHandler $SelectionHandler 629 | } 630 | 631 | ## History completion against either # or # 632 | '^#(.*)' { 633 | $Pattern = $Matches[1] 634 | if ($Pattern -match '^[0-9]+$') { 635 | @(Get-History -Id $Pattern -ErrorAction SilentlyContinue)[0].CommandLine 636 | } else { 637 | Get-History -Count 32767 | Where-Object {$_.CommandLine -like "$Pattern*"} | Sort Id -Descending | 638 | Select-Object -ExpandProperty CommandLine -Unique | New-TabItem -Value {$_} -Text {$_} -Type History | 639 | Invoke-TabItemSelector $Pattern -SelectionHandler $SelectionHandler 640 | } 641 | break 642 | } 643 | 644 | ## About Topics completion 645 | 'about_(.*)' { 646 | Get-Help "about_$($Matches[1])*" | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Help | 647 | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 648 | break 649 | } 650 | 651 | ## DataGrid GUI Shortcuts 652 | '^a_(.*)' {Get-Help "about_$($Matches[1])*" | Select-Object Name,Synopsis,Length | Out-DataGridView Name | Foreach-Object {Get-Help $_}} 653 | '^w_(.*)' {Get-TabExpansion "win32_$($Matches[1])*" WMI | Select-Object "Name" | Out-DataGridView Name} 654 | '^t_(.*)' {Get-TabExpansion "*$($Matches[1])*" Types | Select-Object "Name" | Out-DataGridView Name} 655 | '^c_(.*)' {Get-TabExpansion "$($Matches[1])*" | Select-Object "Text" | Out-DataGridView Text} 656 | '^f_' {Get-ChildItem function: | Select-Object Name | Out-DataGridView Name} 657 | '^d_' {Get-ChildItem | Select-Object Mode,LastWriteTime,Length,Name,FullName | Out-DataGridView FullName} 658 | '^h_' {Get-History -Count 100 | Out-DataGridView Commandline} 659 | 660 | ## WMI completion 661 | '(win32_.*|cim_.*|MSFT_.*)' { 662 | Get-TabExpansion "$($Matches[1])*" WMI | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type WMIObject | 663 | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 664 | break 665 | } 666 | 667 | ## Handle property and method expansion on variables 668 | '\$(.+)\.(.*)' { 669 | Resolve-Member -Object ('$' + $Matches[1]) -Pattern $Matches[2] | 670 | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 671 | break 672 | } 673 | 674 | ## Translate typename to New-Object statement [String][tab] 675 | '^(\[.*\])=(\w*)$' { 676 | "New-Object $($Matches[1].Replace('[','').Replace(']',''))" 677 | break 678 | } 679 | 680 | ## Handle Static methods of Types 681 | '(\[.*\])::(.*)$' { 682 | $LastType = $Matches[1] 683 | $Level = $Matches[2].Split('.').Count 684 | 685 | if ($Level -gt 1) { 686 | $LastType += ('::' + $Matches[2].Split('.')[0]) 687 | $Pattern = $Matches[2].SubString(($Matches[2].IndexOf('.') + 1)) 688 | Resolve-Member -Object $LastType -Pattern $Pattern | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 689 | } else { 690 | $Pattern = $Matches[2].Split('.')[($Level -1)] + '*' 691 | Invoke-Expression "$($Matches[1]) | Get-Member -Static" | Where-Object { 692 | $_.Name -like $Pattern -and $_.Name -notmatch '^[ge]et_'} | ForEach-Object { 693 | if ($_.MemberType -band $_Method) { 694 | $Value = "${LastType}::$($_.Name)" + '(' 695 | New-TabItem -Value $Value -Text $Value -Type StaticMethod 696 | } else { 697 | $Value = "${LastType}::$($_.Name)" 698 | New-TabItem -Value $Value -Text $Value -Type StaticProperty 699 | } 700 | } | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 701 | } 702 | break 703 | } 704 | 705 | ## Handle Static methods of types in Variables 706 | '(\$.*)::(.*)$' { 707 | $LastType = $Matches[1] 708 | $Level = $Matches[2].Split('.').Count 709 | $gt = '' 710 | 711 | if ((Invoke-Expression "$LastType.GetType().Name") -ne 'RuntimeType') {$gt = '.GetType'} 712 | if ($Level -gt 1) { 713 | $LastType += ('::' + $Matches[2].Split('.')[0]) 714 | $Pattern = $Matches[2].SubString(($Matches[2].IndexOf('.') + 1)) 715 | Resolve-Member -Object $LastType -Pattern $Pattern | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 716 | } else { 717 | $Pattern = $Matches[2].Split('.')[($Level -1)] + '*' 718 | Invoke-Expression "$($Matches[1]) | Get-Member -Static" | Where-Object { 719 | $_.Name -like $Pattern -and $_.Name -notmatch '^[ge]et_'} | ForEach-Object { 720 | if ($_.MemberType -band $_Method) { 721 | $Value = "${LastType}${gt}::$($_.Name)" + '(' 722 | New-TabItem -Value $Value -Text $Value -Type StaticMethod 723 | } else { 724 | $Value = "${LastType}${gt}::$($_.Name)" 725 | New-TabItem -Value $Value -Text $Value -Type StaticProperty 726 | } 727 | } | Invoke-TabItemSelector $LastWord.Replace('::',"${gt}::") -SelectionHandler $SelectionHandler 728 | } 729 | break 730 | } 731 | 732 | ## Handle enums and Constructors of Types 733 | '(\[.*\]):*$' { 734 | $LastType = $Matches[1].Split(',')[-1] 735 | $BaseType = (Invoke-Expression "$LastType.BaseType.FullName") 736 | . { 737 | if ($BaseType -eq 'System.Enum') { 738 | $Names = Invoke-Expression "[Enum]::GetNames($LastType)" | 739 | New-TabItem -Value {"${LastType}::$_"} -Text {"${LastType}::$_"} -Type Enum | 740 | Invoke-TabItemSelector ($LastType + '::') -SelectionHandler $SelectionHandler 741 | } else { 742 | $Constructors = Invoke-Expression "$LastType.GetConstructors()" | ForEach-Object { 743 | $Regex = New-Object Regex('\((.*)\)') 744 | $ParamTypes = foreach ($Type in $Regex.Match($_).Groups[1].Value.Split(',')) { 745 | "[$($Type.Trim())]" 746 | } 747 | $Param = [String]::Join(' , ',$ParamTypes) 748 | "New-Object $($LastType.Trim('[]'))($Param)".Replace('([])','()') 749 | } 750 | if ($Constructors) { 751 | $Constructors | New-TabItem -Value {$_} -Text {$_} -Type Constructor | 752 | Invoke-TabItemSelector $LastType -SelectionHandler $SelectionHandler 753 | } else { 754 | $LastWord 755 | } 756 | } 757 | } 758 | break 759 | } 760 | 761 | ## Handle members of Types (runtype) 762 | '^(\[.*\]).(\w*)$' { 763 | $LastType = $Matches[1].Split(',')[-1] 764 | Invoke-Expression "$LastType | Get-Member" | Where-Object {$_.Name -like "$($Matches[2])*"} | ForEach-Object { 765 | if ($_.MemberType -band $_Method) { 766 | $Value = "$LastType.$($_.Name)" + '(' 767 | New-TabItem -Value $Value -Text $Value -Type Method 768 | } else { 769 | $Value = "$LastType.$($_.Name)" 770 | New-TabItem -Value $Value -Text $Value -Type Property 771 | } 772 | } | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 773 | break 774 | } 775 | 776 | ## Handle namespace and type names 777 | '^\[(.*)$' { 778 | $Matched = $Matches[1] 779 | $Dots = $Matches[1].Split(".").Count - 1 780 | $res = @() 781 | $res += foreach ($Namespace in $dsTabExpansionDatabase.Tables['Types'].Select("NS like '$($Matched)%' and DC = $($Dots + 1)") | 782 | Select-Object -Unique NS) { 783 | $Value = "[$($Namespace.NS)" 784 | New-TabItem -Value $Value -Text $Value -Type Namespace 785 | } 786 | $res += foreach ($Namespace in $dsTabExpansionDatabase.Tables['Types'].Select("NS like 'System.$($Matched)%' and DC = $($Dots + 2)") | 787 | Select-Object -Unique NS) { 788 | $Value = "[$($Namespace.NS)" 789 | New-TabItem -Value $Value -Text $Value -Type Namespace 790 | } 791 | if ($Dots -gt 0) { 792 | $res += foreach ($Type in $dsTabExpansionDatabase.Tables['Types'].Select("Name like '$($Matched)%' and DC = $Dots")) { 793 | $Value = "[$($Type.Name)]" 794 | New-TabItem -Value $Value -Text $Value -Type Type 795 | } 796 | $res += foreach ($Type in $dsTabExpansionDatabase.Tables['Types'].Select("Name like 'System.$($Matched)%' and DC = $($Dots + 1)")) { 797 | $Value = "[$($Type.Name)]" 798 | New-TabItem -Value $Value -Text $Value -Type Type 799 | } 800 | } 801 | $res | Where-Object {$_} | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler -ForceList:$ForceList 802 | break 803 | } 804 | 805 | ## Handle expansions for both "Scope Variable Name" and "Type Variable Names" 806 | '^\$(\w+):(\w*)$' { 807 | $Type = $Matches[1] # function, variable, global, etc. 808 | $TypeName = $Matches[2] # e.g. in '$function:C', value will be 'C' 809 | 810 | if ($_ScopeNames -contains $Type) { 811 | # Scope variable name expansion ($global:, $script:, etc.) 812 | $Variables = foreach ($ScopeVariable in (Get-Variable "$TypeName*" -Scope $Type)) { 813 | '$' + (QuoteVariable ($Type + ":" + $ScopeVariable.Name)) 814 | } 815 | } else { 816 | # Type variable name expansion ($function:, $variable:, $env:, etc.) 817 | $Variables = foreach ($t in (Get-ChildItem ($Type + ":" + $TypeName + '*') | Sort-Object Name)) { 818 | '$' + (QuoteVariable ($Type + ":" + $t.Name)) 819 | } 820 | } 821 | $Variables | New-TabItem -Value {$_} -Text {$_} -Type Variable | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 822 | break 823 | } 824 | 825 | ## Handle variable name expansion 826 | '^([\$@])(\w*)$' { 827 | $VarName = $Matches[2] 828 | $Variables = foreach ($Variable in Get-Variable "$VarName*" -Scope Global) { 829 | $Matches[1] + (QuoteVariable $Variable.Name) 830 | } 831 | $Variables | New-TabItem -Value {$_} -Text {$_} -Type Variable | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 832 | break 833 | } 834 | 835 | ## Completion on cmdlets, function, aliases and native commands with defined shortcuts and custom additions from database 836 | 837 | ## Native commands / scripts in path 838 | "(.*)$([Regex]::Escape($PowerTabConfig.ShortcutChars.Native))`$" { 839 | & { 840 | Get-Command -CommandType ExternalScript -Name "$($Matches[1])*" | 841 | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Script 842 | Get-Command -CommandType Application -Name "$($Matches[1])*" | 843 | Where-Object {($env:PATHEXT).Split(";") -contains $_.Extension} | 844 | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Application 845 | } | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 846 | break 847 | } 848 | 849 | ## Aliases 850 | "(.+)$([Regex]::Escape($PowerTabConfig.ShortcutChars.Alias))`$" { 851 | & { 852 | Get-Command -CommandType Alias -Name $Matches[1] | New-TabItem -Value {$_.Definition} -Text {$_.Definition} -Type Alias 853 | Get-TabExpansion $Matches[1] Alias | New-TabItem -Value {$_.Text} -Text {$_.Text} -Type Alias 854 | } | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 855 | break 856 | } 857 | 858 | ## Custom 859 | "(.*)$([Regex]::Escape($PowerTabConfig.ShortcutChars.Custom))`$" { 860 | Get-TabExpansion "$($Matches[1])*" Custom | New-TabItem -Value {$_.Text} -Text {$_.Text} -Type Unknown | 861 | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 862 | break 863 | } 864 | 865 | ## Invoke 866 | "(.+)$([Regex]::Escape($PowerTabConfig.ShortcutChars.Invoke))`$" { 867 | Get-TabExpansion "$($Matches[1])*" Invoke | ForEach-Object { 868 | $ExecutionContext.InvokeCommand.InvokeScript($_.Text) | New-TabItem -Value {$_} -Text {$_} -Type Unknown 869 | } | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 870 | break 871 | } 872 | 873 | ## Call function 874 | "(.*)$([Regex]::Escape($PowerTabConfig.ShortcutChars.CustomFunction))`$" { 875 | if ($PowerTabConfig.CustomFunctionEnabled) { 876 | $Matches[1] | ForEach-Object { 877 | $ExecutionContext.InvokeCommand.InvokeScript("$($PowerTabConfig.CustomUserFunction) '$_'") | 878 | New-TabItem -Value {$_} -Text {$_} -Type Unknown 879 | } | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 880 | } 881 | break 882 | } 883 | 884 | ## Partial functions or cmdlets 885 | "(.*)$([Regex]::Escape($PowerTabConfig.ShortcutChars.Partial))`$" { 886 | ## TODO: Give different types? 887 | Get-Command -CommandType Function,ExternalScript,Filter,Cmdlet -Name "$($Matches[1])*" | 888 | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Command | 889 | Invoke-TabItemSelector $Matches[1] -SelectionHandler $SelectionHandler 890 | break 891 | } 892 | 893 | ## Functions or cmdlets on dash 894 | '(.+-.*)' { 895 | ## TODO: Give different types? 896 | Get-Command -CommandType Function,ExternalScript,Filter,Cmdlet -Name "$($Matches[1])*" | 897 | New-TabItem -Value {$_.Name} -Text {$_.Name} -Type Command | 898 | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 899 | break 900 | } 901 | 902 | ## Alternate alias 903 | '(.+)$' { 904 | if ($DoubleTab -or $PowerTabConfig.AliasQuickExpand) { 905 | & { 906 | Get-Command -CommandType Alias -Name $Matches[1] | New-TabItem -Value {$_.Definition} -Text {$_.Definition} -Type Alias 907 | Get-TabExpansion $Matches[1] Alias | New-TabItem -Value {$_.Text} -Text {$_.Text} -Type Alias 908 | } | Invoke-TabItemSelector $LastWord -SelectionHandler $SelectionHandler 909 | } else { 910 | Get-TabExpansion $Matches[1] Alias | New-TabItem -Value {$_.Text} -Text {$_.Text} -Type Alias | 911 | Invoke-TabItemSelector -SelectionHandler $SelectionHandler 912 | } 913 | break 914 | } 915 | } ## End of switch -regex $LastWord 916 | } | Where-Object {$_} | ForEach-Object {$TabExpansionHasOutput = $true; $_} 917 | 918 | ## Filesystem Completion 919 | if ((-not $TabExpansionHasOutput) -and $PowerTabConfig.FileSystemExpand) { 920 | $PowerTabFileSystemMode = $true 921 | $LastWord = $LastWord -replace '`' 922 | 923 | if (("Push-Location","Set-Location") -contains $Context.Command) { 924 | $ChildItems = @(Get-ChildItem "$LastWord*" | Where-Object {$_.PSIsContainer}) 925 | } else { 926 | $ChildItems = @(Get-ChildItem "$LastWord*") 927 | } 928 | if (-not $ChildItems) {$LastWord; return} 929 | 930 | #if ((@($childitems).count -eq 1) -and ($lastword.endswith('\')) ) {$childitems = $childitems,@{name='..'}} 931 | $PathSlices = [Regex]::Split($LastWord, '\\|/') 932 | if ($PathSlices.Count -eq 1) {$PathSlices = ,"." + $PathSlices} 933 | $Container = [String]::Join('\', $PathSlices[0..($PathSlices.Count -2)]) 934 | 935 | $LastPath = $Container + "\$([Regex]::Split($LastWord,'\\|/|:')[-1])" 936 | 937 | ## Fixes paths for registry keys, certificates and other unusual paths 938 | ## Improved fix for a problem identified by idvorkin (http://poshcode.org/1586) 939 | $ChildItems = foreach ($Item in $ChildItems) { 940 | $Child = switch ($Item.GetType().FullName) { 941 | "System.Security.Cryptography.X509Certificates.X509Certificate2" {$Item.Thumbprint;break} 942 | "Microsoft.Powershell.Commands.X509StoreLocation" {$Item.Location;break} 943 | "Microsoft.Win32.RegistryKey" {$Item.Name.Split("\")[-1];break} 944 | default {$Item.Name} 945 | } 946 | $Type = switch ($Item.GetType().FullName) { 947 | "System.IO.DirectoryInfo" {"Directory";break} 948 | "System.IO.FileInfo" {"File";break} 949 | "System.Management.Automation.AliasInfo" {"Alias";break} 950 | "System.Management.Automation.FilterInfo" {"Command";break} 951 | "System.Management.Automation.FunctionInfo" {"Command";break} 952 | "System.Security.Cryptography.X509Certificates.X509Certificate2" {"Certificate";break} 953 | "Microsoft.Powershell.Commands.X509StoreLocation" {"CertificateStore";break} 954 | "Microsoft.Win32.RegistryKey" {"RegistryKey";break} 955 | default {$_} 956 | } 957 | New-TabItem "$Container\$Child" "$Container\$Child" -Type $Type 958 | } 959 | $ChildItems | Invoke-TabItemSelector $LastPath -SelectionHandler $SelectionHandler -Return $LastWord -ForceList:$ForceList | ForEach-Object { 960 | ## If a path contains any of these characters it needs to be in quotes 961 | $_charsRequiringQuotes = ('`&@''#{}()$,; ' + "`t").ToCharArray() 962 | } { 963 | $Quote = '' 964 | $Invoke = '' 965 | 966 | if ($LastBlock -notmatch ".*['`"]`$") { ## Don't quote if it looks like the path is already quoted 967 | if ($_ -is [String]) { 968 | ## Remove quotes from beginning and end of string 969 | $_ = $_ -replace '^"|"$' 970 | ## Escape certain characters 971 | $_ = $_ -replace '([\$"`])','`$1' 972 | 973 | if ($_.IndexOfAny($_charsRequiringQuotes) -ge 0) { 974 | ## Check for quotes in the last block of the input line, 975 | ## if they exist, PowerShell will add them to this output 976 | ## if not, then quotes can safely be added 977 | if (-not (@([Char[]]$LastBlock | Where-Object {$_ -match '"|'''}).Count % 2)) {$Quote = '"'} 978 | if (($LastBlock.Trim() -eq $LastWord)) {$Invoke = '& '} 979 | } 980 | "$Invoke$Quote$_$Quote" 981 | } else { 982 | ## Remove quotes from beginning and end of string 983 | $_.Value = $_.Value -replace '^"|"$' 984 | ## Escape certain characters 985 | $_.Value = $_.Value -replace '([\$"`])','`$1' 986 | 987 | if ($_.Value.IndexOfAny($_charsRequiringQuotes) -ge 0) { 988 | ## Check for quotes in the last block of the input line, 989 | ## if they exist, PowerShell will add them to this output 990 | ## if not, then quotes can safely be added 991 | if (-not (@([Char[]]$LastBlock | Where-Object {$_ -match '"|'''}).Count % 2)) {$Quote = '"'} 992 | if (($LastBlock.Trim() -eq $LastWord)) {$Invoke = '& '} 993 | } 994 | $_.Value = "$Invoke$Quote$($_.Value)$Quote" 995 | $_ 996 | } 997 | } 998 | } 999 | } 1000 | 1001 | } ## End of outer script block 1002 | 1003 | if ($PowerTabConfig.IgnoreConfirmPreference) { 1004 | $ConfirmPreference = $OriginalConfirmPreference 1005 | } 1006 | 1007 | } # end-function 1008 | --------------------------------------------------------------------------------