How to Echo PowerShell Commands Like Batch File’s “ECHO ON” for Debugging and Logging


3 views

PowerShell has a built-in feature called Set-PSDebug -Trace 1 that provides similar functionality to batch file's ECHO ON. When enabled, it will display each command before execution:

Set-PSDebug -Trace 1
Get-ChildItem
Remove-Item temp.txt
Set-PSDebug -Trace 0

For more detailed logging including both commands and output, use the Start-Transcript cmdlet:

Start-Transcript -Path "C:\logs\script_log_$(Get-Date -Format 'yyyyMMdd').txt"
# Your commands here
Get-Process | Where-Object { $_.CPU -gt 100 }
Stop-Transcript

For more control over command echoing, create a custom function:

function Invoke-EchoCommand {
    param(
        [scriptblock]$ScriptBlock,
        [switch]$ShowCommand
    )
    
    if ($ShowCommand) {
        Write-Host "PS> $($ScriptBlock.ToString())" -ForegroundColor Cyan
    }
    
    & $ScriptBlock
}

# Usage example:
Invoke-EchoCommand -ScriptBlock { Get-Service | Where-Object Status -eq 'Running' } -ShowCommand

For complex scripts, you can implement AST (Abstract Syntax Tree) parsing to echo commands:

function Trace-ScriptBlock {
    param(
        [scriptblock]$ScriptBlock
    )

    $ast = $ScriptBlock.Ast
    $commands = $ast.FindAll({$args[0] -is [System.Management.Automation.Language.CommandAst]}, $true)

    foreach ($cmd in $commands) {
        Write-Host "Executing: $($cmd.Extent.Text)" -ForegroundColor Yellow
        Invoke-Expression $cmd.Extent.Text
    }
}

# Usage:
Trace-ScriptBlock {
    Get-ChildItem
    Get-Process | Sort-Object CPU -Descending | Select-Object -First 5
}

In PowerShell 7, you can use the PSHost trace source for more granular control:

$tracePS = [System.Management.Automation.TraceSource]::New("PSHost")
$tracePS.Listeners.Add([System.Management.Automation.ConsoleTraceListener]::new())
$tracePS.Switch = [System.Diagnostics.SourceLevels]::All

# This will now trace command execution
Get-ChildItem

For production scripts, consider combining multiple approaches:

# Start transcript
$logPath = "C:\logs\script_execution_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
Start-Transcript -Path $logPath

# Enable tracing
Set-PSDebug -Trace 1

try {
    # Main script execution
    Get-ChildItem -Path $env:USERPROFILE\Documents -File
    
    $services = Get-Service | Where-Object Status -eq 'Running'
    $services | Export-Csv -Path "running_services.csv" -NoTypeInformation
}
finally {
    # Clean up
    Set-PSDebug -Trace 0
    Stop-Transcript
}

When transitioning from batch scripting to PowerShell, many developers miss the simple echo on functionality that displays commands as they execute. This visibility is crucial for:

  • Debugging complex scripts
  • Creating self-documenting automation
  • Training purposes when sharing scripts
  • Audit trails in production environments

PowerShell offers several built-in ways to achieve command echoing:

1. Using Set-PSDebug

# Enable command tracing
Set-PSDebug -Trace 1

# Your script commands here
Get-Process | Where-Object { $_.CPU -gt 100 }

# Disable tracing when done
Set-PSDebug -Trace 0

2. The Transcript Feature

# Start recording session
Start-Transcript -Path "C:\scripts\log.txt" -IncludeInvocationHeader

# Commands will show with timestamps
New-Item -ItemType Directory -Path "C:\temp\test"
Stop-Service -Name "Spooler"

# End recording
Stop-Transcript

For more control over output formatting:

Wrapper Function Approach

function Invoke-EchoCommand {
    param (
        [scriptblock]$ScriptBlock
    )
    
    Write-Host -ForegroundColor Cyan "PS > $($ScriptBlock.ToString())"
    & $ScriptBlock
}

# Usage example:
Invoke-EchoCommand { Get-ChildItem C:\Windows -Recurse -Depth 2 }

PowerShell 7+ Enhanced Method

# Requires PS 7+
$PSNativeCommandUseErrorActionPreference = $true
$script:MyInvocation.MyCommand.ScriptContents | ForEach-Object {
    Write-Host "Executing: $_"
    Invoke-Expression $_
}
  • Combine command echoing with proper error handling using try/catch
  • Use different colors for commands vs output with Write-Host -ForegroundColor
  • For production scripts, consider logging to both console and file
  • Be mindful of sensitive information when echoing commands

While command echoing is valuable, it does add overhead. In performance-critical scripts:

  • Only enable echoing during development/debugging
  • Use conditional logic based on a $Debug parameter
  • Consider using the lighter-weight Set-PSDebug approach