How to Handle and Suppress Errors in PowerShell When Checking Remote Processes


2 views

When working with PowerShell to check processes across multiple servers, you'll often encounter two main issues:

  • Connection errors when servers are unavailable
  • Missing process errors when the specified process doesn't exist

The basic command looks like this:

get-process -ComputerName server1,server2,server3 -name explorer | 
Select-Object processname,machinename

PowerShell has several ways to handle errors gracefully:

  • -ErrorAction parameter
  • -ErrorVariable parameter
  • Try/Catch blocks
  • $ErrorActionPreference variable

Here's an improved version that handles errors elegantly:

$servers = "server1","server2","server3"
$results = @()

foreach ($server in $servers) {
    try {
        $process = Get-Process -ComputerName $server -Name explorer -ErrorAction Stop
        $results += $process | Select-Object ProcessName, MachineName
    }
    catch [System.InvalidOperationException] {
        $results += [PSCustomObject]@{
            ProcessName = "N/A (Connection Failed)"
            MachineName = $server
        }
    }
    catch {
        $results += [PSCustomObject]@{
            ProcessName = "N/A (Process Not Found)"
            MachineName = $server
        }
    }
}

$results | Format-Table -AutoSize

For more sophisticated scenarios, consider these approaches:

$ErrorActionPreference = "SilentlyContinue"
$processes = $servers | ForEach-Object {
    $process = Get-Process -ComputerName $_ -Name explorer
    if (-not $process) {
        [PSCustomObject]@{
            ProcessName = "Not Running"
            MachineName = $_
        }
    }
    else {
        $process | Select-Object ProcessName, MachineName
    }
}
$ErrorActionPreference = "Continue"

Here's a function you can add to your profile or module:

function Get-RemoteProcess {
    param(
        [Parameter(Mandatory=$true)]
        [string[]]$ComputerName,
        
        [Parameter(Mandatory=$true)]
        [string]$ProcessName
    )
    
    foreach ($computer in $ComputerName) {
        try {
            $process = Get-Process -ComputerName $computer -Name $ProcessName -ErrorAction Stop
            $process | Select-Object ProcessName, MachineName
        }
        catch {
            [PSCustomObject]@{
                ProcessName = "ERROR: $($_.Exception.Message)"
                MachineName = $computer
            }
        }
    }
}

When querying processes across multiple servers using PowerShell's Get-Process cmdlet, connection failures or missing processes can disrupt your entire output pipeline. The default behavior throws terminating errors that halt execution, which isn't ideal for monitoring scenarios.

PowerShell provides several mechanisms to control error handling:

# Common error handling parameters
-ErrorAction: SilentlyContinue | Stop | Continue | Inquire | Ignore
-ErrorVariable: Store errors in specified variable

Here's an improved version that handles connection issues gracefully while maintaining useful output:

$servers = "server1","server2","server3","server4"
$results = @()

foreach ($server in $servers) {
    try {
        $process = Get-Process -ComputerName $server -Name explorer -ErrorAction Stop |
                  Select-Object ProcessName, MachineName
        $results += $process
    }
    catch [System.InvalidOperationException] {
        $results += [PSCustomObject]@{
            ProcessName = "N/A (Connection Failed)"
            MachineName = $server
        }
    }
    catch {
        $results += [PSCustomObject]@{
            ProcessName = "N/A (Process Missing)"
            MachineName = $server
        }
    }
}

$results | Format-Table -AutoSize

For simpler scenarios, you can use the silent continue approach:

Get-Process -ComputerName $servers -Name explorer -ErrorAction SilentlyContinue |
    Select-Object ProcessName, MachineName | Format-Table

This variation logs errors while continuing execution:

$errorLog = @()
$processes = Get-Process -ComputerName $servers -Name explorer -ErrorVariable +errorLog -ErrorAction SilentlyContinue

$processes | Select-Object ProcessName, MachineName | Format-Table

if ($errorLog) {
    Write-Warning "Encountered $($errorLog.Count) errors:"
    $errorLog | ForEach-Object { Write-Warning $_.Exception.Message }
}

When scanning many servers, consider these optimizations:

  • Use parallel processing with ForEach-Object -Parallel (PowerShell 7+)
  • Implement timeout parameters to prevent hanging
  • Cache results for frequently checked servers

Here's a comprehensive solution with all best practices:

param(
    [string[]]$ComputerNames,
    [string]$ProcessName = "explorer",
    [int]$TimeoutSeconds = 10
)

$results = foreach ($computer in $ComputerNames) {
    try {
        $params = @{
            ComputerName = $computer
            Name = $ProcessName
            ErrorAction = 'Stop'
        }
        
        if ($PSVersionTable.PSVersion.Major -ge 7) {
            $params.ThrottleLimit = 5
        }

        $process = Get-Process @params | 
            Select-Object ProcessName, MachineName, Id, Responding
        
        [PSCustomObject]@{
            Status = "Running"
            ProcessName = $process.ProcessName
            MachineName = $computer
            PID = $process.Id
            Responsive = $process.Responding
        }
    }
    catch [System.InvalidOperationException] {
        [PSCustomObject]@{
            Status = "Server Unreachable"
            ProcessName = $ProcessName
            MachineName = $computer
            PID = $null
            Responsive = $null
        }
    }
    catch [Microsoft.PowerShell.Commands.ProcessCommandException] {
        [PSCustomObject]@{
            Status = "Process Not Found"
            ProcessName = $ProcessName
            MachineName = $computer
            PID = $null
            Responsive = $null
        }
    }
}

$results | Format-Table -AutoSize