Common.ps1
# References: # 1. Below are the list of predefined vars that can be used: # - $PSScriptRoot [System defined] The folder path for current scipt file, NOT the caller script to call this function using namespace System.Management.Automation # MyProfile module env vars $MyProfileManualRegisteredListVarName = "MyProfileManualRegisteredList" $MyProfileImportedListVarName = "MyProfileImportedList" $MyProfileBinPathVarName = "MyProfileBinPath" $MyProfilePSModulesPathVarName = "MyProfilePSModulePath" # MyProfile module paths $MyProfileModulePsProfilePath = Join-Path $PSScriptRoot "PSProfile.ps1" $MyProfileModuleSysProfilePath = Join-Path $PSScriptRoot "SysProfile.ps1" $MyProfileModuleMyProfileShortcutPath = Join-Path $PSScriptRoot "MyProfile.lnk" $MyProfileModuleTemplateRootPath = Join-Path $PSScriptRoot "Template" # MyProfile template relative vars $MyProfileRelativeManifestPath = "MyProfileManifest.psd1" $MyProfileRelativeBinPath = "bin" $MyProfileRelativePSMoudlesPath = "PowerShell\Modules" $MyProfileRelativePSProfilePath = "PowerShell\PSProfile.ps1" $MyProfileRelativeSysProfilePath = "System\SysProfile.ps1" ############################################################################### # Helper functions ############################################################################### <# .SYNOPSIS Write host with embedded color tag support and multi level message type support. .DESCRIPTION A new way to write host with color by adding color tag inside output string. 1. All colors in Write-Host can also be used as tag here. E.g.: Black, DarkBlue, DarkGreen, DarkCyan, DarkRed, DarkMagenta, DarkYellow, Gray, DarkGray, Blue, Green, Cyan, Red, Magenta, Yellow, White 2. Color tag is case insensitive. 3. Use Type to support multi level message printing, and to map to different color. By default, [Default, Highlight, Warning] and [Keynote, Error] are enabled. .PARAMETER Object The Object to write. For string, embedded color tags are supported. .PARAMETER NoNewLine Specifies that the content displayed in the console does not end with a newline character. .PARAMETER Type The type of message to write the object as. It is used to mapping with message purpose, level and color. - Verbose Color=<Default> Level=[Verbose] For verbose information which is similar to the concept in Write-Verbose. - Debug Color=<Default> Level=[Debug] For Debug information which is similar to the concept in Write-Debug. - Information Color=<Default> Level=Information For Information information which is similar to the concept in Write-Information. - Default Color=<Default> Level=[Default,Highlight,Warning] For Default information which is similar to the concept in Write-Host with default color. - Highlight Color=Cyan Level=[Default,Highlight,Warning] For the information to highlight. The importancy is similar to Warning, but it is more for good/important things. - Warning Color=Yellow Level=[Keynote,Error] For Warning information which is similar to the concept in Write-Warning. - Keynote Color=Magenta Level=[Keynote,Error] For information which is considered as keynote. The importancy is similar to Error, but it is more for good/important things. - Error Color=Red Level=[Keynote,Error] For Warning information which is similar to the concept in Write-Error. Unlike the behavior of "-Verbose, -Debug, -InformationAction, -WarningAction, -ErrorAction" in standard powershell which control the message output individually, This function combines the behavior of them to support multi level message printing. The message level is "[Verbose] < [Debug] < [Information] < [Default, Highlight, Warning] < [Keynote, Error]". A type of object/message can be write only when its level or any lower level is enabled (via -Verbose, -WarningAction=Continue, etc.). By default, the lowest enabled level is "[Default,Highlight,Warning]". Below are the details about how to enable/disable a specified level. - [Verbose] Disabled by default, Use "-Verbose" to enable it - [Debug] Disabled by default, Use "-Debug" to enable it - [Information] Disabled by default, Use "-InformationAction Continue" to enable it - [Default,Highlight,Warning] Enabled by default, Use "-WarningAction SilentlyContinue" to disable it - [Keynote,Error] Enabled by default, Use "-ErrorAction SilentlyContinue" to disable it Ref: https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_preference_variables?view=powershell-7.1 .EXAMPLE Write-ColorHost "This is an <RED>single</RED> tag example!" Write-ColorHost "This is an <Red>multi</Red> <Green>tags</Green> example!" -Type Highlight Write-ColorHost "This is <Blue>an <Red>nested</Red> tags example</Blue>!" -Type Error #> function Write-ColorHost { param ( [Parameter(Position=0)] [object] $Object, [switch] $NoNewLine, [ValidateSet('Verbose', 'Debug', 'Information', 'Default', 'Highlight', 'Warning', 'Keynote', 'Error')] [string] $Type = 'Default' ) if ($VerbosePreference -eq [ActionPreference]::SilentlyContinue) { if ($Type -eq 'Verbose') { return } if ($DebugPreference -eq [ActionPreference]::SilentlyContinue) { if ($Type -eq 'Debug') { return } if ($InformationPreference -eq [ActionPreference]::SilentlyContinue) { if ($Type -eq 'Information') { return } if ($WarningPreference -eq [ActionPreference]::SilentlyContinue) { if ($Type -eq 'Warning' -OR $Type -eq 'Highlight' -OR $Type -eq 'Default') { return } if ($ErrorActionPreference -eq [ActionPreference]::SilentlyContinue) { return } } } } } $colorTagRegex = '(<\/?(?:Black|DarkBlue|DarkGreen|DarkCyan|DarkRed|DarkMagenta|DarkYellow|Gray|DarkGray|Blue|Green|Cyan|Red|Magenta|Yellow|White)>)' $colorStack = New-Object 'system.collections.generic.stack[string]' $curColor = switch ($Type) { 'Highlight' { 'Cyan' } # Reason: Blue looks not good, Green is often used to show something success. So Cyan is the best one. 'Warning' { 'Yellow' } # Reason: Match the color of Write-Warning 'Keynote' { 'Magenta' } # Reason: This color is most similar to the color for Error. 'Error' { 'Red' } # Reason: Match the color of Write-Error default { '' } } if ($Object -is [string]) { $message = [string]$Object [regex]::Split($Message, $colorTagRegex, 1) | % { if ([regex]::IsMatch($_, $colorTagRegex, 1)) { $color = $_ -replace '[<>\/]' if ($_ -like '</*>') { $curColor = if ($colorStack.Count -gt 0) { $colorStack.Pop() } else { '' } } else { $colorStack.Push($curColor) $curColor = $color } } else { if ([string]::IsNullOrWhiteSpace($curColor)) { Write-Host $_ -NoNewline } else { Write-Host $_ -NoNewline -ForegroundColor $curColor } } } if (-not $NoNewLine) { Write-Host '' } } else { if ([string]::IsNullOrWhiteSpace($curColor)) { Write-Host $Object -NoNewline:$NoNewLine } else { Write-Host $Object -NoNewline:$NoNewLine -ForegroundColor $curColor } } } function Convert-EnvironmentVariableTarget { param( [Parameter(Position=0, Mandatory = $true)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target ) $targetMapping = @{ Machine = [EnvironmentVariableTarget]::Machine User = [EnvironmentVariableTarget]::User Process = [EnvironmentVariableTarget]::Process } return $targetMapping[$Target] } function Set-EnvironmentVariable { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1, Mandatory = $true)] [AllowNull()] [AllowEmptyString()] [string] $Value, [Parameter(Position=2, Mandatory = $true)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target ) $targetType = Convert-EnvironmentVariableTarget $Target # Always expand the value when targeting to "Process" if ($Target -eq 'Process') { $Value = [Environment]::ExpandEnvironmentVariables($Value) } $oldValue = [Environment]::GetEnvironmentVariable($Name, $targetType) if ($oldValue -ne $value){ [Environment]::SetEnvironmentVariable($Name, $Value, $targetType) } if ($Target -ne 'Process') { [Environment]::SetEnvironmentVariable($Name, [Environment]::ExpandEnvironmentVariables($Value), [EnvironmentVariableTarget]::Process) } } function Get-EnvironmentVariable { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target = 'Process' ) $targetType = Convert-EnvironmentVariableTarget $Target return [Environment]::GetEnvironmentVariable($Name, $targetType) } function Set-EnvironmentListVariable { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1, Mandatory = $true)] [AllowNull()] [string[]] $ListValue, [Parameter(Position=2, Mandatory = $true)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target, [switch] $AllowDuplicate ) if (-NOT $AllowDuplicate) { $ListValue = $ListValue | Select-Object -Unique } $value = ($ListValue | ? { $_ -ne $null }) -join ';' Set-EnvironmentVariable -Name $Name -Value $value -Target $Target } function Get-EnvironmentListVariable { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target = 'Process' ) return @((Get-EnvironmentVariable -Name $Name -Target $Target) -split ';' | % { $_.Trim() } | ? { -NOT [string]::IsNullOrWhiteSpace($_) }) } function Add-EnvironmentListVariableValues { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1, Mandatory = $true)] [string[]] $ValuesToAppend, [Parameter(Position=2, Mandatory = $true)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target, [switch] $AppendFront, [switch] $AllowDuplicate ) $curValueList = Get-EnvironmentListVariable -Name $Name -Target $Target if (-NOT $AllowDuplicate) { $curValueList = $curValueList | Select-Object -Unique } $newValueList = if ($AppendFront) { @($ValuesToAppend) + $curValueList } else { @($curValueList) + $ValuesToAppend } if (-NOT $AllowDuplicate) { $newValueList = $newValueList | Select-Object -Unique } if ($newValueList.Count -gt $curValueList.Count) { Set-EnvironmentListVariable -Name $Name -ListValue $newValueList -Target $Target } } function Remove-EnvironmentListVariableValues { [CmdletBinding()] param( [Parameter(Position=0, Mandatory = $true)] [string] $Name, [Parameter(Position=1, Mandatory = $true)] [string[]] $ValuesToRemove, [Parameter(Position=2, Mandatory = $true)] [ValidateSet('Machine', 'User', 'Process')] [string] $Target ) $curValueList = Get-EnvironmentListVariable -Name $Name -Target $Target $newValueList = $curValueList | ? { -NOT($ValuesToRemove -contains $_) } if ($curValueList.Count -gt $newValueList.Count) { Set-EnvironmentListVariable -Name $Name -ListValue $newValueList -Target $Target } } |