Powershell Ignore error

Viewed 3186

How do you make powershell ignore failures on legacy commands?

All powershell modules support -ErrorAction, however that does not work with legacy commands like NET STOP

NET STOP WUAUSERV
echo $?
true

I want to attempt to stop the service, and if the service is already stopped, continue. An easy way to reproduce this is to try and stop the service twice.

Things I've tried

$ErrorActionPreference = "SilentlyContinue"
NET STOP WUAUSERV
NET STOP WUAUSERV
echo $LASTEXITCODE

Tried using AND and OR operrators

and

NET STOP WUAUSERV || $true
NET STOP WUAUSERV || $true
echo $LASTEXITCODE

or

NET STOP WUAUSERV && $true
NET STOP WUAUSERV && $true
echo $LASTEXITCODE

I've also tried redirecting errors

NET STOP WUAUSERV 2>nul
NET STOP WUAUSERV 2>nul
echo $LASTEXITCODE

As recommended in a similar question, I've also tried

cmd.exe /C "NET STOP WUAUSERV"

How can I make this legacy command idempotent?

3 Answers

For many common tasks, the right answer is to use the native PowerShell commands that already exist.

For this particular example, the correct path is to use Stop-Service cmdlet, which will handle your conditions gracefully.

If you must use a legacy tool, see this StackOverflow answer: Powershell: Capture program stdout and stderr to separate variables

The .exe's don't put a traditional value on the PowerShell output pipeline for you to evaluate, so trying to compare $true does nothing useful. See also: Windows PowerShell Rethinking the Pipeline

Additionally, $ErrorActionPreference will have no effect on a legacy .EXE. (And -ErrorAction is specific to PowerShell commands.)

  • To silence error / stderr output in PowerShell, use 2> $null, not 2> NUL.

    • The value of $ErrorActionPreference should not have any effect on calling external utilities (console applications) such as net.exe, but - due to a bug as of Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.9 - if the value is 'Stop', 2> $null (indeed, any redirection of stream 2, the error stream) currently triggers a PowerShell error.
  • Unfortunately, control operators && and || are not supported in PowerShell as of Windows PowerShell v5.1 / PowerShell Core v6.0.0-beta.9; even if they were, however, you wouldn't need them here (and you wouldn't use them with $true or $false).


Irrespective of whether stderr output is silenced or not:

  • $LASTEXITCODE contains the exit code of the most recently executed external utility.

  • Immediately after executing an external utility, $? is $True if $LASTEXITCODE is 0, and $False otherwise.

For a comprehensive discussion of PowerShell's error handling - with respect to both PowerShell-native commands and external utilities - see here.

My other answer discusses dealing with stderr output / exit codes from external executables generally.

As for an idempotent way to stop a service (ensuring that a service is in the stopped state):

  • Matthew Wetmore's helpful answer suggests using PowerShell's Stop-Service cmdlet, which should be idempotent: it either stops the service, if it is running, or is a no-op if it already is in the stopped state.

    • Stopping is synchronous, unless you use the -NoWait switch (PSv5+), as shown in this answer of mine.
  • If, as you suggest here, there is indeed a problem with Stop-Service (I'm not aware of any issues), you can supplement use of net.exe with the Get-Service cmdlet to ensure that a service is stopped, while still detecting error cases:

$svc = 'wuauserv'
if ((Get-Service $svc).Status -ne 'Stopped') {
  net stop $svc
  if ($LASTEXITCODE) { Throw "Failed to stop service $svc."}
} else {
  Write-Verbose -Verbose "(Service $svc is already stopped.)"
}
Related