I've been giving PowerShell (v3.0) a shot for the first time today, and became enormously frustrated with the strange way some of its error-handling concepts are implemented.
I wrote the following piece of code (using the Remote Registry PowerShell Module)
try
{
New-RegKey -ComputerName $PCName -Key $Key -Name $Value
Write-Host -fore Green ($Key + ": created")
}
catch
{
Write-Host -fore Red "Unable to create RegKey: " $Key
Write-Host -fore Red $_
}
(This is just a snippet)
Apparently the default behavior of PowerShell is to NOT catch errors which are non-terminating. So I added the following line at the top op my script, as recommended by various people:
$ErrorActionPreference = "Stop"
Executing this in the PowerShell ISE did indeed catch all errors. However, execution following command from the terminal still does not catch my errors.
From ISE:
PS C:\windows\system32> C:\Data\Scripts\PowerShell\Error.ps1
Errorhandling: Stop
SOFTWARE\MySoftware does not exist. Attempting to create
Unable to create RegKey: SOFTWARE\MySoftware
Key 'SOFTWARE\MySoftware' doesn't exist.
From Command-Line:
PS C:\Data\Scripts\PowerShell> .\Error.ps1
Errorhandling: Stop
SOFTWARE\MySoftware does not exist. Attempting to create
New-RegKey : Key 'SOFTWARE\MySoftware' doesn't exist.
At C:\Data\Scripts\PowerShell\Error.ps1:17 char:13
+ New-RegKey -ComputerName $PCName -Key $Key -Name $Value
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [Write-Error], WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,New-RegKey
SOFTWARE\MySoftware: created
I have no idea why the behavior of the Preference Variables behaves differently depending on where they are called from, especially since the ISE seems to execute the exact same command?
Based on other feedback, I changed the following line:
New-RegKey -ComputerName $PCName -Key $Key -Name $Value
To:
New-RegKey -ComputerName $PCName -Key $Key -Name $Value -ErrorAction Stop
Using this method, I was able to trap errors from both the command-line and the ISE, but I don't want to specify the error behaviour on each Cmdlet I call, especially because the catching of errors is essential to the proper functioning of the code. (Plus, the fact that this method DOES work only serves to confuse me even more)
What is the proper way of defining error-handling behavior for the scope of an entire script and/or module?
Also, here's my $PSVersionTable:
PS C:\Data\Scripts\PowerShell> $PSVersionTable
Name Value
---- -----
PSVersion 3.0
WSManStackVersion 3.0
SerializationVersion 1.1.0.1
CLRVersion 4.0.30319.18408
BuildVersion 6.2.9200.16481
PSCompatibleVersions {1.0, 2.0, 3.0}
PSRemotingProtocolVersion 2.2
$ErrorActionPreference = 'Stop'; Remove-Item -Verbose xxxxxx; echo hi
. You would not expect theecho
to be executed if the file "xxxxxx" does not exist, but it does get executed. If you remove the-Verbose
, then it works as expected. – dan-gph$ErrorActionPreference = 'Stop'
to the top of almost all of my scripts, and it works as expected. But in this one case (and in yours), it didn't work. That's why I think it's a bug. – dan-gph