Search code examples
regexpowershellreplaceasciiregexp-replace

Colorizing Get-Help output: how to use Regex to select exact string that starts with a hyphen(-) and ends with an alphabet


I'm currently trying to color my PowerShell's Get-Help cmdlet output. I successfully colored the output that shows the name of the cmdlet that I'm trying to use Get-Help on. I've also managed to color the output that shows all the headings of manual page. However, I'm unable to consistently color the output of the options shown on the manual page as you can see below:

#!/usr/bin/env powershell

$GREEN = "$([char]0x1b)[92m"
$RED = "$([char]0x1b)[91m"
$CYAN = "$([char]0x1b)[96m"
$BLUE = "$([char]0x1b)[94m" 
$YELLOW = "$([char]0x1b)[93m" 
$PURPLE = "$([char]0x1b)[95m" 
$RESET = "$([char]0x1b)[0m"

 
Get-Help @args > man_text.txt
$WORD = $args[0]

cat man_text.txt | `
    % {$_ `
         -creplace "^[A-Z \d\W]+$", "$GREEN`$0$RESET" `
         -creplace "\b$WORD\b", "$YELLOW`$0$RESET" `
         -replace "-[a-z]*\b", "$CYAN`$0$RESET" `
    }

enter image description here

In other words, I need the regex that matches a string that starts with a "-" and ends with an alphabet.

I would really appreciate if someone could help me with this. Thanks in advance.


Solution

  • This is something you could put into your $Profile file to automatically colorize output of Get-Help. It fixes the problem of colorizing the parameters using RegEx \B-\w+ (see regex101 demo).

    # Overrides the original Get-Help command to colorize its output.
    
    Function Get-Help {
        [CmdletBinding(DefaultParameterSetName='AllUsersView', HelpUri='https://go.microsoft.com/fwlink/?LinkID=2096483')]
        param(
            [Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
            [ValidateNotNullOrEmpty()]
            [string] ${Name},
    
            [string] ${Path},
    
            [ValidateSet('Alias','Cmdlet','Provider','General','FAQ','Glossary','HelpFile','ScriptCommand','Function','Filter','ExternalScript','All','DefaultHelp','DscResource','Class','Configuration')]
            [string[]] ${Category},
    
            [Parameter(ParameterSetName='DetailedView', Mandatory=$true)]
            [switch] ${Detailed},
    
            [Parameter(ParameterSetName='AllUsersView')]
            [switch] ${Full},
    
            [Parameter(ParameterSetName='Examples', Mandatory=$true)]
            [switch] ${Examples},
    
            [Parameter(ParameterSetName='Parameters', Mandatory=$true)]
            [string[]] ${Parameter},
    
            [string[]] ${Component},
    
            [string[]] ${Functionality},
    
            [string[]] ${Role},
    
            [Parameter(ParameterSetName='Online', Mandatory=$true)]
            [switch] ${Online},
    
            [Parameter(ParameterSetName='ShowWindow', Mandatory=$true)]
            [switch] ${ShowWindow}
        )
    
        process {
            # Call the original Get-Help command by its fully qualified path.
            $help = Microsoft.PowerShell.Core\Get-Help @PSBoundParameters
    
            # Define the styles for colorization.
            $style = @{
                SECTION = $PSStyle.Formatting.FormatAccent
                COMMAND = $PSStyle.Foreground.BrightYellow
                PARAM   = $PSStyle.Foreground.FromRgb(64,200,230)
            }
    
            # Escape the command name for use in RegEx
            $commandNameEscaped = [regex]::Escape( $help.Name )
    
            # Define a RegEx for doing the formatting. The names of the RegEx groups have to match the keys of the $style hashtable.
            $regEx = @(
                "(?m)(?<=^[ \t]*)(?<SECTION>[A-Z][A-Z \t\d\W]+$)"
                "(?<COMMAND>\b$commandNameEscaped\b)"
                "(?<PARAM>\B-\w+)"
            ) -join '|'
    
            # Format the help object
            $help | Out-String | ForEach-Object {
                [regex]::Replace( $_, $regEx, {  
                    # Get the RegEx group that has matched.
                    $matchGroup = $args.Groups.Where{ $_.Success }[ 1 ]
                    # Use the RegEx group name to select associated style for colorizing the match.
                    $style[ $matchGroup.Name ] + $matchGroup.Value + $PSStyle.Reset
                })
            }
        }
    }
    

    Output:

    Console Output

    Remarks:

    • By defining a function with the same name as an existing command, we effectively override it.
    • We can call the original command by specifying its fully qualified name, with module prefix like Microsoft.PowerShell.Core\Get-Help. To get the module prefix, type (Get-Command TheCommand).ModuleName.
    • Using the automatic $PSStyle variable as a handy way to get ANSI escape codes for coloring.
    • This even works when we call a command with -? parameter, as this calls Get-Help internally.
    • Demo and explanation of the complete pattern at regex101.
    • Requires PS 7.2+