├── .gitignore ├── images ├── lsresult.png ├── getcommandresult.png ├── getserviceresult.png ├── selectstringresult.png └── selectstringwithcontextresult.png ├── LICENSE ├── Build.ps1 ├── Install.ps1 ├── src ├── Renderers │ ├── EventLogRecordRenderer.ps1 │ ├── PSModuleInfoRenderer.ps1 │ ├── CommandInfoRenderer.ps1 │ ├── ServiceControllerRenderer.ps1 │ ├── PSDriveInfoRenderer.ps1 │ ├── MemberDefinitionRenderer.ps1 │ ├── MatchInfoRenderer.ps1 │ └── FileRenderer.ps1 ├── Themes │ ├── Default.ps1 │ ├── DefaultHighColor.ps1 │ └── Cool.ps1 ├── PoshColorFunctions.ps1 ├── PoshColor.psd1 ├── PoshColor.psm1 └── New-CommandWrapper.ps1 └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | release/ 2 | release.ps1 -------------------------------------------------------------------------------- /images/lsresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustABearOz/PoshColor/HEAD/images/lsresult.png -------------------------------------------------------------------------------- /images/getcommandresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustABearOz/PoshColor/HEAD/images/getcommandresult.png -------------------------------------------------------------------------------- /images/getserviceresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustABearOz/PoshColor/HEAD/images/getserviceresult.png -------------------------------------------------------------------------------- /images/selectstringresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustABearOz/PoshColor/HEAD/images/selectstringresult.png -------------------------------------------------------------------------------- /images/selectstringwithcontextresult.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JustABearOz/PoshColor/HEAD/images/selectstringwithcontextresult.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 JustABearOz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Build.ps1: -------------------------------------------------------------------------------- 1 | function ZipFiles( $zipfilename, $sourcedir ) 2 | { 3 | Add-Type -Assembly System.IO.Compression.FileSystem 4 | 5 | $compressionLevel = [System.IO.Compression.CompressionLevel]::Optimal 6 | 7 | [System.IO.Compression.ZipFile]::CreateFromDirectory($sourcedir, $zipfilename, $compressionLevel, $false) 8 | } 9 | 10 | $Error.Clear() 11 | 12 | $source = Join-Path -Path $PSScriptRoot -ChildPath "src" 13 | $target = Join-Path -Path $PSScriptRoot -ChildPath "release" 14 | 15 | if (!(Test-Path $target)) 16 | { 17 | 18 | Write-Host "Creating Release Directory" 19 | 20 | New-Item $target -type Directory 21 | } 22 | else 23 | { 24 | Write-Host "Cleaning Release directory" 25 | 26 | $removeItems = Join-Path $target "*" 27 | 28 | remove-item $removeItems -recurse -force 29 | } 30 | 31 | $targetfile = Join-Path -Path $target -ChildPath "PoshColor.zip" 32 | 33 | Write-Host "Creating release package $targetfile" 34 | 35 | ZipFiles $targetfile $source 36 | 37 | if ($Error.Count -eq 0) 38 | { 39 | Write-Host "Build Succesful" -ForegroundColor Green 40 | } 41 | else 42 | { 43 | Write-Host "One or more errors occured" -ForegroundColor Red 44 | } 45 | 46 | copy-item .\src\ .\release\PoshColor\ -recurse -container -force -------------------------------------------------------------------------------- /Install.ps1: -------------------------------------------------------------------------------- 1 | if ((get-module PoshColor) -ne $null) 2 | { 3 | ## Uninstall the existing Version 4 | Remove-Module PoshColor 5 | } 6 | 7 | $modulePath = $env:PSModulePath.Split([IO.Path]::PathSeparator)[0] 8 | 9 | $modulePath = Join-Path $modulePath "PoshColor" 10 | 11 | if ((Test-Path $modulePath) -eq $false) 12 | { 13 | New-Item $modulePath -Type Directory 14 | } 15 | 16 | $poshColorModule = Join-Path . "src" 17 | $poshColorModule = Join-Path $poshColorModule "PoshColor.psd1" 18 | 19 | $module = (Get-Module $poshColorModule -ListAvailable) 20 | 21 | Write-Host $module.Version 22 | 23 | $major = $module.Version.Major.ToString() 24 | $minor = $module.Version.Minor.ToString() 25 | $build = $module.Version.Build.ToString() 26 | $revision = $module.Version.Revision.ToString() 27 | 28 | $version = $major + "." + $minor + "." + $build + "." + $revision 29 | 30 | $modulePath = Join-Path $modulePath $version 31 | 32 | if ((Test-Path $modulePath) -eq $false) 33 | { 34 | Write-Host "Creating Module Path $modulePath" 35 | 36 | New-Item $modulePath -Type Directory 37 | } 38 | 39 | $moduleSource = Join-Path "." "src" 40 | $moduleSource = Join-Path $moduleSource "*" 41 | 42 | copy-item $moduleSource $modulePath -Recurse -Force 43 | 44 | Import-Module PoshColor -------------------------------------------------------------------------------- /src/Renderers/EventLogRecordRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-EventLogHeader 2 | { 3 | ## Do we need to write headers? 4 | if (($script:currentDirectory -eq "")) 5 | { 6 | Write-Host 7 | Write-Host "Time Created Id Level Provider Message" 8 | Write-Host "------------ ------ -------- -------- ----------------" 9 | 10 | $script:currentDirectory = "EventLog" 11 | } 12 | } 13 | 14 | function Write-EventLog 15 | { 16 | param ([Parameter(Mandatory=$True,Position=1)] $item) 17 | 18 | Write-EventLogHeader 19 | 20 | $foreground = $global:PoshColor.EventLog.Default.Color 21 | 22 | if ($item.Level -eq 1) 23 | { 24 | # Critical 25 | $foreground = $global:PoshColor.EventLog.Critical.Color 26 | } 27 | elseif ($item.Level -eq 2) 28 | { 29 | $foreground = $global:PoshColor.EventLog.Error.Color 30 | } 31 | elseif ($item.Level -eq 3) 32 | { 33 | $foreground = $global:PoshColor.EventLog.Warning.Color 34 | } 35 | elseif ($item.Level -eq 4) 36 | { 37 | $foreground = $global:PoshColor.EventLog.Information.Color 38 | } 39 | 40 | $providerName = $item.ProviderName.ToString() 41 | 42 | if ($providerName.Length -gt 20) 43 | { 44 | $providerName = $providerName.Substring(20) 45 | } 46 | 47 | $info = [String]::Format("{0,-22} {1, -7} {2, -12} {3, -20} {4}", $item.TimeCreated.ToString("G"), $item.Id, $item.LevelDisplayName, $providerName, $item.Message) 48 | 49 | Write-HostColor $info -Foreground $foreground 50 | 51 | return $true; 52 | } -------------------------------------------------------------------------------- /src/Renderers/PSModuleInfoRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-ModuleHeader 2 | { 3 | ## Do we need to write headers? 4 | if (($script:currentDirectory -eq "")) 5 | { 6 | Write-Host 7 | Write-Host "ModuleType Version Name ExportedCommands" 8 | Write-Host "---------- ------- ---- ----------------" 9 | 10 | $script:currentDirectory = "Modules" 11 | } 12 | } 13 | 14 | function Write-Module 15 | { 16 | param ([Parameter(Mandatory=$True,Position=1)] $item) 17 | 18 | Write-ModuleHeader 19 | 20 | 21 | $foreground = $global:PoshColor.Module.Default.Color 22 | 23 | if ($item.ModuleType.ToString() -eq 'Binary') { 24 | $foreground = $global:PoshColor.Module.Binary.Color 25 | } 26 | elseif($item.ModuleType.ToString() -eq 'Cim') { 27 | $foreground = $global:PoshColor.Module.Cim.Color 28 | } 29 | elseif($item.ModuleType.ToString() -eq 'Manifest') { 30 | $foreground = $global:PoshColor.Module.Manifest.Color 31 | } 32 | elseif($item.ModuleType.ToString() -eq 'Script') { 33 | $foreground = $global:PoshColor.Module.Script.Color 34 | } 35 | elseif($item.ModuleType.ToString() -eq 'Workflow') { 36 | $foreground = $global:PoshColor.Module.Workflow.Colorz 37 | } 38 | 39 | $info = [String]::Format("{0,-10} {1, -10} {2, -36}", $item.ModuleType, $item.Version, $item.Name) 40 | 41 | $commands = [String]::Join(",", $item.ExportedCommands.Keys) 42 | 43 | $width = $Host.UI.RawUI.WindowSize.Width - $info.Length - 6; 44 | 45 | if ($width -lt 30) 46 | { 47 | $width = 30 48 | } 49 | 50 | if ($commands.Length -ge $width) 51 | { 52 | $commands = $commands.Substring(0, $width) + ".." 53 | } 54 | 55 | $info = $info + "{$commands}" 56 | 57 | Write-HostColor $info -Foreground $foreground 58 | 59 | return $true; 60 | } -------------------------------------------------------------------------------- /src/Renderers/CommandInfoRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-CommandHeaderInfo{ 2 | 3 | if ($script:currentDirectory -eq "") 4 | { 5 | Write-Host 'CommandType Name Version Source' 6 | Write-Host '----------- ---- ------- ------' 7 | 8 | $script:currentDirectory = "CommandInfo" 9 | } 10 | } 11 | 12 | function Write-CommandInfo 13 | { 14 | param ([Parameter(Mandatory=$True,Position=1)] $item) 15 | 16 | Write-CommandHeaderInfo 17 | 18 | $output = [System.String]::Format("{0, -16}{1, -51}{2,-11}{3}", $item.CommandType, $item.Name, $item.Version, $item.Module.Name) 19 | 20 | $foreground = $global:PoshColor.CommandInfo.Default.Color 21 | 22 | if ($item -is [System.Management.Automation.ApplicationInfo]) 23 | { 24 | $foreground = $global:PoshColor.CommandInfo.Application.Color 25 | } 26 | elseif ($item -is [System.Management.Automation.CmdletInfo]) 27 | { 28 | $foreground = $global:PoshColor.CommandInfo.CommandLet.Color 29 | } 30 | elseif ($item -is [System.Management.Automation.ExternalScriptInfo]) 31 | { 32 | $foreground = $global:PoshColor.CommandInfo.ExternalScript.Color 33 | } 34 | elseif ($item -is [System.Management.Automation.FunctionInfo]) 35 | { 36 | $foreground = $global:PoshColor.CommandInfo.Function.Color 37 | } 38 | elseif ($item -is [System.Management.Automation.RemoteCommandInfo]) 39 | { 40 | $foreground = $global:PoshColor.CommandInfo.RemoteCommand.Color 41 | } 42 | elseif ($item -is [System.Management.Automation.ScriptInfo]) 43 | { 44 | $foreground = $global:PoshColor.CommandInfo.ScriptInfo.Color 45 | } 46 | elseif ($item -is [System.Management.Automation.AliasInfo]) 47 | { 48 | $foreground = $global:PoshColor.CommandInfo.Alias.Color 49 | } 50 | 51 | Write-HostColor $output -Foreground $foreground 52 | 53 | return $true 54 | } 55 | -------------------------------------------------------------------------------- /src/Renderers/ServiceControllerRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-ServiceHeader 2 | { 3 | if (($script:currentDirectory -eq "")) 4 | { 5 | Write-Host "" 6 | Write-Host "Status Name DisplayName Startup" 7 | Write-Host "------ ---- ----------- -------" 8 | 9 | $script:currentDirectory = "Services" 10 | } 11 | } 12 | 13 | function Write_Service 14 | { 15 | param ([Parameter(Mandatory=$True,Position=1)] $item) 16 | 17 | Write-ServiceHeader 18 | 19 | $foreground = $global:PoshColor.Service.Default.Color 20 | $background = $global:PoshColor.Service.Default.BackgroundColor 21 | 22 | $name = $item.Name 23 | 24 | $trimmedName = Trim $name 18 25 | 26 | $displayName = $item.DisplayName 27 | 28 | if (!$displayName -or $null -eq $displayName) 29 | { 30 | $displayName = "" 31 | } 32 | 33 | $trimmedDisplayName = Trim $displayName 38 34 | 35 | if ($null -eq $item.StartupType) 36 | { 37 | $startupType = "Unknown" 38 | } 39 | else { 40 | $startupType = $item.StartupType.ToString() 41 | 42 | if (!$startupType -or $null -eq $startupType) 43 | { 44 | $startupType = "Unknown" 45 | } 46 | } 47 | 48 | $startup = Trim $startupType 20 49 | 50 | $status = $item.Status.ToString() 51 | 52 | if ($status -eq 'Running') 53 | { 54 | $foreground = $global:PoshColor.Service.Running.Color 55 | $background = $global:PoshColor.Service.Running.BackgroundColor 56 | } 57 | elseif ($status -eq 'Stopped') 58 | { 59 | $foreground = $global:PoshColor.Service.Stopped.Color 60 | $background = $global:PoshColor.Service.Stopped.BackgroundColor 61 | } 62 | 63 | if (!$status -or $status -eq "") 64 | { 65 | $status = "Unknown" 66 | } 67 | 68 | if (!$startup -or $startup -eq "") 69 | { 70 | $startup = "Unmknown"; 71 | } 72 | 73 | $statusText = [String]::Format("{0, -8}", $status) 74 | $outputText = [String]::Format(" {0, -18} {1, -38} {2, -20}", $trimmedName, $trimmedDisplayName, $startup) 75 | 76 | Write-HostColor $statusText -Foreground $foreground -Background $background -noNewLine 77 | Write-HostColor $outputText -Foreground $global:PoshColor.Service.Properties.Color -Background $global:PoshColor.Service.Properties.BackgroundColor 78 | 79 | return $true 80 | } 81 | -------------------------------------------------------------------------------- /src/Themes/Default.ps1: -------------------------------------------------------------------------------- 1 | $global:PoshColor = @{ 2 | UseConsoleColors = $true 3 | DirectoryForeground = 'Green' 4 | File = [ordered]@{ 5 | HiddenDirectory = @{ Color = 'DarkBlue'; Hidden = $true; Directory = $true; BackgroundColor = 'White' } 6 | CompressedDirectory = @{ Color = 'Blue'; Compressed = $true} 7 | Hidden = @{ Color = 'DarkGray'; Hidden = $true } 8 | IgnoreFiles= @{ Color = 'Gray'; Pattern = '^\.' } 9 | Code = @{ Color = 'DarkYellow'; Pattern = '\.(java|c|cpp|cs|js|css|html|vb)$' } 10 | Executable = @{ Color = 'Red'; Pattern = '\.(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|ps1|sh)$' } 11 | Text = @{ Color = 'Yellow'; Pattern = '\.(txt|cfg|conf|ini|csv|log|config|xml|yml|md|markdown)$' } 12 | Compressed = @{ Color = 'Green'; Pattern = '\.(zip|tar|gz|rar|jar|war)$' } 13 | Directory = @{ Color = 'Cyan'; Directory = $true} 14 | System = @{ Color = 'Magenta'; System = $true} 15 | Default = @{ Color = 'White' } 16 | } 17 | Service = @{ 18 | Running = @{ Color = 'DarkGreen'} 19 | Stopped = @{ Color = 'DarkRed'} 20 | Default = @{ Color = 'DarkGray'} 21 | Properties = @{ Color = 'White'} 22 | } 23 | Match = @{ 24 | Default = @{Color = 'White'} 25 | MatchText = @{ Color = 'Cyan'} 26 | Match = @{Color = 'White'} 27 | LineNumber = @{Color = 'Red'} 28 | File = @{Color = 'Green'} 29 | } 30 | Module = @{ 31 | Binary = @{Color = 'White'} 32 | Cim = @{Color = 'Cyan'} 33 | Manifest = @{Color = 'Green'} 34 | Script = @{Color = 'Yellow'} 35 | Workflow = @{Color = 'Magenta'} 36 | } 37 | EventLog = @{ 38 | Critical = @{Color = 'Magenta'} 39 | Error = @{Color = 'Red'} 40 | Warning = @{Color = 'Yellow'} 41 | Information = @{Color = 'White'} 42 | Default = @{Color = 'Gray'} 43 | } 44 | PSDriveInfo = @{ 45 | Alias = @{Color = 'DarkGray'} 46 | FileSystem = @{Color = 'Green'} 47 | Certificate = @{Color = 'DarkCyan'} 48 | Environment = @{Color = 'Gray'} 49 | Function = @{Color = 'DarkYellow'} 50 | Registry = @{Color = 'DarkBlue'} 51 | Variable = @{Color = 'Cyan'} 52 | WSMan = @{Color = 'Blue'} 53 | Default = @{Color = 'White'} 54 | LowSpace = @{Color = 'Red'} 55 | LowSpacePercent = @{Value = 20} 56 | } 57 | CommandInfo = @{ 58 | Default = @{Color = 'White'} 59 | Alias = @{Color = 'Green'} 60 | Script = @{Color = 'DarkBlue'} 61 | Function = @{Color = 'Yellow'} 62 | CommandLet = @{Color = 'Cyan'} 63 | Application = @{Color = 'Gray'} 64 | RemoteCommand = @{Color = 'DarkGray'} 65 | ExternalScript = @{Color = 'DarkGreen'} 66 | } 67 | } -------------------------------------------------------------------------------- /src/Themes/DefaultHighColor.ps1: -------------------------------------------------------------------------------- 1 | $global:PoshColor = @{ 2 | UseConsoleColors = $false 3 | DirectoryForeground = '#00FF00' 4 | File = [ordered]@{ 5 | HiddenDirectory = @{ Color = '#000080'; Hidden = $true; Directory = $true; BackgroundColor = '#FFFFFF' } 6 | CompressedDirectory = @{ Color = '#0000FF'; Compressed = $true} 7 | Hidden = @{ Color = '#808080'; Hidden = $true } 8 | IgnoreFiles= @{ Color = '#C0C0C0'; Pattern = '^\.' } 9 | Code = @{ Color = '#808000'; Pattern = '\.(java|c|cpp|cs|js|css|html|vb)$' } 10 | Executable = @{ Color = '#FF0000'; Pattern = '\.(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|ps1|sh)$' } 11 | Text = @{ Color = '#FFFF00'; Pattern = '\.(txt|cfg|conf|ini|csv|log|config|xml|yml|md|markdown)$' } 12 | Compressed = @{ Color = '#00FF00'; Pattern = '\.(zip|tar|gz|rar|jar|war)$' } 13 | Directory = @{ Color = '#00FFFF'; Directory = $true} 14 | System = @{ Color = '#FF00FF'; System = $true} 15 | Default = @{ Color = '#FFFFFF' } 16 | } 17 | Service = @{ 18 | Running = @{ Color = "#00FF00"} 19 | Stopped = @{ Color = "#FF0000"} 20 | Default = @{ Color = "#C0C0C0"} 21 | Properties = @{ Color = '#FFFFFF'} 22 | } 23 | Match = @{ 24 | Default = @{Color = '#C0C0C0'} 25 | MatchText = @{ Color = '#00FFFF'} 26 | Match = @{Color = '#FFFFFF'} 27 | LineNumber = @{Color = '#FF0000'} 28 | File = @{Color = '#00FF00'} 29 | } 30 | Module = @{ 31 | Binary = @{Color = '#dddddd'} 32 | Cim = @{Color = '#00FFFF'} 33 | Manifest = @{Color = '#00FF00'} 34 | Script = @{Color = '#FFFF00'} 35 | Workflow = @{Color = '#FF00FF'} 36 | } 37 | EventLog = @{ 38 | Critical = @{Color = '#FF00FF'} 39 | Error = @{Color = '#FF0000'} 40 | Warning = @{Color = '#FFFF00'} 41 | Information = @{Color = '#C0C0C0'} 42 | Default = @{Color = '#FFFFFF'} 43 | } 44 | PSDriveInfo = @{ 45 | Alias = @{Color = '#808080'} 46 | FileSystem = @{Color = '#00FF00'} 47 | Certificate = @{Color = '#00C0C0'} 48 | Environment = @{Color = '#C0C0C0'} 49 | Function = @{Color = '#FFFF00'} 50 | Registry = @{Color = '#808000'} 51 | Variable = @{Color = '#FF00FF'} 52 | WSMan = @{Color = '#0000FF'} 53 | Default = @{Color = '#FFFFFF'} 54 | LowSpace = @{Color = '#FF0000'} 55 | LowSpacePercent = @{Value = 20} 56 | } 57 | CommandInfo = @{ 58 | Default = @{Color = '#FFFFFF'} 59 | Alias = @{Color = '#00FF00'} 60 | Script = @{Color = '#00FFFF'} 61 | Function = @{Color = '#FFFF00'} 62 | CommandLet = @{Color = '#FF00FF'} 63 | Application = @{Color = '#C0C0C0'} 64 | RemoteCommand = @{Color = '#808080'} 65 | ExternalScript = @{Color = '#008000'} 66 | } 67 | } -------------------------------------------------------------------------------- /src/Renderers/PSDriveInfoRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-DriveInfoHeader 2 | { 3 | if (($script:currentDirectory -eq "")) 4 | { 5 | Write-Host "" 6 | Write-Host "Name Used (GB) Free (GB) Provider Root" 7 | Write-Host "---- --------- --------- -------- ----" 8 | 9 | $script:currentDirectory = "PSDriveInfo" 10 | } 11 | } 12 | 13 | function Write-PSDrive 14 | { 15 | param ([Parameter(Mandatory=$True,Position=1)] $item) 16 | 17 | Write-DriveInfoHeader 18 | 19 | $foreground = $global:PoshColor.PSDriveInfo.Default.Color 20 | 21 | if ($item.Provider.Name -eq 'Alias') 22 | { 23 | $foreground = $global:PoshColor.PSDriveInfo.Alias.Color 24 | } 25 | elseif ($item.Provider.Name -eq 'FileSystem') 26 | { 27 | $foreground = $global:PoshColor.PSDriveInfo.FileSystem.Color 28 | } 29 | elseif ($item.Provider.Name -eq 'Certificate') 30 | { 31 | $foreground = $global:PoshColor.PSDriveInfo.Certificate.Color 32 | } 33 | elseif ($item.Provider.Name -eq 'Environment') 34 | { 35 | $foreground = $global:PoshColor.PSDriveInfo.Environment.Color 36 | } 37 | elseif ($item.Provider.Name -eq 'Function') 38 | { 39 | $foreground = $global:PoshColor.PSDriveInfo.Function.Color 40 | } 41 | elseif ($item.Provider.Name -eq 'Registry') 42 | { 43 | $foreground = $global:PoshColor.PSDriveInfo.Registry.Color 44 | } 45 | elseif ($item.Provider.Name -eq 'Variable') 46 | { 47 | $foreground = $global:PoshColor.PSDriveInfo.Variable.Color 48 | } 49 | elseif ($item.Provider.Name -eq 'WSMan') 50 | { 51 | $foreground = $global:PoshColor.PSDriveInfo.WSMan.Color 52 | } 53 | 54 | $used = (($item.Used / 1024) / 1024) / 1024 55 | $free = (($item.Free / 1024) / 1024) / 1024 56 | 57 | $usedText = [System.Math]::Round($used, 2).ToString("#.##") 58 | $freeText = [System.Math]::Round($free, 2).ToString("#.##") 59 | 60 | $output = [System.String]::Format("{0,-14} {1,9} ", $item.Name, $usedText) 61 | $freeOutput = [System.String]::Format("{0, 13}", $freeText) 62 | $providerOutput = [System.String]::Format(" {0, -13} {1}", $item.Provider.Name, $item.Root) 63 | 64 | Write-HostColor $output -Foreground $foreground -noNewLine 65 | 66 | $freeForeground = $foreground 67 | 68 | $totalSize = $item.Used + $item.Free 69 | 70 | if (!($null -eq $totalSize) -and $totalSize -ne 0) 71 | { 72 | $freePercent = (100 / $totalSize) * $item.Free 73 | 74 | $percentage = $global:PoshColor.PSDriveInfo.LowSpacePercent.Value 75 | 76 | if ($freePercent -lt $percentage) 77 | { 78 | $freeForeground = $global:PoshColor.PSDriveInfo.LowSpace.Color 79 | } 80 | } 81 | 82 | Write-HostColor $freeOutput -Foreground $freeForeground -noNewLine 83 | 84 | Write-HostColor $providerOutput -Foreground $foreground 85 | 86 | return $true 87 | } -------------------------------------------------------------------------------- /src/Themes/Cool.ps1: -------------------------------------------------------------------------------- 1 | $global:PoshColor = @{ 2 | UseConsoleColors = $false 3 | DirectoryForeground = '#00bb00' 4 | File = [ordered]@{ 5 | HiddenDirectory = @{ Color = '#707070'; Hidden = $true; Directory = $true } 6 | CompressedDirectory = @{ Color = '#00f1f1'; Compressed = $true; Directory = $true } 7 | Hidden = @{ Color = '#505050'; Hidden = $true } 8 | IgnoreFiles= @{ Color = '#909090'; Pattern = '^\.' } 9 | Code = @{ Color = '#0077cc'; Pattern = '\.(java|c|cpp|cs|js|css|html)$' } 10 | Executable = @{ Color = '#22ee22'; Pattern = '\.(exe|bat|cmd|py|pl|ps1|psm1|vbs|rb|reg|ps1|sh)$' } 11 | Text = @{ Color = '#119911'; Pattern = '\.(txt|cfg|conf|ini|csv|log|config|xml|yml|md|markdown)$' } 12 | Compressed = @{ Color = '#006699'; Pattern = '\.(zip|tar|gz|rar|jar|war)$' } 13 | Directory = @{ Color = '#00aadd'; Directory = $true} 14 | System = @{ Color = '#00ffaa'; System = $true} 15 | Default = @{ Color = '#dddddd' } 16 | } 17 | Service = @{ 18 | Running = @{ Color = '#00bb00'} 19 | Stopped = @{ Color = '#00aadd'} 20 | Default = @{ Color = '#505050'} 21 | Properties = @{ Color = '#dddddd'} 22 | } 23 | Match = @{ 24 | Default = @{Color = '#cccccc'} 25 | MatchText = @{ Color = '#00aadd'} 26 | Match = @{Color = '#dddddd'} 27 | LineNumber = @{Color = '#0055aa'} 28 | File = @{Color = '#00bb00'} 29 | } 30 | Module = @{ 31 | Default = @{Color = '#dddddd'} 32 | Binary = @{Color = '#cccccc'} 33 | Cim = @{Color = '#505050'} 34 | Manifest = @{Color = '#11cc11'} 35 | Script = @{Color = '#00aadd'} 36 | Workflow = @{Color = '#00ffaa'} 37 | } 38 | EventLog = @{ 39 | Critical = @{Color = '#006699'} 40 | Error = @{Color = '#00aadd'} 41 | Warning = @{Color = '#00ffaa'} 42 | Information = @{Color = '#cccccc'} 43 | Default = @{Color = '#909090'} 44 | } 45 | PSDriveInfo = @{ 46 | Alias = @{Color = '#909090'} 47 | FileSystem = @{Color = '#11cc11'} 48 | Certificate = @{Color = '#909090'} 49 | Environment = @{Color = '#909090'} 50 | Function = @{Color = '#00aadd'} 51 | Registry = @{Color = '#0055aa'} 52 | Variable = @{Color = '#00bb00'} 53 | WSMan = @{Color = '#909090'} 54 | Default = @{Color = '#dddddd'} 55 | LowSpace = @{Color = '#00f1f1'} 56 | LowSpacePercent = @{Value = 20} 57 | } 58 | CommandInfo = @{ 59 | Default = @{Color = '#dddddd'} 60 | Alias = @{Color = '#00aadd'} 61 | Script = @{Color = '#0055aa'} 62 | Function = @{Color = '#11cc11'} 63 | CommandLet = @{Color = '#00f1f1'} 64 | Application = @{Color = '#dddddd'} 65 | RemoteCommand = @{Color = '#909090'} 66 | ExternalScript = @{Color = '#00bb00'} 67 | } 68 | PSMemberType = @{ 69 | Default = @{Color = '#dddddd'} 70 | 71 | Property = @{Color = '#55aa55'} 72 | PropertySet = @{Color = '#008800'} 73 | Properties = @{Color = '#00aa00'} 74 | AliasProperty = @{Color = '#00cc00'} 75 | CodeProperty = @{Color = '#00ee00'} 76 | ParameterizedProperty = @{Color = '#22ff22'} 77 | ScriptProperty = @{Color = '#66ff66'} 78 | InferredProperty = @{Color = '#88ff55'} 79 | Event = @{Color = '#dddddd'} 80 | MemberSet = @{Color = '#909090'} 81 | NoteProperty = @{Color = '#00f1f1'} 82 | Method = @{Color = '#0055ff'} 83 | Methods = @{Color = '#0000dd'} 84 | ScriptMethod = @{Color = '#0000ff'} 85 | CodeMethod = @{Color = '#0055aa'} 86 | Dynamic = @{Color = '#5555aa'} 87 | } 88 | } -------------------------------------------------------------------------------- /src/PoshColorFunctions.ps1: -------------------------------------------------------------------------------- 1 | function Pad 2 | { 3 | param([System.String] $value, [System.Int32] $length) 4 | 5 | return $value.PadRight($length) 6 | } 7 | function New-ColorVTSequence 8 | { 9 | param([System.String] $value) 10 | 11 | $color = [System.Drawing.ColorTranslator]::FromHtml($value) 12 | 13 | $r = $color.R; 14 | $g = $color.G; 15 | $b = $color.B; 16 | 17 | return "$r;$g;$b"; 18 | } 19 | 20 | function New-ForegroundVTSequence 21 | { 22 | param([System.String] $hexColor) 23 | 24 | $rgbSequence = New-ColorVTSequence -value $hexColor 25 | 26 | return "38;2;$rgbSequence" 27 | } 28 | 29 | function New-BackgroundVTSequence 30 | { 31 | param([System.String] $hexColor) 32 | 33 | $rgbSequence = New-ColorVTSequence -value $hexColor 34 | 35 | return "48;2;$rgbSequence" 36 | } 37 | 38 | function New-TextColorVTSequence{ 39 | param([System.String] $foregroundHexColor, [System.String] $backgroundHexColor) 40 | 41 | $result = New-ColorVTSequence -value $foregroundHexColor 42 | 43 | if ($backgroundHexColor) 44 | { 45 | $backgroundSequence = New-ColorVTSequence -value $backgroundHexColor 46 | 47 | $result = "$result;$backgroundSequence"; 48 | } 49 | 50 | return "$result" + "m" 51 | } 52 | 53 | function Convert-ToRGB 54 | { 55 | param([System.String]$color) 56 | 57 | $colorValue = [System.Drawing.Color]::FromName($color) 58 | 59 | # if the passed in color name is not a known name, just use white 60 | if (!$colorValue.IsKnownColor) 61 | { 62 | $colorValue = [System.Drawing.Color]::White 63 | } 64 | 65 | $hexValue = "#" + $colorValue.R.ToString() + $colorValue.G.ToString() + $colorValue.B.ToString() 66 | 67 | return $hexValue 68 | } 69 | 70 | function Write-HostColor 71 | { 72 | param ([Parameter(Position=0)] [System.String] $text, [Parameter(Position=1)][System.String] $foreground, [System.String] $background, [switch] $noNewLine = $false) 73 | 74 | if ($global:PoshColor.UseConsoleColors) 75 | { 76 | if ($background) 77 | { 78 | if ($noNewLine) 79 | { 80 | Write-Host $text -ForegroundColor $foreground -BackgroundColor $background -NoNewline 81 | } 82 | else { 83 | Write-Host $text -ForegroundColor $foreground -BackgroundColor $background 84 | } 85 | } 86 | else { 87 | if ($noNewLine) 88 | { 89 | Write-Host $text -ForegroundColor $foreground -NoNewline 90 | } 91 | else { 92 | Write-Host $text -ForegroundColor $foreground 93 | } 94 | } 95 | } 96 | else { 97 | 98 | ## Try and parse colours as named colors 99 | if (!$foreground.StartsWith("#")) 100 | { 101 | $foreground = (Convert-ToRGB $foreground) 102 | } 103 | 104 | $foregroundSequence = New-ForegroundVTSequence -hexColor $foreground 105 | 106 | if ($background) 107 | { 108 | if (!$background.StartsWith("#")) 109 | { 110 | $background = (Convert-ToRGB $background) 111 | } 112 | 113 | $backgroundSequence = New-BackgroundVTSequence -hexColor $background 114 | } 115 | 116 | $vtSequence = "$foregroundSequence" 117 | 118 | if ($backgroundSequence) 119 | { 120 | $vtSequence = "$vtSequence;$backgroundSequence"; 121 | } 122 | 123 | $vtSequence = "`e[$vtSequence" + "m" 124 | 125 | if ($noNewLine) 126 | { 127 | Write-Host "$vtSequence$text" -NoNewLine 128 | } 129 | else { 130 | Write-Host "$vtSequence$text" 131 | } 132 | } 133 | } 134 | 135 | function Trim 136 | { 137 | param ([Parameter(Mandatory=$True,Position=1)][string] $text, [Parameter(Mandatory=$True,Position=2)][int] $length) 138 | 139 | if ($text.Length -gt $length) 140 | { 141 | $text = $text.Substring(0, $length - 3) + "..." 142 | } 143 | 144 | return $text; 145 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PoshColor 2 | PoshColor is a blatant ripoff of [PSColor](https://github.com/Davlind/PSColor) :relaxed:, allowing you to customise items in powershell based on your own color preferences. PoshColor works in Powershell Core and works across both Windows and Linux. 3 | 4 | PSColozier can use either standard console colors or 8 bit RGB allowing 16 million colour goodness. 5 | 6 | ## Features 7 | * Colors can be set to RGB or Named colors from .Net (System.Drawing.Color) 8 | * Tested under Windows (powershell and powershell core) and Linux (Ubuntu/bash Ubuntu/powershell core) 9 | * Support for Background colors 10 | * Coloring of: 11 | * EventLogRecord (get-winevent) 12 | * Files, Directories (ls / get-childitem) 13 | * MatchInfo (select-string) 14 | * MemberInfo (get-member) 15 | * PSModuleInfo (get-module) 16 | * PSDriveInfo (get-psdrive) 17 | * Services (get-service) 18 | * Files & Directories can have rules for coloring including based the following: 19 | * File Names using regular expressions 20 | * File Attributes such as directory, hidden, system, encypted or compressed 21 | * Theme support 22 | * Can be unloaded/reloaded without causing issues in your current session 23 | 24 | ### Screenshot of Get-Childitem 25 | ![Screenshot of get-childitem](images/lsresult.png) 26 | 27 | ### Screenshot of Select String with -Context 1 28 | ![Screenshot of select-string with context](images/selectstringwithcontextresult.png) 29 | 30 | ### Screenshot of Get-Service 31 | ![Screenshot of Get-Service](images/getserviceresult.png) 32 | 33 | ### Get-Command 34 | ![Screenshot of Get-Command](images/getcommandresult.png) 35 | ## Themes 36 | There are currently 3 themes that come with PoshColor. Feel free to contribute more themes to make PoshColor the best it can be. 37 | 38 | ### Included themes 39 | |Theme Name| Description| 40 | |--|--| 41 | |Default|The default theme using standard terminal colors| 42 | |DefaultHighColor| Similar styling to Default, but uses 8 bit RGB colors| 43 | |Cool| Uses RGB colors to provide a theme based on whites, blues and greens| 44 | 45 | ## Comands 46 | |Command|Description| 47 | |---|---| 48 | |Get-PoshColorTheme|Gets the current theme being used by PoshColor| 49 | |Set-PoshColorTheme|Sets the current theme for PoshColor to use| 50 | |Get-PoshColorThemes|Gets a list of all installed PoshColor themes| 51 | 52 | ## Installation 53 | ### PowershellGallery 54 | ```powershell 55 | Install-Module PoshColor 56 | 57 | Import-Module PoshColor 58 | ``` 59 | ### Install from source 60 | ```powershell 61 | git clone https://github.com/JustABearOz/PoshColor.git 62 | 63 | sl .\PoshColor 64 | 65 | .\Install.ps1 66 | ``` 67 | 68 | ### Install from Zip 69 | Download the latest [release](https://github.com/JustABearOz/PoshColor/releases) and extract it into your powershell modules directory. 70 | 71 | ### Add to Profile 72 | The above installation methods will load the PoshColor module for your current session. If you want the PoshColor module loaded for all sessions, add the following line to your profile 73 | ```pwsh 74 | Import-Module PoshColor 75 | ``` 76 | ### Updating PoshColor 77 | To update PoshColor to the newest version, run the following command in powershell 78 | ```pwsh 79 | Update-Module PoshColor 80 | ``` 81 | 82 | ### Unload PoshColor 83 | To unload PoshColor from your session, run the following command in powershell 84 | ```pwsh 85 | Remove-Module PoshColor 86 | ``` 87 | 88 | ### Themes 89 | To view a list of installed themes 90 | ```powershell 91 | Get-PoshColorThemes 92 | ``` 93 | 94 | To set the current theme (Setting theme too Cool) 95 | ```powershell 96 | Set-PoshColorTheme Cool 97 | ``` 98 | 99 | To view the current theme 100 | ``` Powershell 101 | Get-PoshColorTheme 102 | ``` 103 | 104 | ## Questions 105 | ### Why not contribute to PSColor? 106 | PS Color seems to be a dead repository. There have not been any updates to the repo in a few years, and there are a few outstanding issues that have not been resolved. Yes, I could fix these issues, however there are PRs others have raised to fix some of the issues which have not been accepted in years. ALSO, I thought it would be fun to do :) 107 | -------------------------------------------------------------------------------- /src/Renderers/MemberDefinitionRenderer.ps1: -------------------------------------------------------------------------------- 1 | function Write-MemberDefinitionHeader{ 2 | [CmdletBinding()] 3 | param ( 4 | [Parameter()] 5 | [System.String] 6 | $TypeName 7 | ) 8 | 9 | if ($script:currentDirectory -eq "" -or $script:currentDirectory -ne $TypeName) 10 | { 11 | Write-Host 12 | Write-Host $TypeName -ForegroundColor Green 13 | Write-Host 14 | 15 | Write-Host 'Name MemberType Definition' 16 | Write-Host '---- ---------- ----------' 17 | 18 | $script:currentDirectory = "$TypeName" 19 | } 20 | } 21 | 22 | function Write-MemberDefinition 23 | { 24 | param ([Parameter(Mandatory=$True,Position=1)] $item) 25 | 26 | Write-MemberDefinitionHeader $item.TypeName 27 | 28 | $width = $Host.UI.RawUI.WindowSize.Width - 45 29 | 30 | if ($width -lt 30) 31 | { 32 | $width = 30 33 | } 34 | 35 | $definition = $item.Definition; 36 | 37 | if ($definition.Length -ge $width) 38 | { 39 | $definition = $definition.Substring(0, $width) + ".." 40 | } 41 | 42 | $output = [System.String]::Format("{0, -27}{1, -16}{2}", $item.Name, $item.MemberType, $definition) 43 | 44 | $foreground = $global:PoshColor.CommandInfo.Default.Color 45 | 46 | if ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::CodeMethod) 47 | { 48 | $foreground = $global:PoshColor.PSMemberType.CodeMethod.Color 49 | } 50 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::AliasProperty) 51 | { 52 | $foreground = $global:PoshColor.PSMemberType.AliasProperty.Color 53 | } 54 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::CodeProperty) 55 | { 56 | $foreground = $global:PoshColor.PSMemberType.CodeProperty.Color 57 | } 58 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Method) 59 | { 60 | $foreground = $global:PoshColor.PSMemberType.Method.Color 61 | } 62 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Methods) 63 | { 64 | $foreground = $global:PoshColor.PSMemberType.Methods.Color 65 | } 66 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::NoteProperty) 67 | { 68 | $foreground = $global:PoshColor.PSMemberType.NoteProperty.Color 69 | } 70 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::ParameterizedProperty) 71 | { 72 | $foreground = $global:PoshColor.PSMemberType.ParameterizedProperty.Color 73 | } 74 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Properties) 75 | { 76 | $foreground = $global:PoshColor.PSMemberType.Properties.Color 77 | } 78 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Property) 79 | { 80 | $foreground = $global:PoshColor.PSMemberType.Property.Color 81 | } 82 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::PropertySet) 83 | { 84 | $foreground = $global:PoshColor.PSMemberType.PropertySet.Color 85 | } 86 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::ScriptMethod) 87 | { 88 | $foreground = $global:PoshColor.PSMemberType.ScriptMethod.Color 89 | } 90 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::ScriptProperty) 91 | { 92 | $foreground = $global:PoshColor.PSMemberType.ScriptProperty.Color 93 | } 94 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Dynamic) 95 | { 96 | $foreground = $global:PoshColor.PSMemberType.Dynamic.Color 97 | } 98 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::Event) 99 | { 100 | $foreground = $global:PoshColor.PSMemberType.Event.Color 101 | } 102 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::InferredProperty) 103 | { 104 | $foreground = $global:PoshColor.PSMemberType.InferredProperty.Color 105 | } 106 | elseif ($item.MemberType -eq [System.Management.Automation.PSMemberTypes]::MemberSet) 107 | { 108 | $foreground = $global:PoshColor.PSMemberType.MemberSet.Color 109 | } 110 | 111 | Write-HostColor $output -Foreground $foreground 112 | 113 | return $true 114 | } 115 | -------------------------------------------------------------------------------- /src/Renderers/MatchInfoRenderer.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Write-MatchContext 3 | { 4 | param ([Parameter(Position=1,Mandatory=$true)]$context,[Parameter(Position=2,Mandatory=$true)]$relativePath, [Parameter(Position=3,Mandatory=$true)]$lineNumber, 5 | [Switch]$printFile) 6 | 7 | if ($printFile) 8 | { 9 | Write-HostColor " $relativePath" $global:PoshColor.Match.File.Color -Background $global:PoshColor.Match.File.BackgroundColor 10 | } 11 | 12 | $currentLineNumber = $lineNumber 13 | 14 | $context | ForEach-Object { 15 | Write-HostColor " Line: " -Foreground $global:PoshColor.Match.Default.Color -Background $global:PoshColor.Match.Default.BackgroundColor -NoNewline 16 | Write-HostColor (Pad $currentLineNumber 6) -Foreground $global:PoshColor.Match.LineNumber.Color -Background $global:PoshColor.Match.LineNumber.BackgroundColor -NoNewline 17 | Write-HostColor "$_" -Foreground $global:PoshColor.Match.Match.Color -Background $global:PoshColor.Match.Match.BackgroundColor 18 | $currentLineNumber = $currentLineNumber + 1 19 | } 20 | } 21 | 22 | function Write-MatchItem 23 | { 24 | [CmdletBinding()] 25 | param ( 26 | [Parameter(Position=1,Mandatory=$true)] [string] $line, 27 | [Parameter(Position=2,Mandatory=$true)] $matches 28 | ) 29 | 30 | $itemText = $line 31 | 32 | $items = New-Object "System.Collections.Generic.List[object]" 33 | 34 | # Reverse the array and work backwards to avoid causing issues with the index of the matches 35 | [array]::Reverse($matches) 36 | 37 | $matches | foreach-object { 38 | $nonMatchIndex = $_.Index + $_.Length 39 | 40 | # Append whatever text is after the match 41 | if ($nonMatchIndex -lt $itemText.Length) 42 | { 43 | $newTextPart = $itemText.Substring($nonMatchIndex) 44 | 45 | $items.Insert(0, @{ 46 | Text = $newTextPart 47 | Foreground=$global:PoshColor.Match.Match.Color 48 | Background=$global:PoshColor.Match.Match.BackgroundColor 49 | }) 50 | } 51 | 52 | $items.Insert(0, @{ 53 | Text = $_.Value 54 | Foreground=$global:PoshColor.Match.MatchText.Color 55 | Background=$global:PoshColor.Match.MatchText.BackgroundColor 56 | }) 57 | 58 | $itemText = $itemText.Substring(0, $_.Index) 59 | } 60 | 61 | 62 | if ($itemText.Length -gt 0) 63 | { 64 | $items.Insert(0, @{ 65 | Text = $itemText 66 | Foreground=$global:PoshColor.Match.Match.Color 67 | Background=$global:PoshColor.Match.Match.BackgroundColor 68 | }) 69 | } 70 | 71 | $items | ForEach-Object{ 72 | Write-HostColor $_.Text $_.Foreground -Background $_.Background -noNewLine 73 | } 74 | 75 | # newline 76 | Write-Host 77 | } 78 | 79 | function Write-Match 80 | { 81 | param ([Parameter(Position=1, Mandatory=$true)][Microsoft.Powershell.Commands.MatchInfo]$item) 82 | 83 | if ($item.Context) 84 | { 85 | Write-MatchContext $item.Context.DisplayPreContext $item.RelativePath($pwd) ($item.LineNumber - $item.Context.DisplayPreContext.Count) -PrintFile 86 | 87 | Write-HostColor '-> Line: ' -Foreground $global:PoshColor.Match.Default.Color -Background $global:PoshColor.Match.Default.BackgroundColor -noNewLine 88 | Write-HostColor (Pad $item.LineNumber 6) -Foreground $global:PoshColor.Match.LineNumber.Color -Background $global:PoshColor.Match.LineNumber.BackgroundColor -noNewLine 89 | Write-MatchItem $item.Line $item.Matches 90 | 91 | Write-MatchContext $item.Context.DisplayPostContext $item.RelativePath($pwd) ($item.LineNumber + 1) 92 | } 93 | else { 94 | Write-HostColor '-> Line: ' -Foreground $global:PoshColor.Match.Default.Color -Background $global:PoshColor.Match.Default.BackgroundColor -NoNewline 95 | Write-HostColor (Pad $item.LineNumber 6) -Foreground $global:PoshColor.Match.LineNumber.Color -Background $global:PoshColor.Match.LineNumber.BackgroundColor -noNewLine 96 | Write-HostColor $item.RelativePath($pwd) -Foreground $global:PoshColor.Match.File.Color -Background $global:PoshColor.Match.File.BackgroundColor -noNewLine 97 | Write-HostColor ': ' -Foreground $global:PoshColor.Match.Default.Color -Background $global:PoshColor.Match.Default.BackgroundColor -noNewLine 98 | Write-MatchItem $item.Line $item.Matches 99 | } 100 | return $true; 101 | } -------------------------------------------------------------------------------- /src/Renderers/FileRenderer.ps1: -------------------------------------------------------------------------------- 1 | 2 | function Write-FileHeader 3 | { 4 | param ([Parameter(Mandatory=$True,Position=1)] $item) 5 | 6 | if($item -is [System.IO.DirectoryInfo]) 7 | { 8 | $itemPath = $item.Parent.ToString() 9 | 10 | # GetRootedPath will cause an exception if $itemPath is a root directory 11 | try 12 | { 13 | # If running on .net framework, the above statement returns a relative path 14 | # remove the item name from the full name to get the full parent path 15 | if ([System.IO.Path]::GetPathRoot($itemPath) -eq "" ) 16 | { 17 | $replaceName = $item.Name; 18 | $replaceName = "\" + $replaceName 19 | 20 | $itemPath = $item.FullName.Replace($replaceName, "" ) 21 | } 22 | } 23 | catch 24 | { 25 | $replaceName = $item.Name; 26 | 27 | $itemPath = $item.FullName.Replace($replaceName, "" ) 28 | } 29 | } 30 | else 31 | { 32 | $itemPath = $item.Directory.ToString() 33 | } 34 | 35 | if (($script:currentDirectory -eq "") -or ($script:currentDirectory -ne $itemPath)) 36 | { 37 | Write-Host 38 | $script:currentDirectory = $itemPath 39 | 40 | # Do we have a foregorund color configured? 41 | if ($global:PoshColor.DirectoryForeground) 42 | { 43 | Write-Host "Directory: " -NoNewline 44 | 45 | # Use console colors? 46 | if ($global:PoshColor.UseConsoleColors) 47 | { 48 | Write-Host $script:currentDirectory -ForegroundColor $global:PoshColor.DirectoryForeground 49 | } 50 | else { 51 | Write-HostColor $script:currentDirectory $global:PoshColor.DirectoryForeground 52 | } 53 | } 54 | else { 55 | Write-Host "Directory: $script:currentDirectory" 56 | } 57 | Write-Host 58 | Write-Host "Mode LastWriteTime Length Name" 59 | Write-Host "---- ------------- ------ ----" 60 | } 61 | } 62 | 63 | function Write-File 64 | { 65 | param ([Parameter(Mandatory=$True,Position=1)] $item) 66 | 67 | Write-FileHeader $item 68 | 69 | $isDirectory = $item.GetType() -eq [System.IO.DirectoryInfo] 70 | 71 | $isHidden = $item.Attributes.HasFlag([System.IO.FileAttributes]::Hidden) 72 | $isSystem = $item.Attributes.HasFlag([System.IO.FileAttributes]::System) 73 | $isEncrypted = $item.Attributes.HasFlag([System.IO.FileAttributes]::Encrypted) 74 | $isCompressed = $item.Attributes.HasFlag([System.IO.FileAttributes]::Compressed) 75 | 76 | $outputColor = "White" 77 | 78 | $length = "" 79 | 80 | if ($isDirectory -eq $false) 81 | { 82 | $length = $item.Length 83 | } 84 | 85 | foreach($filterKey in $global:PoshColor.File.Keys) 86 | { 87 | $match = $true; 88 | 89 | $filter = $global:PoshColor.File.Item($filterKey) 90 | 91 | if (($filter.Directory -eq $true) -and $isDirectory -eq $false) 92 | { 93 | $match = $false 94 | } 95 | 96 | if (($filter.Hidden -eq $true) -and $isHidden -eq $false) 97 | { 98 | $match = $false 99 | } 100 | 101 | if ($filter.Compressed -eq $true -and $isCompressed -eq $false) 102 | { 103 | $match = $false 104 | } 105 | 106 | if ($filter.Encrypted -eq $true -and $isEncrypted -eq $false) 107 | { 108 | $match = $false 109 | } 110 | 111 | if ($filter.System -eq $true -and $isSystem -eq $false) 112 | { 113 | $match = $false 114 | } 115 | 116 | if ($match -and $filter.Pattern) 117 | { 118 | $regex_opts = ([System.Text.RegularExpressions.RegexOptions]::IgnoreCase) 119 | 120 | $regex = New-Object System.Text.RegularExpressions.Regex($filter.Pattern, $regex_opts) 121 | 122 | if ($regex.IsMatch($item.Name) -eq $false) 123 | { 124 | $match = $false 125 | } 126 | } 127 | 128 | if ($match -eq $true) 129 | { 130 | $outputColor = $filter.Color 131 | 132 | $backgroundColor = $filter.BackgroundColor 133 | 134 | break 135 | } 136 | } 137 | 138 | $lastWriteDate = $item.LastWriteTime.ToString("d") 139 | $lastWriteTime = $item.LastWriteTime.ToString("t") 140 | $lastWrite = [String]::Format("{0,10} {1,8}", $lastWriteDate, $lastWriteTime) 141 | 142 | $outputText = [System.String]::Format("{0,-7} {1,25} {2,10} {3}", $item.mode, $lastWrite, $length, $item.name) 143 | 144 | Write-HostColor $outputText $outputColor -Background $backgroundColor 145 | 146 | return $true 147 | } -------------------------------------------------------------------------------- /src/PoshColor.psd1: -------------------------------------------------------------------------------- 1 | # 2 | # Module manifest for module 'PoshColor' 3 | # 4 | # Generated by: Eddie de Bear 5 | # 6 | # Generated on: 5/10/2019 7 | # 8 | 9 | @{ 10 | 11 | # Script module or binary module file associated with this manifest. 12 | RootModule = 'PoshColor.psm1' 13 | 14 | # Version number of this module. 15 | ModuleVersion = '1.0.3.0' 16 | 17 | # Supported PSEditions 18 | # CompatiblePSEditions = @() 19 | 20 | # ID used to uniquely identify this module 21 | GUID = '97c49386-da8c-4b3d-aa54-f63bc0a41317' 22 | 23 | # Author of this module 24 | Author = 'Eddie de Bear' 25 | 26 | # Company or vendor of this module 27 | #CompanyName = 'Unknown' 28 | 29 | # Copyright statement for this module 30 | Copyright = '(c) Eddie de Bear. All rights reserved.' 31 | 32 | # Description of the functionality provided by this module 33 | Description = 'Brings color to the default powershell.' 34 | 35 | # Minimum version of the PowerShell engine required by this module 36 | # PowerShellVersion = '' 37 | 38 | # Name of the PowerShell host required by this module 39 | # PowerShellHostName = '' 40 | 41 | # Minimum version of the PowerShell host required by this module 42 | # PowerShellHostVersion = '' 43 | 44 | # Minimum version of Microsoft .NET Framework required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 45 | # DotNetFrameworkVersion = '' 46 | 47 | # Minimum version of the common language runtime (CLR) required by this module. This prerequisite is valid for the PowerShell Desktop edition only. 48 | # CLRVersion = '' 49 | 50 | # Processor architecture (None, X86, Amd64) required by this module 51 | # ProcessorArchitecture = '' 52 | 53 | # Modules that must be imported into the global environment prior to importing this module 54 | # RequiredModules = @() 55 | 56 | # Assemblies that must be loaded prior to importing this module 57 | # RequiredAssemblies = @() 58 | 59 | # Script files (.ps1) that are run in the caller's environment prior to importing this module. 60 | # ScriptsToProcess = @() 61 | 62 | # Type files (.ps1xml) to be loaded when importing this module 63 | # TypesToProcess = @() 64 | 65 | # Format files (.ps1xml) to be loaded when importing this module 66 | # FormatsToProcess = @() 67 | 68 | # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess 69 | # NestedModules = @() 70 | 71 | # Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export. 72 | FunctionsToExport = @('Get-PoshColorTheme', 'Set-PoshColorTheme', 'Get-PoshColorThemes') 73 | 74 | # Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export. 75 | CmdletsToExport = @() 76 | 77 | # Variables to export from this module 78 | VariablesToExport = '*' 79 | 80 | # Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export. 81 | AliasesToExport = @() 82 | 83 | # DSC resources to export from this module 84 | # DscResourcesToExport = @() 85 | 86 | # List of all modules packaged with this module 87 | #ModuleList = @(PoshColor) 88 | 89 | # List of all files packaged with this module 90 | FileList = @( 91 | "New-CommandWrapper.ps1", 92 | "PoshColor.psd1", 93 | "PoshColor.psm1", 94 | "PoshColorFunctions.ps1", 95 | ".\Renderers\CommandInfoRenderer.ps1", 96 | ".\Renderers\EventLogRecordRenderer.ps1", 97 | ".\Renderers\FileRenderer.ps1", 98 | ".\Renderers\MatchInfoRenderer.ps1", 99 | ".\Renderers\MemberDefinitionRenderer.ps1", 100 | ".\Renderers\PSDriveInfoRenderer.ps1", 101 | ".\Renderers\PSModuleInfoRenderer.ps1", 102 | ".\Renderers\ServiceControllerRenderer.ps1", 103 | ".\Themes\Cool.ps1", 104 | ".\Themes\Default.ps1", 105 | ".\Themes\DefaultHighColor.ps1" 106 | ) 107 | 108 | # Private data to pass to the module specified in RootModule/ModuleToProcess. This may also contain a PSData hashtable with additional module metadata used by PowerShell. 109 | PrivateData = @{ 110 | 111 | PSData = @{ 112 | 113 | # Tags applied to this module. These help with module discovery in online galleries. 114 | Tags = @('Color', 'Colour', 'File', 'Service', 'Select-String', 'Module', 'EventLog', 'Customisation', 'Customization') 115 | 116 | # A URL to the license for this module. 117 | LicenseUri = 'https://github.com/JustABearOz/PoshColor/blob/master/LICENSE' 118 | 119 | # A URL to the main website for this project. 120 | ProjectUri = 'https://github.com/JustABearOz/PoshColor' 121 | 122 | # A URL to an icon representing this module. 123 | # IconUri = '' 124 | 125 | # ReleaseNotes of this module 126 | ReleaseNotes = '* Fixes an issue with headings rendering for the wrong items.' 127 | 128 | } # End of PSData hashtable 129 | 130 | } # End of PrivateData hashtable 131 | 132 | # HelpInfo URI of this module 133 | # HelpInfoURI = '' 134 | 135 | # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. 136 | # DefaultCommandPrefix = '' 137 | 138 | } 139 | 140 | -------------------------------------------------------------------------------- /src/PoshColor.psm1: -------------------------------------------------------------------------------- 1 | function Get-PoshColorThemes { 2 | <# 3 | .SYNOPSIS 4 | Retrieves a list of all installed PoshColor themes 5 | 6 | .EXAMPLE 7 | Get-PoshColorThemes 8 | #> 9 | $themePath = Join-Path $PSScriptRoot "Themes" 10 | 11 | $themePath = Join-Path $themePath "*.ps1" 12 | 13 | get-childitem $themePath | foreach-object { Write-Output $_.Name.Replace(".ps1", "") } 14 | } 15 | 16 | function Get-PoshColorTheme { 17 | <# 18 | .SYNOPSIS 19 | Retrieves the name of the currently set theme 20 | 21 | .EXAMPLE 22 | Get-PoshColorTheme 23 | #> 24 | if ($IsWindows) { 25 | $themeName = [System.Environment]::GetEnvironmentVariable("PoshColorTheme", [System.EnvironmentVariableTarget]::User) 26 | } 27 | else { 28 | # Read from a user config file 29 | if (Test-Path "~/PoshColor.config") { 30 | $themeName = Get-Content ~/PoshColor.config 31 | } 32 | } 33 | 34 | return $themeName 35 | } 36 | 37 | function Set-PoshColorTheme { 38 | [CmdletBinding(SupportsShouldProcess)] 39 | <# 40 | .SYNOPSIS 41 | Sets the current PoshColor theme 42 | 43 | .EXAMPLE 44 | Set-PoshColorTheme Default 45 | #> 46 | param ( 47 | # Name of the theme to set 48 | [Parameter(Position = 0)][string] $ThemeName, 49 | 50 | # Use to import the theme, making it the currently loaded theme 51 | [switch] $Import 52 | ) 53 | 54 | if ($IsWindows) { 55 | [System.Environment]::SetEnvironmentVariable("PoshColorTheme", $ThemeName, [System.EnvironmentVariableTarget]::User) 56 | } 57 | else { 58 | Set-Content "~/PoshColor.config" $ThemeName 59 | } 60 | 61 | if ($Import) { 62 | Import-PoshColorTheme 63 | } 64 | } 65 | 66 | function Import-PoshColorTheme { 67 | $themeName = Get-PoshColorTheme 68 | 69 | if (!($themeName)) { 70 | $themeName = "Default" 71 | } 72 | 73 | $theme = Join-Path $PSScriptRoot "Themes" 74 | $theme = Join-Path $theme "$themeName.ps1" 75 | 76 | # Import the configured theme 77 | . "$theme" 78 | } 79 | 80 | ## Script cleanup so it can be safely removed wihtout causing issues after its removal 81 | $OnRemoveScript = { 82 | 83 | #Name of the command 84 | $commandName = $originalCommand.Command.Name 85 | 86 | if ((Test-Path function:\GLOBAL:$commandName) -and $originalCommand.CommandType -eq "Function" ) { 87 | # Remove the wrapper command 88 | Remove-Item function:\Out-Default 89 | 90 | #Rename the wrapped command back to Out-Default 91 | Rename-Item function:\GLOBAL:$commandName GLOBAL:Out-Default 92 | } 93 | 94 | # If the original command is no longer public, make it public 95 | if ($originalCommand.Command.Visibility -ne "public") { 96 | $originalCommand.Command.Visibility = "Public" 97 | } 98 | } 99 | 100 | # Needed in old powershell 101 | Add-Type -Assembly System.Drawing 102 | 103 | # Import helpers 104 | $import = Join-Path $PSScriptRoot "New-CommandWrapper.ps1" 105 | . $import 106 | 107 | $import = Join-Path $PSScriptRoot "PoshColorFunctions.ps1" 108 | . $import 109 | 110 | #Import-Renderer -RendererFileName "ServiceControllerRenderer.ps1" 111 | $import = Join-Path $PSScriptRoot "Renderers" 112 | $import = Join-Path $import "ServiceControllerRenderer.ps1" 113 | . $import 114 | 115 | $import = Join-Path $PSScriptRoot "Renderers" 116 | $import = Join-Path $import "FileRenderer.ps1" 117 | . $import 118 | 119 | $import = Join-Path $PSScriptRoot "Renderers" 120 | $import = Join-Path $import "MatchInfoRenderer.ps1" 121 | . $import 122 | 123 | $import = Join-Path $PSScriptRoot "Renderers" 124 | $import = Join-Path $import "PSModuleInfoRenderer.ps1" 125 | . $import 126 | 127 | $import = Join-Path $PSScriptRoot "Renderers" 128 | $import = Join-Path $import "EventLogRecordRenderer.ps1" 129 | . $import 130 | 131 | $import = Join-Path $PSScriptRoot "Renderers" 132 | $import = Join-Path $import "PSDriveInfoRenderer.ps1" 133 | . $import 134 | 135 | $import = Join-Path $PSScriptRoot "Renderers" 136 | $import = Join-Path $import "CommandInfoRenderer.ps1" 137 | . $import 138 | 139 | $import = Join-Path $PSScriptRoot "Renderers" 140 | $import = Join-Path $import "MemberDefinitionRenderer.ps1" 141 | . $import 142 | 143 | # if no theme has been set, set the default 144 | $theme = Get-PoshColorTheme 145 | 146 | if (!$theme) { 147 | Set-PoshColorTheme 'Default' 148 | } 149 | 150 | Import-PoshColorTheme 151 | 152 | ## No starting directory, this is used to detect changes in directories during file listings 153 | $script:currentDirectory = "" 154 | 155 | ## Set handler for cleanup 156 | $ExecutionContext.SessionState.Module.OnRemove += $OnRemoveScript 157 | 158 | ## Wrap the out-default current command/function 159 | $originalCommand = New-CommandWrapper Out-Default -Process { 160 | 161 | try { 162 | 163 | $handled = $false 164 | 165 | if (($_ -is [System.IO.DirectoryInfo]) -or ($_ -is [System.IO.FileInfo])) { 166 | $handled = Write-File $_ 167 | $handled = $true 168 | } 169 | elseif ($_ -is [Microsoft.Powershell.Commands.MatchInfo]) { 170 | $handled = Write-Match $_ 171 | } 172 | elseif ($_ -is [System.Management.Automation.PSModuleInfo]) { 173 | $handled = Write-Module $_ 174 | } 175 | elseif ($_ -is [System.Management.Automation.PSDriveInfo]) { 176 | $handled = Write-PSDrive $_ 177 | } 178 | elseif ($_ -is [System.Management.Automation.ApplicationInfo] -or 179 | $_ -is [System.Management.Automation.CmdletInfo] -or 180 | $_ -is [System.Management.Automation.ExternalScriptInfo] -or 181 | $_ -is [System.Management.Automation.FunctionInfo] -or 182 | $_ -is [System.Management.Automation.RemoteCommandInfo] -or 183 | $_ -is [System.Management.Automation.ScriptInfo] -or 184 | $_ -is [System.Management.Automation.AliasInfo]) { 185 | $handled = Write-CommandInfo $_ 186 | } 187 | elseif($_ -is [Microsoft.PowerShell.Commands.MemberDefinition]) 188 | { 189 | $handled = Write-MemberDefinition $_ 190 | } 191 | 192 | ## Platform specific, Win32, not available in all version of powershell 193 | elseif ([System.Environment]::OSVersion.Platform -eq 'Win32NT') { 194 | try { 195 | 196 | if ($_ -is [System.Diagnostics.Eventing.Reader.EventLogRecord]) { 197 | $handled = Write-EventLog $_ 198 | } 199 | elseif ($_ -is [System.ServiceProcess.ServiceController]) { 200 | $handled = Write_Service $_ 201 | } 202 | } 203 | catch { 204 | $handled = $false 205 | } 206 | } 207 | } 208 | catch { 209 | Write-Error $_.Exception.Message 210 | $handled = $false 211 | } 212 | 213 | if ($handled -eq $true) { 214 | $_ = $null 215 | } 216 | } -end { 217 | write-output "" 218 | $script:currentDirectory = "" 219 | } -------------------------------------------------------------------------------- /src/New-CommandWrapper.ps1: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | ## 3 | ## New-CommandWrapper 4 | ## 5 | ## From Windows PowerShell Cookbook (O'Reilly) 6 | ## by Lee Holmes (http://www.leeholmes.com/guide) 7 | ## 8 | ## Modified to return information to allow reversal 9 | ############################################################################## 10 | 11 | <# 12 | 13 | .SYNOPSIS 14 | 15 | Adds parameters and functionality to existing cmdlets and functions. 16 | 17 | .EXAMPLE 18 | 19 | New-CommandWrapper Get-Process ` 20 | -AddParameter @{ 21 | SortBy = { 22 | $newPipeline = { 23 | __ORIGINAL_COMMAND__ | Sort-Object -Property $SortBy 24 | } 25 | } 26 | } 27 | 28 | This example adds a 'SortBy' parameter to Get-Process. It accomplishes 29 | this by adding a Sort-Object command to the pipeline. 30 | 31 | .EXAMPLE 32 | 33 | $parameterAttributes = @' 34 | [Parameter(Mandatory = $true)] 35 | [ValidateRange(50,75)] 36 | [Int] 37 | '@ 38 | 39 | New-CommandWrapper Clear-Host ` 40 | -AddParameter @{ 41 | @{ 42 | Name = 'MyMandatoryInt'; 43 | Attributes = $parameterAttributes 44 | } = { 45 | Write-Host $MyMandatoryInt 46 | Read-Host "Press ENTER" 47 | } 48 | } 49 | 50 | This example adds a new mandatory 'MyMandatoryInt' parameter to 51 | Clear-Host. This parameter is also validated to fall within the range 52 | of 50 to 75. It doesn't alter the pipeline, but does display some 53 | information on the screen before processing the original pipeline. 54 | 55 | #> 56 | function New-CommandWrapper { 57 | param( 58 | ## The name of the command to extend 59 | [Parameter(Mandatory = $true)] 60 | $Name, 61 | 62 | ## Script to invoke before the command begins 63 | [ScriptBlock] $Begin, 64 | 65 | ## Script to invoke for each input element 66 | [ScriptBlock] $Process, 67 | 68 | ## Script to invoke at the end of the command 69 | [ScriptBlock] $End, 70 | 71 | ## Parameters to add, and their functionality. 72 | ## 73 | ## The Key of the hashtable can be either a simple parameter name, 74 | ## or a more advanced parameter description. 75 | ## 76 | ## If you want to add additional parameter validation (such as a 77 | ## parameter type,) then the key can itself be a hashtable with the keys 78 | ## 'Name' and 'Attributes'. 'Attributes' is the text you would use when 79 | ## defining this parameter as part of a function. 80 | ## 81 | ## The Value of each hashtable entry is a scriptblock to invoke 82 | ## when this parameter is selected. To customize the pipeline, 83 | ## assign a new scriptblock to the $newPipeline variable. Use the 84 | ## special text, __ORIGINAL_COMMAND__, to represent the original 85 | ## command. The $targetParameters variable represents a hashtable 86 | ## containing the parameters that will be passed to the original 87 | ## command. 88 | [HashTable] $AddParameter 89 | ) 90 | 91 | Set-StrictMode -Version Latest 92 | 93 | ## Store the target command we are wrapping, and its command type 94 | $target = $Name 95 | $commandType = "Cmdlet" 96 | 97 | ## If a function already exists with this name (perhaps it's already been 98 | ## wrapped,) rename the other function and chain to its new name. 99 | if (Test-Path function:\$Name) { 100 | $target = "$Name" + "-" + [Guid]::NewGuid().ToString().Replace("-", "") 101 | Rename-Item function:\GLOBAL:$Name GLOBAL:$target 102 | $commandType = "Function" 103 | } 104 | 105 | ## The template we use for generating a command proxy 106 | $proxy = @' 107 | 108 | __CMDLET_BINDING_ATTRIBUTE__ 109 | param( 110 | __PARAMETERS__ 111 | ) 112 | begin 113 | { 114 | try { 115 | __CUSTOM_BEGIN__ 116 | 117 | ## Access the REAL Foreach-Object command, so that command 118 | ## wrappers do not interfere with this script 119 | $foreachObject = $executionContext.InvokeCommand.GetCmdlet( 120 | "Microsoft.PowerShell.Core\Foreach-Object") 121 | 122 | $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand( 123 | '__COMMAND_NAME__', 124 | [System.Management.Automation.CommandTypes]::__COMMAND_TYPE__) 125 | 126 | ## TargetParameters represents the hashtable of parameters that 127 | ## we will pass along to the wrapped command 128 | $targetParameters = @{} 129 | $PSBoundParameters.GetEnumerator() | 130 | & $foreachObject { 131 | if($command.Parameters.ContainsKey($_.Key)) 132 | { 133 | $targetParameters.Add($_.Key, $_.Value) 134 | } 135 | } 136 | 137 | ## finalPipeline represents the pipeline we wil ultimately run 138 | $newPipeline = { & $wrappedCmd @targetParameters } 139 | $finalPipeline = $newPipeline.ToString() 140 | 141 | __CUSTOM_PARAMETER_PROCESSING__ 142 | 143 | $steppablePipeline = [ScriptBlock]::Create( 144 | $finalPipeline).GetSteppablePipeline() 145 | $steppablePipeline.Begin($PSCmdlet) 146 | } catch { 147 | throw 148 | } 149 | } 150 | 151 | process 152 | { 153 | try { 154 | __CUSTOM_PROCESS__ 155 | $steppablePipeline.Process($_) 156 | } catch { 157 | throw 158 | } 159 | } 160 | 161 | end 162 | { 163 | try { 164 | __CUSTOM_END__ 165 | $steppablePipeline.End() 166 | } catch { 167 | throw 168 | } 169 | } 170 | 171 | dynamicparam 172 | { 173 | ## Access the REAL Get-Command, Foreach-Object, and Where-Object 174 | ## commands, so that command wrappers do not interfere with this script 175 | $getCommand = $executionContext.InvokeCommand.GetCmdlet( 176 | "Microsoft.PowerShell.Core\Get-Command") 177 | $foreachObject = $executionContext.InvokeCommand.GetCmdlet( 178 | "Microsoft.PowerShell.Core\Foreach-Object") 179 | $whereObject = $executionContext.InvokeCommand.GetCmdlet( 180 | "Microsoft.PowerShell.Core\Where-Object") 181 | 182 | ## Find the parameters of the original command, and remove everything 183 | ## else from the bound parameter list so we hide parameters the wrapped 184 | ## command does not recognize. 185 | $command = & $getCommand __COMMAND_NAME__ -Type __COMMAND_TYPE__ 186 | $targetParameters = @{} 187 | $PSBoundParameters.GetEnumerator() | 188 | & $foreachObject { 189 | if($command.Parameters.ContainsKey($_.Key)) 190 | { 191 | $targetParameters.Add($_.Key, $_.Value) 192 | } 193 | } 194 | 195 | ## Get the argumment list as it would be passed to the target command 196 | $argList = @($targetParameters.GetEnumerator() | 197 | Foreach-Object { "-$($_.Key)"; $_.Value }) 198 | 199 | ## Get the dynamic parameters of the wrapped command, based on the 200 | ## arguments to this command 201 | $command = $null 202 | try 203 | { 204 | $command = & $getCommand __COMMAND_NAME__ -Type __COMMAND_TYPE__ ` 205 | -ArgumentList $argList 206 | } 207 | catch 208 | { 209 | 210 | } 211 | 212 | $dynamicParams = @($command.Parameters.GetEnumerator() | 213 | & $whereObject { $_.Value.IsDynamic }) 214 | 215 | ## For each of the dynamic parameters, add them to the dynamic 216 | ## parameters that we return. 217 | if ($dynamicParams.Length -gt 0) 218 | { 219 | $paramDictionary = ` 220 | New-Object Management.Automation.RuntimeDefinedParameterDictionary 221 | foreach ($param in $dynamicParams) 222 | { 223 | $param = $param.Value 224 | $arguments = $param.Name, $param.ParameterType, $param.Attributes 225 | $newParameter = ` 226 | New-Object Management.Automation.RuntimeDefinedParameter ` 227 | $arguments 228 | $paramDictionary.Add($param.Name, $newParameter) 229 | } 230 | return $paramDictionary 231 | } 232 | } 233 | 234 | <# 235 | 236 | .ForwardHelpTargetName __COMMAND_NAME__ 237 | .ForwardHelpCategory __COMMAND_TYPE__ 238 | 239 | #> 240 | 241 | '@ 242 | 243 | ## Get the information about the original command 244 | $originalCommand = Get-Command $target 245 | $metaData = New-Object System.Management.Automation.CommandMetaData ` 246 | $originalCommand 247 | $proxyCommandType = [System.Management.Automation.ProxyCommand] 248 | 249 | ## Generate the cmdlet binding attribute, and replace information 250 | ## about the target 251 | $proxy = $proxy.Replace("__CMDLET_BINDING_ATTRIBUTE__", 252 | $proxyCommandType::GetCmdletBindingAttribute($metaData)) 253 | $proxy = $proxy.Replace("__COMMAND_NAME__", $target) 254 | $proxy = $proxy.Replace("__COMMAND_TYPE__", $commandType) 255 | 256 | ## Stores new text we'll be putting in the param() block 257 | $newParamBlockCode = "" 258 | 259 | ## Stores new text we'll be putting in the begin block 260 | ## (mostly due to parameter processing) 261 | $beginAdditions = "" 262 | 263 | ## If the user wants to add a parameter 264 | $currentParameter = $originalCommand.Parameters.Count 265 | if ($AddParameter) { 266 | foreach ($parameter in $AddParameter.Keys) { 267 | ## Get the code associated with this parameter 268 | $parameterCode = $AddParameter[$parameter] 269 | 270 | ## If it's an advanced parameter declaration, the hashtable 271 | ## holds the validation and / or type restrictions 272 | if ($parameter -is [Hashtable]) { 273 | ## Add their attributes and other information to 274 | ## the variable holding the parameter block additions 275 | if ($currentParameter -gt 0) { 276 | $newParamBlockCode += "," 277 | } 278 | 279 | $newParamBlockCode += "`n`n " + 280 | $parameter.Attributes + "`n" + 281 | ' $' + $parameter.Name 282 | 283 | $parameter = $parameter.Name 284 | } 285 | else { 286 | ## If this is a simple parameter name, add it to the list of 287 | ## parameters. The proxy generation APIs will take care of 288 | ## adding it to the param() block. 289 | $newParameter = 290 | New-Object System.Management.Automation.ParameterMetadata ` 291 | $parameter 292 | $metaData.Parameters.Add($parameter, $newParameter) 293 | } 294 | 295 | $parameterCode = $parameterCode.ToString() 296 | 297 | ## Create the template code that invokes their parameter code if 298 | ## the parameter is selected. 299 | $templateCode = @" 300 | 301 | if(`$PSBoundParameters['$parameter']) 302 | { 303 | $parameterCode 304 | 305 | ## Replace the __ORIGINAL_COMMAND__ tag with the code 306 | ## that represents the original command 307 | `$alteredPipeline = `$newPipeline.ToString() 308 | `$finalPipeline = `$alteredPipeline.Replace( 309 | '__ORIGINAL_COMMAND__', `$finalPipeline) 310 | } 311 | "@ 312 | 313 | ## Add the template code to the list of changes we're making 314 | ## to the begin() section. 315 | $beginAdditions += $templateCode 316 | $currentParameter++ 317 | } 318 | } 319 | 320 | ## Generate the param() block 321 | $parameters = $proxyCommandType::GetParamBlock($metaData) 322 | if ($newParamBlockCode) { $parameters += $newParamBlockCode } 323 | $proxy = $proxy.Replace('__PARAMETERS__', $parameters) 324 | 325 | ## Update the begin, process, and end sections 326 | $proxy = $proxy.Replace('__CUSTOM_BEGIN__', $Begin) 327 | $proxy = $proxy.Replace('__CUSTOM_PARAMETER_PROCESSING__', $beginAdditions) 328 | $proxy = $proxy.Replace('__CUSTOM_PROCESS__', $Process) 329 | $proxy = $proxy.Replace('__CUSTOM_END__', $End) 330 | 331 | ## Save the function wrapper 332 | Write-Verbose $proxy 333 | Set-Content function:\GLOBAL:$NAME $proxy 334 | 335 | ## If we were wrapping a cmdlet, hide it so that it doesn't conflict with 336 | ## Get-Help and Get-Command 337 | if ($commandType -eq "Cmdlet") { 338 | $originalCommand.Visibility = "Private" 339 | } 340 | 341 | return @{ 342 | Command = $originalCommand 343 | Target = $target 344 | CommandType = $commandType 345 | } 346 | } 347 | --------------------------------------------------------------------------------