Продолжаем “работу над ошибками”
В прошлый раз я рассказал о параметре командлетов -ErrorAction, а сегодня займёмся его соседом -ErrorVariable. Как можно догадаться из названия, он указывает переменную в которую будет помещён объект ошибки (да, в PowerShell даже ошибки являются объектами
). Но тут возникает одна популярная ошибка. Обычно все (в том числе и я
) пробуют указать в качестве аргумента этой команде переменную
[PS <24> C:\Root] Get-Process -id 1234 -ErrorVariable $MyError
Get-Process : Cannot find a process with the process identifier 1234.
At line:1 char:12
+ Get-Process <<<< -id 1234 -ErrorVariable $MyError
Казалось бы всё правильно, произошла ошибка, и соответствующий объект был помещен в переменную $MyError? Ан нет, такой переменной даже не существует. В чём же дело? А в том что парсер PowerShell’а, разбирая эту строчку увидел символ $ и понял что следом за ним идет переменная, которую надо преобразовать в её значение перед передачей команде (логично ведь?
). А так как такой переменной не существует, PowerShell поступил так же как он обычно поступает с неназначенными переменными - передал вместо неё … ничего. То есть параметр -ErrorVariable не получил названия переменной в которую ему следовало поместить ошибку. Думаю уже понятно что для того чтобы этого не произошло, надо указывать просто название переменной, без символа $:
[PS <25> C:\Root] Get-Process -id 1234 -ErrorVariable MyError
Get-Process : Cannot find a process with the process identifier 1234.
At line:1 char:12
+ Get-Process <<<< -id 1234 -ErrorVariable MyError
[PS <26> C:\Root] $MyError
Get-Process : Cannot find a process with the process identifier 1234.
At line:1 char:12
+ Get-Process <<<< -id 1234 -ErrorVariable MyError
Итак объект с ошибкой у нас есть, что же с ним можно делать дальше?
Нет! Ни в коем случае не парсить! Хотя это и можно сделать - это было бы в корне неправильно. У нас в руках полноценный объект, с очень полезными свойстами к которым можно обращаться без всяких заморочек с разбором текста (который кстати может отличатся не только у разных ошибок, но и при использовании разных языков).
И тут возникает вторая тонкость. При попытке посмотреть свойства ошибки перенаправив её на команду Format-List * нас ждёт жестокий облом:
[PS <27> C:\Root] $MyError | Format-List *
Get-Process : Cannot find a process with the process identifier 1234.
At line:1 char:12
+ Get-Process <<<< -id 1234 -ErrorVariable MyError
На выходе получился не ожидаемый список всех свойств, а тот же самый текст. Чтобы этого не случилось, надо добавить к Format-List параметр -Force:
[PS <28> C:\Root] $MyError | Format-List * -Force
Exception : Microsoft.PowerShell.Commands.ProcessCommandException: Cannot find a process with the process identifier 1234.
TargetObject : 1234
CategoryInfo : ObjectNotFound: (1234:Int32) [Get-Process], ProcessCommandException
FullyQualifiedErrorId : NoProcessFoundForGivenId,Microsoft.PowerShell.Commands.GetProcessCommand
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
Еще стоит обратить внимание на то что $MyError является массивом. В случае если при выполнении команды произойдет несколько ошибок - все они будут помещены в переменную, и ни одна не потеряется. И поэтому если мы хотим посмотреть например свойство InvocationInfo то следует указать индекс элемента:
[PS <29> C:\Root] $MyError[0].InvocationInfo
MyCommand : Get-Process
CommandLineParameters : {[Id, System.Int32[]]}
ScriptLineNumber : 1
OffsetInLine : 12
ScriptName :
Line : Get-Process -id 1234 -ErrorVariable MyError
PositionMessage :
At line:1 char:12
+ Get-Process <<<< -id 1234 -ErrorVariable MyError
InvocationName : Get-Process
PipelineLength : 1
PipelinePosition : 1
ExpectingInput : False
CommandOrigin : Runspace
Ну и конечно можно получить только значение конкретного свойства. И без всякого парсинга
Например позицию в строке на которой произошла ошибка:
[PS <30> C:\Root] $MyError[0].InvocationInfo.OffsetInLine
12
Это разумеется еще не всё про ошибки, ждите продолжений