Search code examples
powershellcontrol-characters

Make control/invisible characters visible in PowerShell `Write-*` cmdlets


Background

I have a PowerShell script that reads some cell values from .xlsx files and validates them. This script sometimes reports errors at apparently normal cells. I investigated these cells and found that these cells contain control characters (e.g. tab) in their value.

Problem

I want to show the cell value in error messages, but control characters are invisible when you show a message with Write-* cmdlets like:

PS C:\> $message = "`t"
PS C:\> Write-Warning ("Cell Value: [{0}]" -F $message)
WARNING: Cell Value: [ ]
PS C:\>

I couldn't recognize what control characters are contained in the message.

Question

I want to make control characters in error messages visible to recognize what control characters are contained in the message at a glance.

Is there any way to make control/invisible characters visible in Write-* cmdlets? I assume control/invisible characters like:

  • ASCII C0/C1 control characters (CR, LF, HT, VT, ...)
  • Unicode control characters (ZWSP, LRM, RLM, ...)

Solution

  • you can make a function to replace those with a list of known control characters.

    Only downside in that approach is that you have to manually define the control characters you want to replace.

    Just tested it and this worked for me:

    function Show-ControlCharacters {
        param (
            [string]$inputString
        )
    
        $visualMap = @{
            "`0" = '<NUL>'; "`a" = '<BEL>'; "`b" = '<BS>'; "`t" = '<HT>'; "`n" = '<LF>'; "`r" = '<CR>'; "`e" = '<ESC>'; "`f" = '<FF>'; "`v" = '<VT>'
            # Add more mappings as needed
        }
    
        foreach ($key in $visualMap.Keys) {
            $inputString = $inputString -replace $key, $visualMap[$key]
        }
    
        return $inputString
    }
    
    $message = "`t"
    
    Write-Warning ("Cell Value: [{0}]" -F (Show-ControlCharacters($message)))
    

    I hope it helps

    Edit: The regex escape was redundant. But I think the return makes the intention of returning the value clearer. Thx @js2010