REW

How Do I Check If A PowerShell Script Is Run Successfully?

Published Aug 29, 2025 5 min read
On this page

There are several robust methods to check if a PowerShell script ran successfully, ranging from simple automatic variables to advanced structured error handling.

The best approach depends on whether you are handling native PowerShell cmdlets, external applications, or complex scripts.

1. Using automatic variables ($? and $LASTEXITCODE)

PowerShell provides built-in variables that automatically store the status of the last executed command or application.

$? (Success/Failure status)

The $? variable is a boolean (True or False) that indicates whether the last operation was successful. It is a quick and simple way to check command status, but it has limitations.

  • True: The last command succeeded.
  • False: The last command failed.

Key Considerations:

  • $? is set by both PowerShell cmdlets and external applications.
  • A "successful" command that returns no results (like Get-Item C:\NonExistent without a -ErrorAction) will still set $? to True.
  • A terminating error (one that stops script execution) will set $? to False.

Example:

# Check for success of a PowerShell cmdlet
Get-Process -Name "notepad"
if ($?) {
    Write-Host "Notepad process retrieved successfully." -ForegroundColor Green
} else {
    Write-Host "Failed to retrieve the notepad process." -ForegroundColor Red
}
# Example with an external application
ping 127.0.0.1
if ($?) {
    Write-Host "Ping succeeded." -ForegroundColor Green
} else {
    Write-Host "Ping failed." -ForegroundColor Red
}

Use code with caution.

$LASTEXITCODE (External application exit code)

The $LASTEXITCODE variable contains the numerical exit code of the last external application that was run. By convention, an exit code of 0 indicates success, and any non-zero value indicates a failure.

  • This variable is crucial for checking the status of .exe files, batch scripts, or other non-PowerShell programs.
  • For a pure PowerShell script or cmdlet, this variable often remains at its previous value and should not be used as a primary success indicator.

Example:

# Run an external application
cmd.exe /c "exit 123"
# Check the exit code
if ($LASTEXITCODE -eq 0) {
    Write-Host "The application ran successfully." -ForegroundColor Green
} else {
    Write-Host "The application failed with exit code: $LASTEXITCODE" -ForegroundColor Red
}

Use code with caution.

2. Using try/catch/finally blocks

For complex or critical scripts, try/catch/finally provides the most robust and structured error handling. By default, catch blocks only handle terminating errors (those that stop a script's execution). You must convert non-terminating errors to terminating ones to catch them.

How it works:

  1. try: Contains the code to execute. If a terminating error occurs, control immediately transfers to the catch block.
  2. catch: Contains code to run when a terminating error is caught. You can log the error, display a custom message, or take corrective action. Use the $_ automatic variable inside the catch block to access the error object and its properties.
  3. finally: Contains code that always runs, regardless of whether an error occurred. This is ideal for cleanup tasks like closing files or connections.

Enabling try/catch for all errors

To ensure your catch block handles non-terminating errors, use the -ErrorAction Stop parameter on individual commands or set the global preference $ErrorActionPreference = "Stop" at the beginning of your script.

Example:

# Set global preference for the script
$ErrorActionPreference = "Stop"
try {
    # This command will fail and generate a terminating error
    Get-ChildItem -Path "C:\NonExistentFolder"
    Write-Host "This line will not run if the above command fails." -ForegroundColor Yellow
}
catch {
    Write-Host "An error occurred!" -ForegroundColor Red
    Write-Host "Details: $($_.Exception.Message)" -ForegroundColor Red
}
finally {
    Write-Host "Script execution completed." -ForegroundColor Cyan
}

Use code with caution.

3. Using output redirection to log errors

For scripts that run unattended (e.g., via a scheduler), capturing output and errors to a log file is essential. PowerShell's redirection operators allow you to send different streams to a file.

  • >: Redirects the Success stream.
  • 2>: Redirects the Error stream.
  • *>: Redirects all streams.
  • *>&1: Redirects all streams to the Success stream, which is then redirected to a log file.

Example: Capturing all output to a log file

# Run the script and send all output and errors to a log file.
# The `&` symbol is the call operator used for invoking a script or command.
powershell.exe -File "C:\Path\to\YourScript.ps1" *>&1 | Out-File -FilePath "C:\Path\to\ScriptLog.txt"

Use code with caution.

4. Best practices for robust error handling

Use specific catch blocks

If a script performs multiple, distinct operations, use specific catch blocks to handle different types of errors. This allows for more targeted recovery logic.

try {
    # Attempt a network operation
    Invoke-WebRequest -Uri "https://httpbin.org/status/404" -ErrorAction Stop
}
catch [System.Net.WebException] {
    Write-Warning "The web request failed. Check your network connection."
}
catch {
    Write-Warning "An unexpected error occurred."
}

Use code with caution.

Combine checks and try/catch

Use conditional checks (if/else) for predictable failures and reserve try/catch for unexpected exceptions.

# Use if/else for a predictable check
if (Test-Path -Path "C:\NonExistentFolder") {
    # Do something...
} else {
    Write-Warning "Folder not found. Operation skipped."
}
# Use try/catch for an unpredictable failure, like a permission denied error.
try {
    Remove-Item -Path "C:\ProtectedFolder" -ErrorAction Stop
}
catch [System.UnauthorizedAccessException] {
    Write-Error "Permission denied when trying to delete the folder."
}

Use code with caution.

Log everything with transcripts

The Start-Transcript and Stop-Transcript cmdlets record a transcript of an entire session, including commands and their outputs. This is extremely valuable for troubleshooting automated scripts.

Start-Transcript -Path "C:\Temp\ScriptLog.txt" -Append
# Your script commands here...
Get-Process -Name "explorer"
Get-Process -Name "nonexistent"
```Stop-Transcript
Use code with caution.

By combining these methods, you can create a comprehensive error handling strategy that ensures script success is reliably determined, logged, and handled appropriately in any environment.
Enjoyed this article? Share it with a friend.