PowerShell return value, exit code, or ErrorLevel equivalent

Date posted: 2015-10-08
Last updated: 2026-08-22

By verifying PowerShell exit code using the $? operator or $LASTEXITCODE is how you find out whether an external command was executed successfully in PowerShell. The operator $? contains True if the last operation succeeded and False otherwise.

Here is how you can verify whether an external command in PowerShell was executed successfully or not by checking its errorlevel. Simply by verifying the PowerShell exit code using the $? operator or $LASTEXITCODE.

The terms exit code, return value or ErrorLevel can be used interchangeably.

Powershell $? operator

The PowerShell operator $? contains True if the last operation succeeded and False otherwise.

# source:
# http://blogs.msdn.com/b/powershell/archive/2006/09/15/errorlevel-equivalent.aspx
if( $? ) {
	# True, last operation succeeded
}

if( !$? ) {
	# Not True, last operation failed
}

To illustrate PowerShell $? usage, have a look at the following DISM Cleanup-Image command. In my Windows Server disk cleanup using DISM blogpost, I’ve shown you how to clean up your Windows Server WinSxs folder with DISM.

Those commands are easily wrapped into a PowerShell script, and here it is:

$os_version = [System.Environment]::OSVersion.Version
# The above returns 6.3.9600.0 for Server 2012 R2 or
# 10.0.14393.0 for Server 2016. Server 2012 matches
# 6.2.9200.0, and so on.
#
# See https://msdn.microsoft.com/nl-nl/library/windows/desktop/ms724832(v=vs.85).aspx
# for more information about Windows Server versions.

$cleanup = $false
# Always be careful comparing strings and integers!
if( $os_version -ge ( New-Object System.Version "10.0" )) {
  # $os_version is greater than, or equal to "10.0", so
  # this is Windows Server 2016 or higher.
}

if( $os_version -ge ( New-Object System.Version "6.3" ) -And $os_version -le ( New-Object System.Version "10.0" )) {
  # $os_version is greater than 6.3 and smaller than 10.0,
  # therefore this must be Windows Server 2012 R2

  &dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase | Write-Output
  if( $? ) {
    # dism cleanup-image was successful, set variable to True
    $cleanup = $true
  }
}

if ( $cleanup ) {
  # Dism.exe was executed
  Write-Host "[*] System going down for reboot in 3 seconds!"
  &shutdown /r /f /t 3
} else {
  # an error occurred
  Write-Host "[*] Something went wrong with DISM and Cleanup-Image, `
    please perform the actions by hand."
}

How can I stop PowerShell errors from being displayed in a script?

Suppress error messages in PowerShell like a pro 🙂 If you don’t want to display PowerShell errors completely, you can wrap your PowerShell commands in a Try{} / Catch{} block. For example:

Get-Website | % {
	$sitename = $_.name;
	try{
		$handlers = Get-WebConfiguration /system.webServer/handlers/add -Location $sitename
		If( $handlers.scriptProcessor -like "x:\php73\php-cgi.exe*" ) {
			write-output "$sitename uses PHP 7.3"
			&appcmd.exe recycle apppool $sitename
			# Restart-WebAppPool $sitename
		}
	}
	catch {}
}

This checks the registred handler to see if scriptProcessor contains x:\php73\php-cgi.exe*. If so, recycle that website’s application pool (assuming the website and apppool names are the same).

By using a Try{} / Catch{} block, you don’t see the PowerShell errors like:

Get-WebConfiguration : Filename: ?\z:\sites\www\example.com\www\web.config
 Line number: 14
 Error: There is a duplicate 'system.web.extensions/scripting/scriptResourceHandler' section defined
 At line:3 char:13
 $handlers = Get-WebConfiguration /system.webServer/handlers/add -Loca …
 ~~~~~~~~~~~~~ CategoryInfo          : NotSpecified: (:) [Get-WebConfiguration], COMException
 FullyQualifiedErrorId : System.Runtime.InteropServices.COMException,Microsoft.IIs.PowerShell.Provider.GetConfigu
 rationCommand

The operator $? contains True if the last operation succeeded and False otherwise.

Sysadmins of the North

In PowerShell, $LASTEXITCODE and $? serve two distinct purposes when handling errors, and confusing them is a common gotcha for system administrators. $LASTEXITCODE specifically captures the integer exit code returned by the last native, external executable (like ping.exe or git) that finished running, where 0 typically indicates success and any non-zero value indicates a specific failure. On the other hand, $? is a boolean flag ($true or $false) that reflects the execution status of the very last command that ran – whether it was a native executable, a built-in PowerShell cmdlet, an advanced function, or an expression. Because $? is instantly overwritten by the success or failure of whatever ran immediately after your target command (even a simple if condition evaluation), you should always inspect or store $LASTEXITCODE immediately after executing external tools to ensure accurate error handling in your automation scripts.

PowerShell $LASTEXITCODE

The PowerShell $LASTEXITCODE should be 0, since $LASTEXITCODE contains the exit code of the last Win32 executable execution. $LASTEXITCODE the equivalent to cmd.exe %ERRORLEVEL%, and you can use it as follows in your PowerShell scripts:

&dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase
if( $LASTEXITCODE -eq 0 ) {
	Write-Output "Command executed successfully"
	# do something, like `Restart-Computer -Force`
} else {
	Write-Output "Last command failed"
}

$LASTEXITCODE is updated only by native executables (like dism.exe, netsh.exe). It is not set by PowerShell functions / cmdlets / scripts. If you run another native executable later, $LASTEXITCODE will change, so capturing it immediately is the recommended pattern. For example (pseudo code):

# $LASTEXITCODE is only set by native executables (e.g. dism.exe).
# It will change each time you run another native executable, so capture it immediately.

& dism.exe /Online /Cleanup-Image /StartComponentCleanup /ResetBase
$dismExit = $LASTEXITCODE

# do some stuff
# foreach-object { ... }
# more stuff (including other native commands)
# netsh.exe http delete sslcert hostnameport=example.com:443

# Fail the step if DISM failed
if ($dismExit -ne 0) {
    throw "DISM.exe failed (exit code $dismExit)"
}

One-time donation

Your donation 💸 helps support me in the ongoing costs running a blog like this one. Costs like coffee ☕, web hosting services 🖥 , article research 🔎 , and so on. Thank you 🙏 for your support❤️ https://www.paypal.com/paypalme/jreilink.


Summary

  • You can verify if a PowerShell command executed successfully by checking its PowerShell return value, exit code, or ErrorLevel equivalent using the $LASTEXITCODE and $? operators.
  • The $ operator gives a boolean result indicating the success of the last command, while $LASTEXITCODE provides the exit code of the last native executable.
  • To suppress error messages in PowerShell scripts, wrap commands in a Try{} / Catch{} block, which prevents errors from being displayed.
  • PowerShell’s $LASTEXITCODE echoes the exit code of the last executed Win32 executable, similar to cmd.exe’s %ERRORLEVEL%.
  • It’s crucial to capture $LASTEXITCODE immediately after running external tools for accurate error handling in scripts.

Leave a Comment