PowerShell DSC: Stop On Errors

Hello!

I like my code to stop on errors, not continue past them. For example, if a script fails to enable logs for my app I want to know right away. I don’t want to find out tomorrow when I need logs that aren’t there. The earlier I know about errors, the better. I learned this as the Fail Early Fail Often pattern.

PowerShell has a dedicated type of error that’s non-terminating. Its default is to continue past them. That applies in DSC configurations, too.

We can see this with a simple DSC configuration and the Write-Error command in a Script resource:

Configuration Headless {
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Node 'localhost' {
        Log Before {
            Message = 'Before error.'
        }
        Script NonTerminatingError {
            GetScript = {@{Result = ''}}
            SetScript = {Write-Error 'Non-terminating error.'}
            TestScript = {Return $false}
        }
        Log After {
            Message = 'After error.'
        }
    }
}

Headless -ConfigurationData $ConfigurationData
Start-DscConfiguration -Wait -Force -Verbose -Path '.\Headless\'

The middle resource generates an error but the last resource still runs:

...
VERBOSE: [VAGRANT]:                            [[Log]Before] Before error.
VERBOSE: [VAGRANT]: LCM:  [ End    Set      ]  [[Log]Before]  in 0.0000 seconds.
VERBOSE: [VAGRANT]: LCM:  [ End    Resource ]  [[Log]Before]
VERBOSE: [VAGRANT]: LCM:  [ Start  Resource ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]: LCM:  [ Start  Test     ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]: LCM:  [ End    Test     ]  [[Script]NonTerminatingError]  in 0.0780 seconds.
VERBOSE: [VAGRANT]: LCM:  [ Start  Set      ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]:                            [[Script]NonTerminatingError] Performing the 
operation "Set-TargetResource" on target "Executing the SetScript with the user supplied 
credential".
VERBOSE: [VAGRANT]: LCM:  [ End    Set      ]  [[Script]NonTerminatingError]  in 0.0470 seconds.
VERBOSE: [VAGRANT]: LCM:  [ Start  Resource ]  [[Log]After]
VERBOSE: [VAGRANT]: LCM:  [ Start  Test     ]  [[Log]After]
VERBOSE: [VAGRANT]: LCM:  [ End    Test     ]  [[Log]After]  in 0.0000 seconds.
VERBOSE: [VAGRANT]: LCM:  [ Start  Set      ]  [[Log]After]
VERBOSE: [VAGRANT]:                            [[Log]After] After error.
...

We can tell DSC to stop on non-terminating errors by passing the ErrorAction flag when we start our configuration:

Start-DscConfiguration -Wait -Force -Verbose -ErrorAction 'Stop' -Path '.\Headless\'

Now it stops on the Write-Error:

VERBOSE: [VAGRANT]:                            [[Log]Before] Before error.
VERBOSE: [VAGRANT]: LCM:  [ End    Set      ]  [[Log]Before]  in 0.0000 seconds.
VERBOSE: [VAGRANT]: LCM:  [ End    Resource ]  [[Log]Before]
VERBOSE: [VAGRANT]: LCM:  [ Start  Resource ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]: LCM:  [ Start  Test     ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]: LCM:  [ End    Test     ]  [[Script]NonTerminatingError]  in 0.0780 seconds.
VERBOSE: [VAGRANT]: LCM:  [ Start  Set      ]  [[Script]NonTerminatingError]
VERBOSE: [VAGRANT]:                            [[Script]NonTerminatingError] Performing the 
operation "Set-TargetResource" on target "Executing the SetScript with the user supplied 
credential".

Stderr from the command:

powershell.exe : Non-terminating error.

There’s also an $ErrorActionPreference variable, but that didn’t work no matter where I set it. The ErrorAction flag seems to be the way.

This isn’t necessarily a best practice, the PowerShell default is to continue past errors, but I usually have a better life if I switch it to stop.

Happy automating!

Adam

Need more than just this article? I’m available to consult.

You might also want to check out these related articles: