Write-Colour.psm1
using namespace System.Text <# .SYNOPSIS Display strings in the host using multiple colours. .DESCRIPTION Takes an array of strings to display, and an array of console colours to use as the foreground colour for each string. See the notes for more information. .PARAMETER Message Strings to display in the host. .PARAMETER DefaultColour Default foreground colour to use when displaying strings. .PARAMETER Colour Foreground colours to use when displaying strings. .PARAMETER BackgroundColour Background colour to use when displaying strings. The same background colour will be used for every string. .PARAMETER LinesBefore Number of lines to output before the strings. Note that lines before are never written to the log file. .PARAMETER LinesAfter Number of lines to output after the strings. Note that lines after are never written to the log file. .PARAMETER SpacesBefore Number of spaces to output before the first string. .PARAMETER SpacesAfter Number of spaces to output after the last string. .PARAMETER TabsBefore Number of tabs to output before the first string. .PARAMETER LogFile Path to log file to which strings are written. Defaults to '$Env:WriteColourLogFile', (falls back to '$Env:WriteColorLogFile') to allow for global logging. .PARAMETER TimestampTimezone ID of the timezone to use when displaying timestamps. Available timezones can be found by running 'Get-TimeZone -ListAvailable'. .PARAMETER TimestampColour Colour of the timestamp to output before the first string. .PARAMETER TimestampFormat Format of the timestamp to output before the first string. .PARAMETER NoTimestamp Whether to omit the timestamp before the first string. .PARAMETER NoNewLine Whether there should be no new line at after output of the last string. .PARAMETER Split Whether to split strings so each is on a new line. .INPUTS None. You cannot pipe strings to this function. .OUTPUTS None. This function only displays text in the host. .NOTES There is no requirement for the number of colours specified in -Colour to match the number of messages specified in -Message. In fact, there is no requirement to specify -Colour at all. The -DefaultColour is will be used for each message without a corrisponding -Colour. Note that in reality, the strings displayed in the examples would be coloured. .EXAMPLE Write-Colour -Message "This ", "is ", "a ", "message" -Colour Red, Blue, Green, Yellow This is a message #> function Write-Colour { [alias("wrc", "Write-Color")] param( [Parameter(Mandatory = $True, Position = 0, HelpMessage = "Strings to display in the host.")] [Alias("m", "t")] [ValidateNotNullOrEmpty()] [String[]]$Message, [Parameter(Mandatory = $False)] [Alias("d", "DefaultColor", "DefaultForegroundColour", "DefaultForegroundColor")] [ConsoleColor]$DefaultColour = [ConsoleColor]::White, [Parameter(Mandatory = $False)] [Alias("c", "Color", "ForegroundColour", "ForegroundColor")] [ConsoleColor[]]$Colour = $DefaultColour, [Parameter(Mandatory = $False)] [Alias("b", "BackgroundColor")] [ConsoleColor[]]$BackgroundColour, [Parameter(Mandatory = $False)] [Alias("lb")] [ValidateRange(0, 5)] [Int]$LinesBefore = 0, [Parameter(Mandatory = $False)] [Alias("la")] [ValidateRange(0, 5)] [Int]$LinesAfter = 0, [Parameter(Mandatory = $False)] [Alias("sb")] [ValidateRange(0, 40)] [Int]$SpacesBefore = 0, [Parameter(Mandatory = $False)] [Alias("sa")] [ValidateRange(0, 40)] [Int]$SpacesAfter = 0, [Parameter(Mandatory = $False)] [Alias("tb")] [ValidateRange(0, 5)] [Int]$TabsBefore = 0, [Parameter(Mandatory = $False)] [Alias("l")] [ValidateNotNull()] [AllowEmptyString()] [String]$LogFile = (($null -ne $Env:WriteColourLogFile) ? $Env:WriteColourLogFile : $Env:WriteColorLogFile), [Parameter(Mandatory = $False, DontShow)] [Alias('le')] [Encoding]$LogFileEncoding = [Encoding]::UTF8, [Parameter(Mandatory = $False)] [Alias("tz")] [ValidateScript( { try { Get-TimeZone -Id $_ -ErrorAction Stop -ErrorVariable timezonErr } catch { throw [ValidationMetadataException]::new($timezonErr.ErrorRecord.Exception.Message) } })] [String]$TimestampTimezone = "UTC", [Parameter(Mandatory = $False)] [Alias("tc", "TimestampColor")] [ConsoleColor[]]$TimestampColour = [ConsoleColor]::DarkGray, [Parameter(Mandatory = $False)] [Alias("tf")] [ValidateNotNullOrEmpty()] [String]$TimestampFormat = "[yyyy-MM-dd HH:mm:sszzz] ", [Parameter(Mandatory = $False)] [Alias("nt")] [Switch]$NoTimestamp, [Parameter(Mandatory = $False)] [Alias("nn")] [Switch]$NoNewLine, [Parameter(Mandatory = $False)] [Alias("s")] [Switch]$Split ) begin { ### If a log file has been specified, ensure that it exists. if ($LogFile) { if (-not(Test-Path -Path $LogFile)) { New-Item -Path $logFile -ItemType File -Force } } ### Construct the timestamp, and inject it in to the strings to display. $timestamp = (-not($NoTimestamp)) ? [System.TimeZoneInfo]::ConvertTimeBySystemTimeZoneId((Get-Date), $TimestampTimezone).ToString($TimestampFormat) : "" if (-not($NoTimestamp)) { $Message = , $timestamp + $Message $Colour = , $TimestampColour + $Colour } ### Output lines before output of $Message begins. for ($i = 0; $i -lt $LinesBefore; $i++) { $Message = , ("{0}`n" -f $timestamp) + $Message $Colour = , $TimestampColour + $Colour } ### Add spaces before the first string, and after the last string. if ($SpacesBefore -gt 0) { $Message[0] = "{0}{1}" -f (" " * $SpacesBefore), $Message[0] } if ($SpacesAfter -gt 0) { $lastMessageIndex = $Message.Count - 1 $Message[$lastMessageIndex] = "{0}{1}" -f $Message[$lastMessageIndex], (" " * $SpacesAfter) } ### Add tabs before the first string. if ($TabsBefore -gt 0) { $Message[0] = "{0}{1}" -f ("`t" * $TabsBefore), $Message[0] } ### Create an array for the parameters that will be used when displaying strings in the host. $paramsArr = @() } process { ### Iterate the $Message string, with the purpose of this block being to minimise the number of 'Write-Host' commands that are executed. for ($i = 0; $i -lt $Message.Count; $i++) { $lastParamsIndex = $paramsArr.Count - 1 $currentForegroundColour = ($null -ne $Colour[$i]) ? $Colour[$i] : $DefaultColour $currentBackgroundColour = ($null -ne $BackgroundColour) ? $BackgroundColour : "" $currentNoNewLine = (($Split -eq $True) -and (-not($i -eq $Message.Count - 1))) ? $False : $True ### Check whether the current string should use the same foreground color as the last message. ### -- If $True, then append the string to the last 'Object' in the $paramsArr. ### -- Else, create a new set of parameters in the $paramsArr. if ($currentForegroundColour -eq $paramsArr[$lastParamsIndex].ForegroundColor) { $paramsArr[$lastParamsIndex].Object += (($Split -eq $True) ? "`n" : "") + $Message[$i] $paramsArr[$lastParamsIndex].NoNewLine = $currentNoNewLine } else { $tempParams = @{ Object = $Message[$i] ForegroundColor = $currentForegroundColour BackgroundColor = $currentBackgroundColour NoNewLine = $currentNoNewLine } ($tempParams.GetEnumerator() | Where-Object { -not $_.Value }) | ForEach-Object { $tempParams.Remove($_.Name) } $paramsArr += $tempParams } } ### Itterate $paramsArr array and display strings in the host. for ($i = 0; $i -lt $paramsArr.Count; $i++) { $params = $paramsArr[$i] Write-Host @params if (-not([String]::IsNullOrWhiteSpace($LogFile))) { $params.Object | Add-Content -Path $LogFile -Encoding $LogFileEncoding -NoNewline } } ### Output a new line at the end of the message, unless one should be specifically omitted. if (-not($NoNewLine)) { Write-Output "" if (-not([String]::IsNullOrWhiteSpace($LogFile))) { "" | Add-Content -Path $LogFile -Encoding $LogFileEncoding } } } end { ### Output lines after output of $Message ends. for ($i = 0; $i -lt $LinesAfter; $i++) { Write-Host $timestamp -ForegroundColor $TimestampColour } } } |