commands.ps1
<# .SYNOPSIS Retrieves the border symbols for a specified border type. .DESCRIPTION The Get-BorderSymbol function returns a hashtable containing the symbols used for the top-left, top-right, bottom-left, bottom-right corners, as well as the spacers for the top, bottom, left, and right sides of a border. The border type is specified using the BorderType enum. .PARAMETER BorderType Specifies the type of border for which to retrieve the symbols. The parameter is mandatory and must be a valid value from the BorderType enum. .OUTPUTS System.Collections.Hashtable A hashtable containing the border symbols. .EXAMPLE PS C:\> Get-BorderSymbol -BorderType Box Returns the border symbols for the "Box" border type. .EXAMPLE PS C:\> Get-BorderSymbol -BorderType Asterisk Returns the border symbols for the "Asterisk" border type. .EXAMPLE PS C:\> Get-BorderSymbol -BorderType DoubleBox Returns the border symbols for the "DoubleBox" border type. .NOTES The function uses the BorderType enum for input validation, ensuring only valid border types are accepted. #> function Get-BorderSymbol { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [Parameter(Mandatory = $true)] [BorderType] # Use the enum for validation $BorderType ) switch ($BorderType) { 'Asterisk' { return @{ TopLeft = "*"; TopRight = "*"; BottomLeft = "*"; BottomRight = "*"; TopSpacer = "*"; BottomSpacer = "*"; LeftSpacer = "*"; RightSpacer = "*" } } 'Hash' { return @{ TopLeft = "#"; TopRight = "#"; BottomLeft = "#"; BottomRight = "#"; TopSpacer = "#"; BottomSpacer = "#"; LeftSpacer = "#"; RightSpacer = "#" } } 'Plus' { return @{ TopLeft = "+"; TopRight = "+"; BottomLeft = "+"; BottomRight = "+"; TopSpacer = "+"; BottomSpacer = "+"; LeftSpacer = "+"; RightSpacer = "+" } } 'Box' { return @{ TopLeft = "┌"; TopRight = "┐"; BottomLeft = "└"; BottomRight = "┘"; TopSpacer = "─"; BottomSpacer = "─"; LeftSpacer = "│"; RightSpacer = "│" } } 'TwoLinesFrame' { return @{ TopLeft = "/"; TopRight = "\"; BottomLeft = "\"; BottomRight = "/"; TopSpacer = "="; BottomSpacer = "="; LeftSpacer = "||"; RightSpacer = "||" } } 'DoubleBox' { return @{ TopLeft = "╔"; TopRight = "╗"; BottomLeft = "╚"; BottomRight = "╝"; TopSpacer = "═"; BottomSpacer = "═"; LeftSpacer = "║"; RightSpacer = "║" } } 'DoubleCorners' { return @{ TopLeft = "╔"; TopRight = "╗"; BottomLeft = "╚"; BottomRight = "╝"; TopSpacer = "─"; BottomSpacer = "─"; LeftSpacer = "│"; RightSpacer = "│" } } 'BubbleBorder' { return @{ TopLeft = "(_)"; TopRight = "(_)"; BottomLeft = "(_)"; BottomRight = "(_)"; TopSpacer = "(_)"; BottomSpacer = "(_)"; LeftSpacer = "(_)"; RightSpacer = "(_)" } } 'BoxBorder' { return @{ TopLeft = "|_|"; TopRight = "|_|"; BottomLeft = "|_|"; BottomRight = "|_|"; TopSpacer = "|_|"; BottomSpacer = "|_|"; LeftSpacer = "|_|"; RightSpacer = "|_|" } } 'Dots' { return @{ TopLeft = "."; TopRight = "."; BottomLeft = ":"; BottomRight = ":"; TopSpacer = "."; BottomSpacer = "."; LeftSpacer = ":"; RightSpacer = ":" } } 'None' { return @{ TopLeft = ""; TopRight = ""; BottomLeft = ""; BottomRight = ""; TopSpacer = ""; BottomSpacer = ""; LeftSpacer = ""; RightSpacer = "" } } } } <# .SYNOPSIS Handle time measurement .DESCRIPTION Handle time measurement from when a cmdlet / function starts and ends Will write the output to the verbose stream (Write-PSFMessage -Level Verbose) .PARAMETER Start Switch to instruct the cmdlet that a start time registration needs to take place .PARAMETER End Switch to instruct the cmdlet that a time registration has come to its end and it needs to do the calculation .EXAMPLE PS C:\> Invoke-TimeSignal -Start This will start the time measurement for any given cmdlet / function .EXAMPLE PS C:\> Invoke-TimeSignal -End This will end the time measurement for any given cmdlet / function. The output will go into the verbose stream. .NOTES This is refactored function from d365fo.tools Original Author: Mötz Jensen (@Splaxi) Author: Oleksandr Nikolaiev (@onikolaiev) #> function Invoke-TimeSignal { [CmdletBinding(DefaultParameterSetName = 'Start')] param ( [Parameter(Mandatory = $true, ParameterSetName = 'Start', Position = 1 )] [switch] $Start, [Parameter(Mandatory = $True, ParameterSetName = 'End', Position = 2 )] [switch] $End ) $Time = (Get-Date) $Command = (Get-PSCallStack)[1].Command if ($Start) { if ($Script:TimeSignals.ContainsKey($Command)) { Write-PSFMessage -Level Verbose -Message "The command '$Command' was already taking part in time measurement. The entry has been update with current date and time." $Script:TimeSignals[$Command] = $Time } else { $Script:TimeSignals.Add($Command, $Time) } } else { if ($Script:TimeSignals.ContainsKey($Command)) { $TimeSpan = New-TimeSpan -End $Time -Start (($Script:TimeSignals)[$Command]) Write-PSFMessage -Level Verbose -Message "Total time spent inside the function was $TimeSpan" -Target $TimeSpan -FunctionName $Command -Tag "TimeSignal" $null = $Script:TimeSignals.Remove($Command) } else { Write-PSFMessage -Level Verbose -Message "The command '$Command' was never started to take part in time measurement." } } } <# .SYNOPSIS Converts a given text to ASCII art using a specified font and optional border style with color support. .DESCRIPTION The Convert-FSCPSTextToAscii function takes a string input and converts it into ASCII art using the specified font. Optionally, a border style and colors for the text and border can be applied. The function supports various fonts and border styles, allowing for customization of the output. The text and border colors can also be specified to enhance the visual appearance of the ASCII art. This function is ideal for creating visually appealing text banners or decorations in scripts, logs, or console outputs. .PARAMETER Text The text to be converted into ASCII art. This parameter is mandatory. .PARAMETER Font The font to be used for generating the ASCII art. This parameter is mandatory. .PARAMETER BorderType The type of border to apply around the ASCII art. This parameter is optional and defaults to 'None'. .PARAMETER TextColor The color to use for the ASCII art text. This parameter is optional and defaults to 'White'. .PARAMETER BorderColor The color to use for the border. This parameter is optional and defaults to 'Gray'. .PARAMETER Timestamp Enables or disables detailed information (timestamp) in the output. Defaults to `$false`. .EXAMPLE PS C:\> Convert-FSCPSTextToAscii -Text "Hello" -Font "Standard" -BorderType Asterisk -TextColor Yellow -BorderColor Green -DetailedInfo $true Converts the text "Hello" into ASCII art using the "Standard" font, surrounds it with an asterisk border, and applies yellow text with a green border. Detailed information (timestamp and function name) is enabled. .NOTES Author: Oleksandr Nikolaiev (@onikolaiev) #> function Convert-FSCPSTextToAscii { [CmdletBinding()] [OutputType()] param( [Parameter(Mandatory=$true)] [string]$Text, [Parameter(Mandatory=$true)] [FontType]$Font, [Parameter(Mandatory=$false)] [BorderType]$BorderType = [BorderType]::None, [Parameter(Mandatory=$false)] [ValidateSet("Black", "DarkBlue", "DarkGreen", "DarkCyan", "DarkRed", "DarkMagenta", "DarkYellow", "Gray", "DarkGray", "Blue", "Green", "Cyan", "Red", "Magenta", "Yellow", "White")] [string]$TextColor = "White", [Parameter(Mandatory=$false)] [ValidateSet("Black", "DarkBlue", "DarkGreen", "DarkCyan", "DarkRed", "DarkMagenta", "DarkYellow", "Gray", "DarkGray", "Blue", "Green", "Cyan", "Red", "Magenta", "Yellow", "White")] [string]$BorderColor = "Gray", [Parameter(Mandatory=$false)] [switch]$Timestamp = $false ) begin { Invoke-TimeSignal -Start # Save the current state of the PSFramework message style settings $originalTimestampSetting = (Get-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp').Value $originalFunctionNameSetting = (Get-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName').Value # Apply the detailed info setting if ($Timestamp) { Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $true Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $false } else { Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $false Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $false } $border = Get-BorderSymbol -BorderType $BorderType $fontDirectory = "$ModuleRoot\internal\misc\Fonts" $fontFilePath = Join-Path $fontDirectory "$Font.flf" # Load .flf file lines $flfLines = (Get-Content -Path $fontFilePath -Raw -ErrorAction Stop -Encoding UTF8) -split "`r?`n" # Parse metadata from the first line $headerParts = $flfLines[0].Split(' ') $charHeight = [int]$headerParts[1] $commentLines= [int]$headerParts[5] # Skip header + comment lines $startIndex = 1 + $commentLines # Build a dictionary of ASCII art for each printable character $charMap = @{ } $asciiCode = 32 # Start from space (ASCII 32) } PROCESS { $linePos = $startIndex while ($linePos -lt $flfLines.Count) { $charLines = @() for ($i = 0; $i -lt $charHeight; $i++) { if ($linePos -ge $flfLines.Count) { break } $charLines += $flfLines[$linePos] $linePos++ } $charMap[$asciiCode] = $charLines $asciiCode++ # Stop if we've passed typical ASCII printable range if ($asciiCode -gt 126) { break } } # Generate ASCII art lines for input text $outputLines = New-Object System.Collections.Generic.List[string] for ($row = 0; $row -lt $charHeight; $row++) { $rowBuilder = " " foreach ($c in $Text.ToCharArray()) { $charCode = [int][char]$c if ($charMap.ContainsKey($charCode)) { $rowText = $charMap[$charCode][$row] # Logic to handle '@' replacements if ($rowText -eq "@") { $rowText = " " } elseif ($rowText.EndsWith("@")) { $rowText = $rowText.TrimEnd("@") } # Logic to handle '$' replacements if ($rowText -eq "$") { $rowText = " " } elseif ($rowText.EndsWith("$")) { $rowText = $rowText.TrimEnd("$") } $rowBuilder += $rowText } else { $rowBuilder += "?" # fallback if not in font map } } $rowBuilder += " " $outputLines.Add($rowBuilder) } if ($outputLines[-1].Replace(" ", "").Length -eq 0) { $outputLines.RemoveAt($outputLines.Count - 1) # Remove last line of whitespace } # Determine max line length $maxLen = ($outputLines | ForEach-Object { $_.Length } | Measure-Object -Maximum).Maximum # Calculate the total width of the content including side borders $totalWidth = $maxLen if ($BorderType -ne [BorderType]::None) { # Repeat spacer patterns to match the required total width $topBorder = $border.TopSpacer * ([math]::Ceiling($totalWidth / $border.TopSpacer.Length)) $topBorder = $topBorder.Substring(0, $topBorder.Length) # Trim to exact length $bottomBorder = $border.BottomSpacer * [math]::Ceiling($totalWidth / $border.BottomSpacer.Length) $bottomBorder = $bottomBorder.Substring(0, $bottomBorder.Length) # Trim to exact length # Draw top border $topBorderLine = $border.TopLeft + $topBorder + $border.TopRight Write-PSFMessage -Level Important -Message ('<c="'+$BorderColor.ToLower()+'">' + $topBorderLine + "</c>") # Draw lines, padding each to the max length foreach ($line in $outputLines) { $curLineLength = $line.Length + $border.LeftSpacer.Length + $border.RightSpacer.Length $curAdvDifference = ($topBorderLine.Length - ($curLineLength)) $padded = $line.PadRight($maxLen + $curAdvDifference) Write-PSFMessage -Level Important -Message ('<c="'+$BorderColor.ToLower()+'">' + "$($border.LeftSpacer)" + "</c>" + '<c="'+$TextColor.ToLower()+'">' + $padded +"</c>" + '<c="'+$BorderColor.ToLower()+'">' + "$($border.RightSpacer)" + "</c>") } # Draw bottom border Write-PSFMessage -Level Host -Message ('<c="'+$BorderColor.ToLower()+'">' + $border.BottomLeft + $bottomBorder + $border.BottomRight + "</c>") } else { # Draw lines without borders foreach ($line in $outputLines) { Write-PSFMessage -Level Host -Message ('<c="'+$TextColor.ToLower()+'">' + $line + "</c>") } } } END { # Restore the original state of the PSFramework message style settings Set-PSFConfig -Module PSFramework -Name 'Message.Style.Timestamp' -Value $originalTimestampSetting Set-PSFConfig -Module PSFramework -Name 'Message.Style.FunctionName' -Value $originalFunctionNameSetting Invoke-TimeSignal -End } } |