PowerShell — настройка $ErrorActionPreference для всего скрипта

Сегодня я впервые попробовал PowerShell (v3.0) и был крайне разочарован странным способом реализации некоторых его концепций обработки ошибок.

Я написал следующий фрагмент кода (используя модуль удаленного реестра PowerShell)

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 $_
}

(Это всего лишь фрагмент)

По-видимому, поведение PowerShell по умолчанию заключается в том, чтобы НЕ перехватывать ошибки, которые не прекращаются. Поэтому я добавил следующую строку вверху моего сценария, как рекомендовали разные люди:

$ErrorActionPreference = "Stop"

Выполнение этого в PowerShell ISE действительно выявило все ошибки. Однако выполнение следующей команды из терминала по-прежнему не улавливает мои ошибки.

Из 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.

Из командной строки:

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

Я понятия не имею, почему поведение переменных предпочтений ведет себя по-разному в зависимости от того, откуда они вызываются, тем более что ISE, похоже, выполняет одну и ту же команду?

Основываясь на других отзывах, я изменил следующую строку:

New-RegKey -ComputerName $PCName -Key $Key -Name $Value

To:

New-RegKey -ComputerName $PCName -Key $Key -Name $Value -ErrorAction Stop

Используя этот метод, я смог перехватывать ошибки как из командной строки, так и из ISE, но я не хочу указывать поведение ошибок для каждого вызываемого мной командлета, особенно потому, что перехват ошибок необходим для правильного функционирования код. (Кроме того, тот факт, что этот метод ДЕЙСТВИТЕЛЬНО работает, только еще больше сбивает меня с толку)

Каков правильный способ определения поведения обработки ошибок для всего скрипта и/или модуля?

Кроме того, вот моя таблица $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

person romatthe    schedule 20.01.2014    source источник
comment
Это может быть ошибка. Я нашел похожий случай. Выполните это в PS3: $ErrorActionPreference = 'Stop'; Remove-Item -Verbose xxxxxx; echo hi. Вы не ожидаете, что echo будет выполнено, если файл xxxxxx не существует, но он выполняется. Если вы удалите -Verbose, то он будет работать как положено.   -  person dan-gph    schedule 21.01.2014
comment
@Dangph Это именно то, что я имею в виду: поведение, которое вы демонстрируете, вызывает крайнее замешательство. Функция, столь необходимая для написания базового сценария, не должна сбивать с толку (или, возможно, я просто дурак), по крайней мере, если это действительно предполагаемое поведение, а не ошибка.   -  person romatthe    schedule 21.01.2014
comment
Я этого не понимаю. Я добавляю $ErrorActionPreference = 'Stop' в начало почти всех своих скриптов, и он работает, как и ожидалось. Но в этом случае (и в вашем) это не сработало. Вот почему я думаю, что это ошибка.   -  person dan-gph    schedule 22.01.2014


Ответы (1)


Поскольку вы используете V3, у вас также есть возможность использовать $PSDefaultParameterValues:

$PSDefaultParameterValues += @{'New-RegKey:ErrorAction' = 'Stop'}

Обычно это меняет его в глобальном масштабе. Если вы хотите изолировать его только для локальной области или области сценария, вы можете сначала инициализировать новую в локальной области:

$PSDefaultParameterValues = @{}
$PSDefaultParameterValues += @{'New-RegKey:ErrorAction' = 'Stop'}

Если вы хотите унаследовать то, что уже находится в родительской области, а затем добавить к ней локальную область:

 $PSDefaultParameterValues = $PSDefaultParameterValues.clone()
 $PSDefaultParameterValues += @{'New-RegKey:ErrorAction' = 'Stop'}

Чтобы установить ErrorAction по умолчанию для всех командлетов, а не только для New-RegKey, укажите '*:ErrorAction' вместо 'New-RegKey:ErrorAction' в приведенном выше коде.

person mjolinor    schedule 21.01.2014
comment
Настраивает ли это предпочтение уровня профиля, сеанса или сценария? Я не могу найти ответ на этот вопрос сразу. - person romatthe; 21.01.2014
comment
Он сделает это в первой области, в которой найдет $PSDefaultParameterValues. Обновлен ответ. - person mjolinor; 21.01.2014
comment
Спасибо, очень полезный ответ! Я все еще думаю, что это немного странно, справляться с такими вещами, сейчас мне комфортно с этим решением. - person romatthe; 21.01.2014
comment
Это не объясняет, почему $ErrorActionPreference = "Stop" не сработало. Почему мы должны установить этот параметр по умолчанию в New-RegKey? - person dan-gph; 22.01.2014
comment
Хотел бы я иметь на это ответ, но его нет. Модули, кажется, играют в некоторые забавные игры с масштабом, для которого никто не получил хорошего объяснения: modules-any-sug" title="странное поведение с областью действия переменной powershell scriptblock и модулями any sug"> stackoverflow.com/questions/2193410/ Это сообщение о том, как написать свой модуль, чтобы он импортировал текущие настройки настройки: powershell.org/wp/2014/01/13/, но я не знаю, как заставить его делать это вне модуля. - person mjolinor; 22.01.2014
comment
Такая же проблема с такими командами, как Clear-Disk из командлетов DISM... какой беспорядок. Это затрудняет серьезное отношение к powershell; У меня всего пара недель, а я уже добился еще нескольких подобных вещей. Спасибо @mjolinor за обходной путь. - person aggieNick02; 19.06.2017
comment
Обратите внимание, что указания *:ErrorAction недостаточно, вам также необходимо указать $ErrorActionPreference = 'Stop'. Только последний будет ловить такие вещи, как вызов $a.propertyThatDoesntExist, когда у вас есть Set-StrictMode -Version Latest. - person aggieNick02; 28.06.2017