Command Line

Improving ‘diff’ readability on Windows | Tip

The output of diff -q path1 path2 is pretty verbose. This function

  • Converts full paths to relative
  • Differences are red.

Missing ‘diff’ ?

If git is installed, you may need to update your %PATH% environment variable.

# in your profile
$Env:Path = "$Env:ProgramFiles\Git\usr\bin", $Env:Path -join ';'

Stand-Alone function Compare-Directory

This is an isolated version of Ninmonkey.Console: Compare-Directory . I removed all dependencies except coloring is provided by the module PoshCode/Pansies.

function Invoke-NativeCommand {
        wrapper to both call 'Get-NativeCommand' and invoke an argument list
        PS> # Use the first 'python' in path:
        Invoke-NativeCommand 'python' -Args '--version'

        # command name: 'python' 'ping.exe', extension is optional
        [Parameter(Mandatory, Position = 0)]

        # Force error if multiple  binaries are found

        # native command argument list
        [Parameter(Position = 1)]

    $binCommand = Get-NativeCommand $CommandName -OneOrNone:$OneOrNone -ea Stop
    & $binCommand @ArgumentList

function Compare-Directory {
    Compare Two directories using 'diff'
    Compare-Directory 'c:\foo' 'c:\bar\bat'
        # Path1
        [Parameter(Mandatory, Position = 0)]

        # Path2
        [Parameter(Mandatory, Position = 1)]

        # Output original raw text?

    $Base1 = $Path1 | Get-Item -ea Stop
    $Base2 = $Path2 | Get-Item -ea Stop
    $Label1 = $Base1 | Split-Path -Leaf | New-Text -fg 'green'
    $Label2 = $Base2 | Split-Path -Leaf | New-Text -fg 'yellow'

        Path: $Path1
        Path: $Path2
    " | Write-Information

    $stdout = Invoke-NativeCommand 'diff' -args @(

    $outColor = $stdout
    $outColor = $outColor -replace [regex]::Escape($path1), $Label1
    $outColor = $outColor -replace [regex]::Escape($path2), $Label2
    $outColor = $outColor -replace 'Only in', (New-Text 'Only In' -fg 'red')
    $outColor = $outColor -replace 'Differ', (New-Text 'Differ' -fg 'red')

    if ($OutputRaw) {
        h1 'Raw' | Write-Information


function Get-NativeCommand {
        wrapper that returns Get-Item on a native command
        # if you want an error when multiple options are found
        PS> Get-NativeCommand python -OneOrNone
        # note: this is important, $cmdArgs to be an array not scalar for '@' usage
        $binPy = Get-NativeCommand python
        $cmdArgs = @('--version')
        & $binPy @cmdArgs
        # Name of Native .exe Application
        [Parameter(Mandatory, Position = 0, ValueFromPipeline)]

        # One or None: Raise errors when there are more than one match

    process {
        try {
            $query = Get-Command -Name $CommandName -All -CommandType Application -ea Stop
            | Sort-Object Name

        } catch [CommandNotFoundException] {
            Write-Error "ZeroResults: '$CommandName'"

        if ($OneOrNone -and $query.Count -gt 1) {
            $query | Format-Table -Wrap -AutoSize -Property Name, Version, Source
            Write-Error "OneOrNone: Multiple results for '$CommandName'"

        if ($query.Count -gt 1) {
            $query = $query | Select-Object -First 1

        Write-Debug "Using Item: $($query.Source)"
Command Line PowerShell Quick Tips References And Cheat Sheets

Easy way to cache results on the Command Line | Power Shell Tip

Sometimes you’ll need to run a command with the same input with different logic.
This can be a hassle using a slow command like Get-ADUser or Get-ChildItem on a lot of files like ~ (Home) with -Depth / -Recurse

ls ~ -Depth 4 | Format-Table Name

PowerShell 7.0+

Powershell 7 added the Ternary Operator, and several operators for handling $null values.

All of these examples will only run Get-ChildItem the first time. Any future calls are cached.

Null-Coalesce ??= Assignment Operator

This is my favorite on the Command line. The RHS (Right Hand Side) skips evaluation if the left side is not $null

$AllFiles ??= ls ~ -Depth 4

Using the Null-Coalesce ?? Operator

$AllFiles = $AllFiles ?? ( ls ~ -Depth 4  )

Ternary Operator ? whenTrue : WhenFalse

$allFiles = $allFiles ? $allFiles : ( ls ~ -Depth 4 )

Windows PowerShell and Powershell < 7

Windows Powershell can achieve the same effect with an if statement

if(! $AllFiles) { $AllFiles = ls ~ -Depth 4 }