PSColors.psm1
# Function to check wheter current Console support ANSI codes function Test-Ansi { # Powershell ISE don't support ANSI, and this test will print ugly chars there if($host.PrivateData.ToString() -eq 'Microsoft.PowerShell.Host.ISE.ISEOptions') { return $false; } # To test is console supports ANSI, we will print an ANSI code # and check if cursor postion has changed. If it has, ANSI is not # supported $oldPos = $host.UI.RawUI.CursorPosition.X Write-Host -NoNewline "$([char](27))[0m" -ForegroundColor ($host.UI.RawUI.BackgroundColor); $pos = $host.UI.RawUI.CursorPosition.X if($pos -eq $oldPos) { return $true; } else { # If ANSI is not supported, let's clean up ugly ANSI escapes Write-Host -NoNewLine ("`b" * 4) return $false } } $Script:HasAnsi = Test-Ansi if($Script:HasAnsi) { # If ANSI is supported, save current console mode, so we can restore it latter. # Some programs, like cygwin's git disables ANSI support in windows Console. # This it will bad side effetcts from GIT. $sig = ''; $sig = $sig + '[DllImport("kernel32.dll", SetLastError = true)] public static extern bool SetConsoleMode(IntPtr hConsoleHandle, int dwMode);'; $sig = $sig + '[DllImport("kernel32.dll", SetLastError = true)] public static extern bool GetConsoleMode(IntPtr hConsoleHandle, ref int nCmdShow);'; $sig = $sig + '[DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetStdHandle(int nStdHandle);'; Add-Type -MemberDefinition $sig -name PSColorsNativeMethods -namespace Win32; $Script:ConsoleHandle = [Win32.PSColorsNativeMethods]::GetStdHandle(-11); $Script:ConsoleMode = 0; [Win32.PSColorsNativeMethods]::GetConsoleMode($Script:ConsoleHandle, [ref] $Script:ConsoleMode); } function Test-Git { param([IO.DirectoryInfo] $dir) # Function to check wheter directory is in a git repository # If have .git dir, it's a git repo if(Test-Path (Join-Path $dir.FullName '.git')) { return $true; } # If reached root dir, we are not in a git repository if(($dir.Parent -eq $null) -or ($dir -eq $dir.Parent)) { return $false; } # Check parent dir. Let's hope PowerShell supports tail recursion return Test-Git ($dir.Parent.FullName) } # Overriding PowerShell's default prompt function! function prompt { if($Script:HasAnsi) { # Making sure we are restoing original Console Mode in case someone (e.g. GIT) has changed it [Win32.PSColorsNativeMethods]::SetConsoleMode($Script:ConsoleHandle, $Script:ConsoleMode) | Out-Null } if($global:FSFormatDefaultColor) { [Console]::ForegroundColor = $global:FSFormatDefaultColor } $isFS = (Get-Item .).PSProvider.Name -eq 'FileSystem'; if($isFS) { # PowerShell don't change CurrentDirectory when you navigate throught File Sytem # which causes problem when executing external programs providing relative paths # This will fix the issue, syncing PowerShell current localtion to Windows Environment [system.Environment]::CurrentDirectory = (Convert-Path "."); } #Check if current user has admin privilges so we can use a different color $user = [Security.Principal.WindowsIdentity]::GetCurrent(); $admin = (New-Object Security.Principal.WindowsPrincipal $user).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator) $branch = $null; # Legancy functionality to display git branch. Recommend to use posh-git, as it has better info # PSColors will not use its own branching displaying if it dectects posh-git is present if(-not(Get-Command Write-VcsStatus -ErrorAction SilentlyContinue)) { if( $isFS -and (Test-Git (Convert-Path .)) -and (Get-Command git)) { $branch = (git branch 2>$null) | %{ ([regex] '\* (.*)').match($_) } | ? { $_.Success } | %{ $_.Groups[1].Value } | Select-Object -First 1 } } $drive = (Get-Location).Drive if($drive.Root -eq "$($drive.Name):\") { $title = $executionContext.SessionState.Path.CurrentLocation if($branch) { $title = "[$branch] $title"; } } else { $title = $drive.Name if($branch) { $title = "$title@$branch"; } } $host.UI.RawUI.WindowTitle = $title # Choosing color based on admin's privileges if($admin) { $color = 'Yellow'; } else { $color = 'Green'; } Write-Host ([System.Char](10)) -NoNewLine; # Print git branch, if posh-git is not present if($branch) { Write-Host "[" -NoNewLine -ForegroundColor Yellow Write-Host "$branch" -NoNewLine -ForegroundColor Cyan Write-Host "] " -NoNewLine -ForegroundColor Yellow } # If we have posh-git, use it if(Get-Command Write-VcsStatus -ErrorAction SilentlyContinue) { Write-VcsStatus; } # Write prompt info Write-Host $executionContext.SessionState.Path.CurrentLocation -NoNewLine -ForegroundColor $color; Write-Host ('>' * ($nestedPromptLevel + 1)) -NoNewLine -ForegroundColor $color; # Prevents PowerShell default prompt printing if($host.Name -like 'StudioShell*') { return " "; } else { return " `b"; } } # Wrapper for Get-ChildItem, that will aid PSColors.format.ps1xml detect if it's outputing to console, # and hence use ANSI code for coloring different file types function Get-ChildItem { <# .ForwardHelpTargetName Get-ChildItem .ForwardHelpCategory Cmdlet #> [CmdletBinding(DefaultParameterSetName='Items', SupportsTransactions=$true, HelpUri='https://go.microsoft.com/fwlink/?LinkID=113308')] param( [Parameter(ParameterSetName='Items', Position=0, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)] [string[]] ${Path}, [Parameter(ParameterSetName='LiteralItems', Mandatory=$true, ValueFromPipelineByPropertyName=$true)] [Alias('PSPath')] [string[]] ${LiteralPath}, [Parameter(Position=1)] [string] ${Filter}, [string[]] ${Include}, [string[]] ${Exclude}, [Alias('s')] [switch] ${Recurse}, [uint32] ${Depth}, [switch] ${Force}, [System.IO.FileAttributes] ${Attributes}, [switch] ${Directory}, [switch] ${File}, [switch] ${Hidden}, [switch] ${ReadOnly}, [switch] ${System}, [switch] ${Name}) dynamicparam { try { # Set global variable to indicates PSColors.format.ps1xml should output ANSI colors $global:PSColorsUseAnsi = $Script:HasAnsi -and ($MyInvocation.PipelineLength -eq $MyInvocation.PipelinePosition); $targetCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet, $PSBoundParameters) $dynamicParams = @($targetCmd.Parameters.GetEnumerator() | Microsoft.PowerShell.Core\Where-Object { $_.Value.IsDynamic }) if ($dynamicParams.Length -gt 0) { $paramDictionary = [Management.Automation.RuntimeDefinedParameterDictionary]::new() foreach ($param in $dynamicParams) { $param = $param.Value if(-not $MyInvocation.MyCommand.Parameters.ContainsKey($param.Name)) { $dynParam = [Management.Automation.RuntimeDefinedParameter]::new($param.Name, $param.ParameterType, $param.Attributes) $paramDictionary.Add($param.Name, $dynParam) } } return $paramDictionary } } catch { throw } } begin { try { $outBuffer = $null if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer)) { $PSBoundParameters['OutBuffer'] = 1 } $showDotFiles = -not $env:PSCOLORS_HIDE_DOTFILE -or $env:PSCOLORS_HIDE_DOTFILE.ToLower() -ne 'true' $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Microsoft.PowerShell.Management\Get-ChildItem', [System.Management.Automation.CommandTypes]::Cmdlet) $scriptCmd = {& $wrappedCmd @PSBoundParameters | ? { $Force -or $showDotFiles -or -not $_.Name.StartsWith('.') } } $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin) $steppablePipeline.Begin($PSCmdlet) } catch { throw } } process { try { $steppablePipeline.Process($_) } catch { throw } } end { try { # Get-ChildItem has ended. PSColors.format.ps1xml will not longer append ANSI codes $global:PSColorsUseAnsi = $false; $steppablePipeline.End() } catch { throw } } } if($Script:HasAnsi) { # If ANSI is active, use custom PSColors.format.ps1xml for output coloring Update-FormatData -Prepend (Join-Path $PSScriptRoot PSColors.format.ps1xml) } |