Powershell ошибка строка 1 знак 1

Скачал Node js, открыл Power Shell, ввёл простую команду и он выдал ошибку. Искал решение проблемы. Не нашёл. Это мой первый час в изучении JS, помогите пожалуйста. Ниже привожу ответ консоли:

PS C:Usersromaw> console.log('kik')
console.log : Имя "console.log" не распознано как имя командлета, функции, файла сценария или выполняемой программы. Пр
оверьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытку.
строка:1 знак:1
+ console.log('kik')
+ ~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (console.log:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Коллеги, добрый день!

Возможно моя проблема не очень соотносится с данной веткой, но я попробую.

Есть скрипт PS, который сверяет хэши паролей пользователей на КДомена со словарем

$DictFile = "C:DSInternalspassword2.txt"
$DC = "ll.local"
$Domain = "DC=ll, DC=local"
$Dict = Get-Content $DictFile | ConvertTo-NTHashDictionary
Get-ADReplAccount -All -Server $DC -NamingContext $Domain | Test-PasswordQuality -WeakPasswordHashes $Dict -ShowPlainTextPasswords -IncludeDisabledAccounts
$EWB.Saveas('C:password.txt') 

Все работало, пока коллега не обновил пакет 

DSInternals

После обновления я не могу получить результаты данного скрипта, т.к. в новом пакете убрали командлет ConvertTo-NTHashDictionary и вместо него рекомендуется использовать командлет Test-PasswordQuality

Пытался переделать скрипт, но не получилось. Я не очень разбираюсь в PS

Пробовал 

$Dict = Get-Content $DictFile
Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
Test-PasswordQuality -WeakPasswords $Dict -ShowPlainTextPasswords -IncludeDisabledAccounts

Ошибка  

PS C:Windowssystem32> $Dict = Get-Content $DictFile
Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
Test-PasswordQuality -WeakPasswords $Dict -ShowPlainTextPasswords -IncludeDisabledAccounts
Get-Content : Не удается привязать аргумент к параметру "Path", так как он имеет значение NULL.
строка:1 знак:21
+ $Dict = Get-Content $DictFile
+                     ~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Get-Content], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetContentCommand
 
Get-ADReplAccount : Не удается проверить аргумент для параметра "Server". Аргумент пустой или имеет значение NULL. Укажите непустой аргумент, не имеющий значение NULL, п
осле чего повторите выполнение команды.
строка:2 знак:32
+ Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
+                                ~~~
    + CategoryInfo          : InvalidData: (:) [Get-ADReplAccount], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,DSInternals.PowerShell.Commands.GetADReplAccountCommand

и второй вариант

Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
Test-PasswordQuality -WeakPasswordsFile "C:distrPSDSInternalsPasswordDict.txt" -ShowPlainTextPasswords -IncludeDisabledAccounts

Ошибка

PS C:Windowssystem32> Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
Test-PasswordQuality -WeakPasswordsFile "C:distrPSDSInternalsPasswordDict.txt" -ShowPlainTextPasswords -IncludeDisabledAccounts
Get-ADReplAccount : Имя "Get-ADReplAccount" не распознано как имя командлета, функции, файла сценария или выполняемой программы. Проверьте правильность написания имени, 
а также наличие и правильность пути, после чего повторите попытку.
строка:1 знак:1
+ Get-ADReplAccount -All -Server $DC -NamingContext $Domain |
+ ~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-ADReplAccount:String) [], CommandNotFoundException
    + FullyQualifiedErrorId : CommandNotFoundException

Во втором варианте, видимо, опять командлет заменили.

Можете мне помочь собрать скрипт в соответствии с изменениями пакета 

DSInternals

Скрипт нужен для того, чтобы юзеры не создавали простые пароли. Раньше, когда скрипт работал, было выявлено три топ менеджера со слабыми паролями. 

Спасибо!

  • Edited by

    Tuesday, April 16, 2019 7:05 AM

  • Moved by
    Dmitriy VereshchakMicrosoft contingent staff, Moderator
    Tuesday, April 16, 2019 7:11 AM
    Из Win10

Вообще я редко вижу смысл в том чтобы отлавливать ошибки в скриптах, но недавно ко мне попалась задача, где необходимо было обработать ошибки в скрипте PowerShell. Дело в том что данный скрипт использовался как часть работы System Center Orchestrator. Для этого я использовал Try/Catch/Finaly . Но все по порядку.

Немного про ошибки

Ошибки можно условно разделить на две больших категории.

  1. Прерывающие
  2. Не прерывающие

Первые завершают выполнение конвейера с ошибкой. Т.е. дальнейшие команды в конвейере не выполняются. Например, вы не правильно указали имя команды. Вторая категория лишь генерирует ошибку, но конвейер продолжает выполняться далее. Например, вы запросили содержимое не существующего каталога.

В любом случае всю информацию о всех ошибках можно поглядеть в переменной $error. Последняя ошибка идет с индексом 0, т.е. $error[0] — покажет последнюю ошибку. А $error[0].Exception описание последней ошибки.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

PS C:> Get-Command NoCommand,Dir

Get-Command : Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Пров

ерьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытку.

строка:1 знак:1

+ Get-Command NoCommand,Dir

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (NoCommand:String) [Get-Command], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

CommandType     Name                                               ModuleName

                                                   

Alias           dir -> Get-ChildItem

PS C:> $error[0]

Get-Command : Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Пров

ерьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытку.

строка:1 знак:1

+ Get-Command NoCommand,Dir

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (NoCommand:String) [Get-Command], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

PS C:> $error[0].Exception

Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Проверьте правильн

ость написания имени, а также наличие и правильность пути, после чего повторите попытку.

Этот же пример, но в виде рисунка для наглядности.

Переменная Error

Для того чтобы выяснить была ли в какой-то части кода ошибка необходимо использовать Try. Это помогает избавиться от неожиданного и некорректного завершение вашего скрипта. Позволяя так же корректно завершить его работу.

Синтаксис выглядит в общем случае так.

Try

{

  часть кода в которой ищем ошибку

}

Catch

{

[тип ошибки, которую ищем] код,

     который будет выполнен когда ошибка будет найдена

}

Finally

{

код, который будет выполнен в любом случае

}

Однако использование Finally и определение типа ошибки — опционально и может не использоваться.

Для проверки напишем вот такой код где используем Try в PowerShell для того чтобы обработать ошибку деления на ноль и вывести информацию об ошибке.

try

{

[float](4/0)

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Как видно я произвожу деление на ноль в блоке try, т.е. совершаю прерывающую ошибку. Только прерывающие ошибку будут отловлены. А далее в блоке catch произвожу уже необходимые отладочные действия, т.е. произвожу обработку ошибки.. В моей исходной задаче я в данном блоке заносил информацию об ошибках в специальный лог файл, но давайте попробуем запустить мой данный пример.

PS C:> .test.ps1

Error!!!

System.Management.Automation.RuntimeException: Попытка деления на нуль. -> System.DivideByZeroException: Попытка делен

ия на нуль.

   Конец трассировки внутреннего стека исключений

   в System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exce

ption)

   в System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)

   в System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

   в System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

Увы в блоке try в PowerShell должна присутствовать прерывающая ошибка.

Преобразуем не прерывающую ошибку в прерывающую

Существует общий параметр для всех командлетов в PowerShell -ErrorAction. Данный параметр может принимать четыре значения

  • Continue — выводит ошибку и продолжает выполнение
  • SilentlyContinue — не выводит ошибку и продолжает выполнение
  • Stop — завершает выполнение
  • Inquire — спрашивает у пользователя как поступить

В нашем случае подходит действие stop. Если использовать параметр со значением -ErrorAction Stop, то при возникновении ошибки при выполнении команды, данная ошибка прерывает выполнение команды. Ниже пример скрипта, использующего -ErrorAction Stop.

try

{

  Dir NoFolder -ErrorAction Stop

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Ниже результат выполнения данного скрипта

PS C:> .test.ps1

Error!!!

System.Management.Automation.ItemNotFoundException: Не удается найти путь «C:NoFolder»,

так как он не существует.

   в System.Management.Automation.SessionStateInternal.GetChildItems(String path, Boolean recurse, C

mdletProviderContext context)

   в Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()

В моей исходной задаче try в PowerShell необходимо было использовать для всех команд в скрипте. Поскольку обработка ошибки была общей для любой ошибки в скрипте весь скрипт можно поместить в один Try, конечно это не совсем правильно, но зато просто. Чтобы каждый раз не писать -ErrorAction Stop. Можно воспользоваться переменной $ErrorActionPreference, которая имеет те же значения и сходна по действию, однако распространяет свое действие на все командлеты в скрипте.

$ErrorActionPreference = «stop»

try

{

  Dir Folder

  Get-Process -ComputerName TestPC

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Вместо заключения

Конечно, по началу вы мало будете задумываться об поиске ошибок, используя множество условных конструкций вы их минимизируете. Однако использование try в PowerShell позволит минимизировать случаи неожиданного завершения скрипта.

Здравствуйте.

Совсем недавно меня спросили как можно обработать ошибку выполнения в PowerShell. Вопрос был про Errors Handling. И вопрос звучал на анлийском. Что-то я помнил, но смутно, так как плотно обработчики ошибок писать не доводилось. Поэтому пошел в сеть, нашел отличный материал по теме, и весь его протестировал. Материал богатый поэтому разбиваю его на две части. Уверен что вам тоже будет полезно.

Для начала определимся, что такое обработка ошибок вообще. В общем случае ошибка — это поведение программы или скрипта, отличное от запланированного. Совсем избежать ошибок не очень возможно, поэтому надо предвидеть, где они могут возникнуть и писать код так, чтобы при возникновении ошибки можно было перехватить ее, проанализировать и определить дальнейшее поведение скрипта.  Именно это обычно и подразумевается под обработкой ошибок.

В PowerShell ошибки делятся на два типа: прерывающие (Terminating) и непрерывающие (Non-Terminating). Как следует из названия, непрерывающие ошибки позволяют продолжить выполнение команды, тогда как при возникновении прерывающей ошибки дальнейшее продолжение выполнения команды невозможно. К примеру, у нас есть файл со списком служб, которые необходимо перезапустить следующей командой:
Get-Content -Path C:Filesservices.txt | Restart-Service

Предположим, что перезапуск одной из перечисленных служб по какой либо причине невозможен. Тем не менее можно продолжать выполнение задачи, поскольку остальные службы доступны и их можно перезапустить. Это пример непрерывающей ошибки.

А теперь представьте, что у нас нет прав на открытие этого файла, и соответственно прочитать список служб мы не можем. В этой ситуации продолжение работы невозможно, т.е. это прерывающая ошибка.

PowerShell позволяет обрабатывать оба эти типа ошибок. Большинство ошибок в PowerShell непрерывающие, и сегодня речь пойдет о том, как их обрабатывать.

Обработка непрерывающих ошибок

Для получения ошибки возьмем службу с ″оригинальным″ названием Service. Поскольку службы этой на сервере нет, то обращение к ней стабильно будет генерировать ошибку. Запросим данные о нескольких службах командой:
Get-Service service,spooler

PS D:Courses!!!Done!PowerShellscripts> Get-Service service,spooler
Get-Service : Не удается найти службу с именем службы «service».
строка:1 знак:1
+ Get-Service service,spooler     + CategoryInfo          : ObjectNotFound: (service:String) [Get-Service], ServiceCommandException     + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
 Status   Name               DisplayName                          
——   —-               ————                          
Running  spooler            Диспетчер печати     

                

Как видно из примера, PowerShell не нашел службу Service, о чем выдал ошибку и затем продолжил выполнение команды. Давайте разберемся, почему команда повела себя именно так и как это поведение изменить.

За поведение команды при возникновении ошибки отвечает параметр ErrorAction, который может принимать одно из пяти значений:
• Continue;
• SilentlyContinue;
• Stop;
• Ignore;
• Inquire.

Примечание. Еще у ErrorAction может быть значение Suspend. Но это значение может применяться только к рабочим процессам (workflows), поэтому в рамках данной статьи речь о нем не пойдет.

Значение Continue означает, что при возникновении ошибки информация об этом будет выведена на экран (отправлена в поток вывода Error) и добавлена в автоматическую переменную $Error, после чего выполнение команды будет продолжено. Надо сказать, что Continue — это действие, определенное в сеансе по умолчанию, поэтому его можно не указывать явно.

PS D:Courses!!!Done!PowerShellscripts> Get-Service service,spooler -ErrorAction Continue
Get-Service : Не удается найти службу с именем службы «service».
строка:1 знак:1
+ Get-Service service,spooler -ErrorAction Continue     + CategoryInfo          : ObjectNotFound: (service:String) [Get-Service], ServiceCommandException     + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

Status   Name               DisplayName                          
——   —-               ————                          
Running  spooler            Диспетчер печати                     

При значении SilentlyContinue информация об ошибке добавляется в переменную $Error, но не выводится на экран. При этом команда продолжает выполняться дальше, также как и в предыдущем случае.

PS D:Courses!!!Done!PowerShellscripts> Get-Service service,spooler -ErrorAction SilentlyContinue
Status   Name               DisplayName                          
——   —-               ————                          
Running  spooler            Диспетчер печати                     

Значение Stop останавливает дальнейшее выполнение команды при возникновении ошибки. И наоборот, значение Ignore полностью игнорирует возникновение ошибки, при этом не выводится сообщение на экран и не производится запись в $Error. Это значение появилось в PowerShell 3.0.

PS D:Courses!!!Done!PowerShellscripts> Get-Service service,spooler -ErrorAction Stop
Get-Service : Не удается найти службу с именем службы «service».
строка:1 знак:1
+ Get-Service service,spooler -ErrorAction Stop     + CategoryInfo          : ObjectNotFound: (service:String) [Get-Service], ServiceCommandException     + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

Inquire — наиболее интересное значение ErrorAction. Если задать это значение, то при возникновении ошибки предлагается на выбор несколько действий: продолжить (Yes), продолжить не смотря на эту и все последующие ошибки (Yes to All), остановить (Halt) или приостановить (Suspend) выполнение команды.

Самый необычный эффект дает Suspend, при выборе которого открывается параллельный сеанс (Nested Namespace). Определить его можно по значку >>. Nested Namespace представляет из себя дочерний процесс, в котором можно полноценно работать — выполнять команды, запускать скрипты и т.п. Этот режим удобно использовать для отладки скриптов, например можно по быстрому исправить причину ошибки и продолжить выполнение. Для выхода из Nested Namespace достаточно набрать exit и выбрать необходимое действие.

PS D:Courses!!!Done!PowerShellscripts> Get-Service service,spooler -ErrorAction Inquire
Подтверждение
Не удается найти службу с именем службы «service».
[Y] Да — Y  [A] Да для всех — A  [H] Прервать команду — H  [S] Приостановить — S  [?] Справка
(значением по умолчанию является «Y»):s
PS D:Courses!!!Done!PowerShellscripts>> Get-Service service,spooler -ErrorAction Inquire
Подтверждение
Не удается найти службу с именем службы «service».
[Y] Да — Y  [A] Да для всех — A  [H] Прервать команду — H  [S] Приостановить — S  [?] Справка
(значением по умолчанию является «Y»):y
Get-Service : Не удается найти службу с именем службы «service».
строка:1 знак:1
+ Get-Service service,spooler -ErrorAction Inquire     + CategoryInfo          : ObjectNotFound: (service:String) [Get-Service], ServiceCommandException     + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand
Status   Name               DisplayName                          
——   —-               ————                          
Running  spooler            Диспетчер печати                     

Примечание. У параметра ErrorAction есть алиас — EA. Кроме того, вместо названия параметра можно указывать числовые значения: 0 (SilentlyContinue), 1 (Stop), 2 (Continue), 3 (Inquire). Так например, вместо:
Get-Service service,spooler -ErrorAction SilentlyContinue
можно написать так:
Get-Service service,spooler -EA 0

Переменные для обработки ошибок

Как я уже говорил, если не указывать параметр ErrorAction, то для команды действует режим обработки ошибок, определенный в сеансе. Этот режим задается переменной $ErrorActionPreference, которая по умолчанию имеет значение Continue. При желании можно переопределить режим для всего сеанса, задав переменной $ErrorActionPreference нужное значение.

 PS D:Courses!!!Done!PowerShellscripts>> $ErrorActionPreference
Continue

Все ошибки PowerShell сохраняет в автоматическую переменную $Error. Это глобальная переменная, которая представляет из себя массив строк, содержащий записи обо всех ошибках в текущем сеансе. Каждая новая ошибка добавляется в начало массива, соответственно для просмотра последней ошибки надо обратиться к самому первому элементу массива $Error[0].
$Error имеет свои свойства и методы, которые можно использовать. Например, посмотреть общее количество ошибок в текущем сеансе можно командой $Error.Count, а очистить список — командой $Error.Clear().

 PS D:Courses!!!Done!PowerShellscripts>> $Error[0]
Не удается преобразовать значение «SilentContinue» в тип «System.Management.Automation.ActionPreference». Ошибка: «Не удается сопоставить пустое имя идентификатора SilentContinue с допустимым именем перечислителя.  Укажите одно из следующих имен перечислителя и попробуйте еще раз: SilentlyContinue, Stop, Continue, Inquire, Ignore»
строка:1 знак:1
+ $ErrorActionPreference = «SilentContinue»

    + CategoryInfo          : MetadataError: (:) [], ArgumentTransformationMetadataException
    + FullyQualifiedErrorId : RuntimeException

PS D:Courses!!!Done!PowerShellscripts>> $Error.Count
8
PS D:Courses!!!Done!PowerShellscripts>> $Error.Clear()
PS D:Courses!!!Done!PowerShellscripts>> $Error.Count
0

Переменная $Error не безразмерна, по умолчанию она хранит не более 256 ошибок. При превышении этого количества наиболее старые ошибки будут затираться. При необходимости количество записей в переменной $Error можно увеличить, изменив значение другой переменной $MaximumErrorCount.

Кроме $Error для хранения ошибок допускается задавать собственные переменные. Сделать это можно с помощью параметра ErrorVariable, например так:
Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var

Обратите внимание, что имя переменной в команде задается без знака $, хотя в дальнейшем к ней обращаемся как к обычной переменной $var.

PS D:Courses!!!Done!PowerShellscripts>> Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var
Status   Name               DisplayName                          
——   —-               ————                          
Running  spooler            Диспетчер печати                     
PS D:Courses!!!Done!PowerShellscripts>> $var
Get-Service : Не удается найти службу с именем службы «service».
строка:1 знак:1
+ Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var
CategoryInfo          : ObjectNotFound: (service:String) [Get-Service], ServiceCommandException
    + FullyQualifiedErrorId : NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.GetServiceCommand

В отличие от глобальной переменной $Error заданные вручную переменные хранят только ошибки той команды, в которой они определены. Кроме того, по умолчанию эти переменные каждый раз перезаписываются и поэтому хранят только последнюю ошибку. Если вы хотите, чтобы новые ошибки добавлялись в переменную, не перезаписывая ее содержимое, то перед именем переменной надо поставить знак +, например +var.

В следующей части речь пойдет про обработку прерывающих ошибок (exceptions).

В Powershell существует несколько уровней ошибок и несколько способов их обработать. Проблемы одного уровня (Non-Terminating Errors) можно решить с помощью привычных для Powershell команд. Другой уровень ошибок (Terminating Errors) решается с помощью исключений (Exceptions) стандартного, для большинства языков, блока в виде Try, Catch и Finally. 

До рассмотрения основных методов посмотрим на теоретическую часть.

Автоматические переменные $Error

В Powershell существует множество переменных, которые создаются автоматически. Одна из таких переменных — $Error хранит в себе все ошибки за текущий сеанс PS. Например так я выведу количество ошибок и их сообщение за весь сеанс:

Get-TestTest
$Error
$Error.Count

Переменная $Error в Powershell

При отсутствии каких либо ошибок мы бы получили пустой ответ, а счетчик будет равняться 0:

Счетчик ошибок с переменной $Error в Powershell

Переменная $Error являет массивом и мы можем по нему пройтись или обратиться по индексу что бы найти нужную ошибку:

$Error[0]

foreach ($item in $Error){$item}

Вывод ошибки по индексу в Powershell c $Error

Свойства объекта $Error

Так же как и все что создается в Powershell переменная $Error так же имеет свойства (дополнительную информацию) и методы. Названия свойств и методов можно увидеть через команду Get-Member:

$Error | Get-Member

Свойства переменной $Error в Powershell

Например, с помощью свойства InvocationInfo, мы можем вывести более структурный отчет об ошибки:

$Error[0].InvocationInfo

Детальная информация об ошибке с $Error в Powershell

Методы объекта $Error

Например мы можем очистить логи ошибок используя clear:

$Error.clear()

Очистка логов об ошибке в Powershell с $Error

Критические ошибки (Terminating Errors)

Критические (завершающие) ошибки останавливают работу скрипта. Например это может быть ошибка в названии командлета или параметра. В следующем примере команда должна была бы вернуть процессы «svchost» дважды, но из-за использования несуществующего параметра ‘—Error’ не выполнится вообще:

'svchost','svchost' | % {Get-Process -Name $PSItem} --Error 

Критические ошибки в Powershell Terminating Errors

Не критические ошибки (Non-Terminating Errors)

Не критические (не завершающие) ошибки не остановят работу скрипта полностью, но могут вывести сообщение об этом. Это могут быть ошибки не в самих командлетах Powershell, а в значениях, которые вы используете. На предыдущем примере мы можем допустить опечатку в названии процессов, но команда все равно продолжит работу:

'svchost111','svchost' | % {Get-Process -Name $PSItem}

Не критические ошибки в Powershell Non-Terminating Errors

Как видно у нас появилась информация о проблеме с первым процессом ‘svchost111’, так как его не существует. Обычный процесс ‘svchost’ он у нас вывелся корректно.

Параметр ErrorVariable

Если вы не хотите использовать автоматическую переменную $Error, то сможете определять свою переменную индивидуально для каждой команды. Эта переменная определяется в параметре ErrorVariable:

'svchost111','svchost' | % {Get-Process -Name $PSItem } -ErrorVariable my_err_var
$my_err_var

Использование ErrorVariable в Powershell

Переменная будет иметь те же свойства, что и автоматическая:

$my_err_var.InvocationInfo

Свойства  ErrorVariable в Powershell

Обработка некритических ошибок

У нас есть два способа определения последующих действий при ‘Non-Terminating Errors’. Это правило можно задать локально и глобально (в рамках сессии). Мы сможем полностью остановить работу скрипта или вообще отменить вывод ошибок.

Приоритет ошибок с $ErrorActionPreference

Еще одна встроенная переменная в Powershell $ErrorActionPreference глобально определяет что должно случится, если у нас появится обычная ошибка. По умолчанию это значение равно ‘Continue’, что значит «вывести информацию об ошибке и продолжить работу»:

$ErrorActionPreference

Определение $ErrorActionPreference в Powershell

Если мы поменяем значение этой переменной на ‘Stop’, то поведение скриптов и команд будет аналогично критичным ошибкам. Вы можете убедиться в этом на прошлом скрипте с неверным именем процесса:

$ErrorActionPreference = 'Stop'
'svchost111','svchost' | % {Get-Process -Name $PSItem}

Определение глобальной переменной $ErrorActionPreference в Powershell

Т.е. скрипт был остановлен в самом начале. Значение переменной будет храниться до момента завершения сессии Powershell. При перезагрузке компьютера, например, вернется значение по умолчанию.

Ниже значение, которые мы можем установить в переменной $ErrorActionPreference:

  • Continue — вывод ошибки и продолжение работы;
  • Inquire — приостановит работу скрипта и спросит о дальнейших действиях;
  • SilentlyContinue — скрипт продолжит свою работу без вывода ошибок;
  • Stop — остановка скрипта при первой ошибке.

Самый частый параметр, который мне приходится использовать — SilentlyContinue:

$ErrorActionPreference = 'SilentlyContinue'
'svchost111','svchost' | % {Get-Process -Name $PSItem}

Игнорирование ошибок в Powershell с ErrorActionPreference и SilentlyContinue

Использование параметра ErrorAction

Переменная $ErrorActionPreference указывает глобальный приоритет, но мы можем определить такую логику в рамках команды с параметром ErrorAction. Этот параметр имеет больший приоритет чем $ErrorActionPreference. В следующем примере, глобальная переменная определяет полную остановку скрипта, а в параметр ErrorAction говорит «не выводить ошибок и продолжить работу»:

$ErrorActionPreference = 'Stop'
'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'SilentlyContinue'}

Использование параметра ErrorAction в ошибках с Powershell

Кроме ‘SilentlyContinue’ мы можем указывать те же параметры, что и в переменной $ErrorActionPreference. 

Значение Stop, в обоих случаях, делает ошибку критической.

Обработка критических ошибок и исключений с Try, Catch и Finally

Когда мы ожидаем получить какую-то ошибку и добавить логику нужно использовать Try и Catch. Например, если в вариантах выше мы определяли нужно ли нам отображать ошибку или останавливать скрипт, то теперь сможем изменить выполнение скрипта или команды вообще. Блок Try и Catch работает только с критическими ошибками и в случаях если $ErrorActionPreference или ErrorAction имеют значение Stop.

Например, если с помощью Powershell мы пытаемся подключиться к множеству компьютеров один из них может быть выключен — это приведет к ошибке. Так как эту ситуацию мы можем предвидеть, то мы можем обработать ее. Процесс обработки ошибок называется исключением (Exception).

Синтаксис и логика работы команды следующая:

try {
    # Пытаемся подключиться к компьютеру
}
catch [Имя исключения 1],[Имя исключения 2]{
    # Раз компьютер не доступен, сделать то-то
}
finally {
    # Блок, который выполняется в любом случае последним
}

Блок try мониторит ошибки и если она произойдет, то она добавится в переменную $Error и скрипт перейдет к блоку Catch. Так как ошибки могут быть разные (нет доступа, нет сети, блокирует правило фаервола и т.д.) то мы можем прописывать один блок Try и несколько Catch:

try {
    # Пытаемся подключится
}
catch ['Нет сети']['Блокирует фаервол']{
    # Записываем в файл
}
catch ['Нет прав на подключение']{
    # Подключаемся под другим пользователем
}

Сам блок finally — не обязательный и используется редко. Он выполняется самым последним, после try и catch и не имеет каких-то условий.

Catch для всех типов исключений

Как и было показано выше мы можем использовать блок Catch для конкретного типа ошибок, например при проблемах с доступом. Если в этом месте ничего не указывать — в этом блоке будут обрабатываться все варианты ошибок:

try {
   'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch {
   Write-Host "Какая-то неисправность" -ForegroundColor RED
}

Игнорирование всех ошибок с try и catch в Powershell

Такой подход не рекомендуется использовать часто, так как вы можете пропустить что-то важное.

Мы можем вывести в блоке catch текст ошибки используя $PSItem.Exception:

try {
   'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch {
   Write-Host "Какая-то неисправность" -ForegroundColor RED
   $PSItem.Exception
}

Переменная PSITem в блоке try и catch в Powershell

Переменная $PSItem хранит информацию о текущей ошибке, а глобальная переменная $Error будет хранит информацию обо всех ошибках. Так, например, я выведу одну и ту же информацию:

$Error[0].Exception

Вывод сообщения об ошибке в блоке try и catch в Powershell

Создание отдельных исключений

Что бы обработать отдельную ошибку сначала нужно найти ее имя. Это имя можно увидеть при получении свойств и методов у значения переменной $Error:

$Error[0].Exception | Get-Member

Поиск имени для исключения ошибки в Powershell

Так же сработает и в блоке Catch с $PSItem:

Наименование ошибок для исключений в Powershell

Для вывода только имени можно использовать свойство FullName:

$Error[0].Exception.GetType().FullName

Вывод типа ошибок и их названия в Powershell

Далее, это имя, мы вставляем в блок Catch:

try {
   'svchost111','svchost' | % {Get-Process -Name $PSItem -ErrorAction 'Stop'}
}
catch [Microsoft.PowerShell.Commands.ProcessCommandException]{
   Write-Host "Произошла ошибка" -ForegroundColor RED
   $PSItem.Exception
}

Указываем исключение ошибки в блоке Try Catch Powershell

Так же, как и было описано выше мы можем усложнять эти блоки как угодно указывая множество исключений в одном catch.

Выброс своих исключений

Иногда нужно создать свои собственные исключения. Например мы можем запретить добавлять через какой-то скрипт названия содержащие маленькие буквы или сотрудников без указания возраста и т.д. Способов создать такие ошибки — два и они тоже делятся на критические и обычные.

Выброс с throw

Throw — выбрасывает ошибку, которая останавливает работу скрипта. Этот тип ошибок относится к критическим. Например мы можем указать только текст для дополнительной информации:

$name = 'AD.1'

if ($name -match '.'){
   throw 'Запрещено использовать точки в названиях'
}

Выброс ошибки с throw в Powershell

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

$name = 'AD.1'

if ($name -like '*.*'){
   throw [System.IO.FileNotFoundException]'Запрещено использовать точки в названиях'
}

Выброс ошибки с throw в Powershell

Использование Write-Error

Команда Write-Error работает так же, как и ключ ErrorAction. Мы можем просто отобразить какую-то ошибку и продолжить выполнение скрипта:

$names = @('CL1', 'AD.1', 'CL3')

foreach ($name in $names){
   if ($name -like '*.*'){
      Write-Error -Message 'Обычная ошибка'
   }
   else{
      $name
   }
}

Использование Write-Error для работы с исключениями в Powershell

При необходимости мы можем использовать параметр ErrorAction. Значения этого параметра были описаны выше. Мы можем указать значение ‘Stop’, что полностью остановит выполнение скрипта:

$names = @('CL1', 'AD.1', 'CL3')

foreach ($name in $names){
   if ($name -like '*.*'){
      Write-Error -Message 'Обычная ошибка' -ErrorAction 'Stop'
   }
   else{
      $name
   }
}

Использование Write-Error и Stop в Powershell

Отличие команды Write-Error с ключом ErrorAction от обычных команд в том, что мы можем указывать исключения в параметре Exception:

Write-Error -Message 'Обычная ошибка' -ErrorAction 'Stop'

Write-Error -Message 'Исключение' -Exception [System.IO.FileNotFoundException] -ErrorAction 'Stop'

Свойства Write-Errror в Powershell

В Exception мы так же можем указывать сообщение. При этом оно будет отображаться в переменной $Error:

Write-Error -Exception [System.IO.FileNotFoundException]'Моё сообщение'

Свойства Write-Errror в Powershell 

Теги:

#powershell

#ошибки

Продолжаем тему обработки ошибок в PowerShell, начатую в предыдущей статье. Сегодня речь пойдет об обработке прерывающих ошибок (исключений). Надо понимать, что сообщение об ошибке — это не то же самое, что исключение. Как вы помните, в PowerShell есть два типа ошибок — непрерывающие и прерывающие.

Непрерывающие ошибки позволяют продолжить работу, тогда как прерывающие останавливают выполнение команды. Остановка приводит к исключению (exception), которое и можно отлавливать и обрабатывать.

Примечание. Таким же образом можно обрабатывать и непрерывающие ошибки. Изменение параметра ErrorAction на Stop прервет выполнение команды и произведет исключение, которое можно уловить.

Для наглядности сгенерируем ошибку, попытавшись прочитать файл, на который у нас нет прав. А теперь обратимся к переменной $Error и выведем данные об исключении. Как видите, данное исключение имеет тип UnauthorizedAccessException и относится к базовому типу System.SystemException.

определение исключения

Для обработки исключений в PowerShell есть несколько способов, которые мы сегодня и рассмотрим.

Try/Catch/Finally

Конструкция Try/Catch/Finally предназначена для обработки исключений, возникающих в процессе выполнения скрипта. В блоке Try располагается исполняемый код, в котором должны отслеживаться ошибки. При возникновении в блоке Try прерывающей ошибки оболочка PowerShell ищет соответствующий блок Catch для обработки этой ошибки, и если он найден, то выполняет находящиеся в нем инструкции. Блок Catch может включать в себя любые команды, необходимые для обработки возникнувшей ошибки иили восстановления дальнейшей работы скрипта.

Блок Finally располагается обычно в конце скрипта. Команды, находящиеся в нем, выполняются в любом случае, независимо от возникновения ошибок. Была ли  ошибка перехвачена и обработана блоком Catch или при выполнении скрипта ошибок не возникало вообще, блок Finally будет выполнен. Присутствие этого блока в скрипте необязательно, основная его задача — высвобождение ресурсов (закрытие процессов, очистка памяти и т.п.).

В качестве примера в блок Try поместим код, который читает файлы из указанной директории. При возникновении проблем блок Catch выводит сообщение об ошибке, после чего отрабатывает блок Finally и работа скрипта завершается:

try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch {
Write-Host ″Some error was found.″
}
finally {
Write-Host ″Finish.″
}

обработка общей ошибки с помощью trycatch

Для блока Catch можно указать конкретный тип ошибки, добавив после ключевого слова Catch в квадратных скобках название исключения. Так в следующем примере укажем в качестве типа исключение System.UnauthorizedAccessException, которое возникает при отсутствии необходимых прав доступа к объекту:

try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host ″File is not accessible.″
}
finally {
Write-Host ″Finish.″
}

обработка конкретного исключения в trycatch

Если для блока Catch указан тип ошибки, то этот блок будет обрабатывать только этот тип ошибок, или тип ошибок, наследуемый от указанного типа. При возникновении другого типа ошибка не будет обработана. Если же тип не указан, то блок будет обрабатывать любые типы ошибок, возникающие в блоке Try.

Блок Try может включать несколько блоков Catch, для разных типов ошибок, соответственно можно для каждого типа ошибки задать свой обработчик. Например, возьмем два блока Catch, один для ошибки при отсутствии прав доступа, а второй — для любых других ошибок, которые могут возникнуть в процессе выполнения скрипта:

try {
Get-Content -Path ″C:Files*″ -ErrorAction Stop
}
catch [System.UnauthorizedAccessException]
{
Write-Host ″File is not accessible.″
}
catch {
Write-Host ″Other type of error was found:″
Write-Host ″Exception type is $($_.Exception.GetType().Name)″
}
finally {
Write-Host ″Finish.″
}

обработка нескольких исключений в trycatch

Trap

Еще один способ обработки ошибок — это установка ловушки (trap). В этом варианте обработчик ошибок задается с помощью ключевого слова Trap, определяющего список команд, которые должны выполниться при возникновении прерывающей ошибки и исключения. Когда происходит исключение, то оболочка PowerShell ищет в коде инструкции Trap для данной ошибки, и если находит, то выполняет их.

Возьмем наиболее простой пример ловушки, которая обрабатывает все произошедшие исключения и выводит сообщение об ошибке:

trap {
Write-Host ″Error was found.″
}
Get-Content -Path C:File* -ErrorAction Stop

обработка исключения с помощью trap

Так же, как и для trycatch, ключевое слово Trap позволяет задавать тип исключения, указав его в квадратных скобках. К примеру, можно задать в скрипте несколько ловушек, одну нацелив на конкретную ошибку, а вторую на обработку оставшихся:

trap [System.Management.Automation.ItemNotFoundException]
{
Write-Host ″File is not accessible.″
break
}
trap {
Write-Host ″Other error was found.″
continue
}
Get-Content -Path C:File* -ErrorAction Stop

Вместе с Trap можно использовать ключевые слова Break и Continue, которые позволяют определить, должен ли скрипт продолжать выполняться после возникновения прерывающей ошибки. По умолчанию при возникновении исключения выполняются команды, входящие в блок Trap, выводится информация об ошибке, после чего выполнение скрипта продолжается со строки, вызвавшей ошибку:

trap {
Write-Host ″Error was found.″
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″

обработка исключения с помощью trap без доп. параметров

Если использовать ключевое слово Break, то при возникновении ошибки будет выполнены команды в блоке Trap, после чего выполнение скрипта будет прервано:

trap {
Write-Host ″Error was found.″
break
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″

Как  видно из примера, команда, следующая за исключением, не отработала и сообщение ″After error.″ выведено не было.

обработка исключения с помощью trap с параметром break

Если же в Trap включено ключевое слово Continue, то выполнение скрипта будет продолжено, так же как и в случае по умолчанию. Единственное отличие в том, что с Continue ошибка не записывается в поток Error и не выводится на экран.

trap {
Write-Host ″Error was found.″
continue
}
Write-Host ″Before error.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error.″

обработка исключения с помощью trap с параметром continue

Область действия

При отлове ошибок с помощью Trap надо помнить о такой вещи, как область действия (scope). Оболочка PowerShell является глобальной областью, в которую входят все процессы, запущенный скрипт получает собственную область, а если внутри скрипта определены функции, то внутри каждой определена своя, частная область действия. Это создает своего рода родительско-дочернюю иерархию.

При появлении исключения оболочка ищет ловушку в текущей области. Если в ней есть ловушка, она выполняется, если нет — то производится выход в вышестоящую область и поиск ловушки там. Когда ловушка находится, то происходит ее выполнение. Затем, если ловушка предусматривает продолжение работы, то оболочка возобновляет выполнение кода, начиная с той строки, которая вызвала исключение, но при этом оставаясь в той же области, не возвращаясь обратно.

Для примера возьмем функцию Content, внутри которой будет выполняться наш код. Область действия внутри функции назовем scope 1, а снаружи scope 2:

trap {
Write-Host ″Error was found.″
continue
}
function Content {
Write-Host ″Before error, scope1.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error, scope 1.″
}
Content
Write-Host ″After error, scope 2.″

При возникновении ошибки в функции Content оболочка будет искать ловушку внутри нее. Затем, не найдя ловушку внутри функции, оболочка выйдет из текущей области и будет искать в родительской области. Ловушка там есть, поэтому будет выполнена обработка ошибки, после чего Continue возобновит выполнение скрипта, но уже в родительской области (scope 2), не возвращаясь обратно в функцию (scope 1).

область действия, вариант 1

А теперь немного изменим скрипт, поместив ловушку внутрь функции:

function Content {
trap {
Write-Host ″Error was found.″
continue
}
Write-Host ″Before error, scope 1.″
Get-Content -Path C:File* -ErrorAction Stop
Write-Host ″After error, scope 1.″
}
Content
Write-Host ″After error, scope 2.″

Как видите, теперь при возникновении ошибки внутри функции будет произведена обработка ошибки, после чего выполнение  будет продолжено с той строки, в которой произошла ошибка — не выходя из функции.

область действия, вариант 2

Заключение

Если сравнить Try/Catch и Trap, то у каждого метода есть свои достоинства и недостатки. Конструкцию Try/Catch можно более точно нацелить на возможную ошибку, так как Catch обрабатывает только содержимое блока Try. Эту особенность удобно использовать при отладке скриптов, для поиска ошибок.

И наоборот, Trap является глобальным обработчиком, отлавливая ошибки во всем скрипте независимо от расположения. На мой взгляд это более жизненный вариант, который больше подходит для постоянной работы.

description Locale ms.date online version schema title

Describes how to use the `try`, `catch`, and `finally` blocks to handle terminating errors.

en-US

11/12/2021

https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.2&WT.mc_id=ps-gethelp

2.0.0

about Try Catch Finally

Short description

Describes how to use the try, catch, and finally blocks to handle
terminating errors.

Long description

Use try, catch, and finally blocks to respond to or handle terminating
errors in scripts. The Trap statement can also be used to handle terminating
errors in scripts. For more information, see about_Trap.

A terminating error stops a statement from running. If PowerShell does not
handle a terminating error in some way, PowerShell also stops running the
function or script using the current pipeline. In other languages, such as C#,
terminating errors are referred to as exceptions.

Use the try block to define a section of a script in which you want
PowerShell to monitor for errors. When an error occurs within the try block,
the error is first saved to the $Error automatic variable. PowerShell then
searches for a catch block to handle the error. If the try statement does
not have a matching catch block, PowerShell continues to search for an
appropriate catch block or Trap statement in the parent scopes. After a
catch block is completed or if no appropriate catch block or Trap
statement is found, the finally block is run. If the error cannot be handled,
the error is written to the error stream.

A catch block can include commands for tracking the error or for recovering
the expected flow of the script. A catch block can specify which error types
it catches. A try statement can include multiple catch blocks for different
kinds of errors.

A finally block can be used to free any resources that are no longer needed
by your script.

try, catch, and finally resemble the try, catch, and finally
keywords used in the C# programming language.

Syntax

A try statement contains a try block, zero or more catch blocks, and zero
or one finally block. A try statement must have at least one catch block
or one finally block.

The following shows the try block syntax:

The try keyword is followed by a statement list in braces. If a terminating
error occurs while the statements in the statement list are being run, the
script passes the error object from the try block to an appropriate catch
block.

The following shows the catch block syntax:

catch [[<error type>][',' <error type>]*] {<statement list>}

Error types appear in brackets. The outermost brackets indicate the element is
optional.

The catch keyword is followed by an optional list of error type
specifications and a statement list. If a terminating error occurs in the
try block, PowerShell searches for an appropriate catch block. If
one is found, the statements in the catch block are executed.

The catch block can specify one or more error types. An error type is a
Microsoft .NET Framework exception or an exception that is derived from a .NET
Framework exception. A catch block handles errors of the specified .NET
Framework exception class or of any class that derives from the specified
class.

If a catch block specifies an error type, that catch block handles that
type of error. If a catch block does not specify an error type, that catch
block handles any error encountered in the try block. A try statement can
include multiple catch blocks for the different specified error types.

The following shows the finally block syntax:

finally {<statement list>}

The finally keyword is followed by a statement list that runs every time the
script is run, even if the try statement ran without error or an error was
caught in a catch statement.

Note that pressing CTRL+C stops the pipeline. Objects
that are sent to the pipeline will not be displayed as output. Therefore, if
you include a statement to be displayed, such as «Finally block has run», it
will not be displayed after you press CTRL+C, even if the
finally block ran.

Catching errors

The following sample script shows a try block with a catch block:

try { NonsenseString }
catch { "An error occurred." }

The catch keyword must immediately follow the try block or another catch
block.

PowerShell does not recognize «NonsenseString» as a cmdlet or other item.
Running this script returns the following result:

When the script encounters «NonsenseString», it causes a terminating error. The
catch block handles the error by running the statement list inside the block.

Using multiple catch statements

A try statement can have any number of catch blocks. For example, the
following script has a try block that downloads MyDoc.doc, and it contains
two catch blocks:

try {
   $wc = new-object System.Net.WebClient
   $wc.DownloadFile("http://www.contoso.com/MyDoc.doc","c:tempMyDoc.doc")
}
catch [System.Net.WebException],[System.IO.IOException] {
    "Unable to download MyDoc.doc from http://www.contoso.com."
}
catch {
    "An error occurred that could not be resolved."
}

The first catch block handles errors of the System.Net.WebException and
System.IO.IOException types. The second catch block does not specify an
error type. The second catch block handles any other terminating errors that
occur.

PowerShell matches error types by inheritance. A catch block handles errors
of the specified .NET Framework exception class or of any class that derives
from the specified class. The following example contains a catch block that
catches a «Command Not Found» error:

catch [System.Management.Automation.CommandNotFoundException]
{"Inherited Exception" }

The specified error type, CommandNotFoundException, inherits from the
System.SystemException type. The following example also catches a Command
Not Found error:

catch [System.SystemException] {"Base Exception" }

This catch block handles the «Command Not Found» error and other errors that
inherit from the SystemException type.

If you specify an error class and one of its derived classes, place the catch
block for the derived class before the catch block for the general class.

[!NOTE]
PowerShell wraps all exceptions in a RuntimeException type. Therefore,
specifying the error type System.Management.Automation.RuntimeException
behaves the same as an unqualified catch block.

Using Traps in a Try Catch

When a terminating error occurs in a try block with a Trap defined within
the try block, even if there is a matching catch block, the Trap statement
takes control.

If a Trap exists at a higher block than the try, and there is no matching
catch block within the current scope, the Trap will take control, even if
any parent scope has a matching catch block.

Accessing exception information

Within a catch block, the current error can be accessed using $_, which
is also known as $PSItem. The object is of type ErrorRecord.

try { NonsenseString }
catch {
  Write-Host "An error occurred:"
  Write-Host $_
}

Running this script returns the following result:

An Error occurred:
The term 'NonsenseString' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.

There are additional properties that can be accessed, such as ScriptStackTrace,
Exception, and ErrorDetails. For example, if we change the script to the
following:

try { NonsenseString }
catch {
  Write-Host "An error occurred:"
  Write-Host $_.ScriptStackTrace
}

The result will be similar to:

An Error occurred:
at <ScriptBlock>, <No file>: line 2

Freeing resources using finally

To free resources used by a script, add a finally block after the try and
catch blocks. The finally block statements run regardless of whether the
try block encounters a terminating error. PowerShell runs the finally block
before the script terminates or before the current block goes out of scope.

A finally block runs even if you use CTRL+C to stop the
script. A finally block also runs if an Exit keyword stops the script from
within a catch block.

See also

  • about_Break
  • about_Continue
  • about_Scopes
  • about_Throw
  • about_Trap
description Locale ms.date online version schema title

Describes how to use the `try`, `catch`, and `finally` blocks to handle terminating errors.

en-US

11/12/2021

https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_try_catch_finally?view=powershell-7.3&WT.mc_id=ps-gethelp

2.0.0

about Try Catch Finally

Short description

Describes how to use the try, catch, and finally blocks to handle
terminating errors.

Long description

Use try, catch, and finally blocks to respond to or handle terminating
errors in scripts. The Trap statement can also be used to handle terminating
errors in scripts. For more information, see about_Trap.

A terminating error stops a statement from running. If PowerShell does not
handle a terminating error in some way, PowerShell also stops running the
function or script using the current pipeline. In other languages, such as C#,
terminating errors are referred to as exceptions.

Use the try block to define a section of a script in which you want
PowerShell to monitor for errors. When an error occurs within the try block,
the error is first saved to the $Error automatic variable. PowerShell then
searches for a catch block to handle the error. If the try statement does
not have a matching catch block, PowerShell continues to search for an
appropriate catch block or Trap statement in the parent scopes. After a
catch block is completed or if no appropriate catch block or Trap
statement is found, the finally block is run. If the error cannot be handled,
the error is written to the error stream.

A catch block can include commands for tracking the error or for recovering
the expected flow of the script. A catch block can specify which error types
it catches. A try statement can include multiple catch blocks for different
kinds of errors.

A finally block can be used to free any resources that are no longer needed
by your script.

try, catch, and finally resemble the try, catch, and finally
keywords used in the C# programming language.

Syntax

A try statement contains a try block, zero or more catch blocks, and zero
or one finally block. A try statement must have at least one catch block
or one finally block.

The following shows the try block syntax:

The try keyword is followed by a statement list in braces. If a terminating
error occurs while the statements in the statement list are being run, the
script passes the error object from the try block to an appropriate catch
block.

The following shows the catch block syntax:

catch [[<error type>][',' <error type>]*] {<statement list>}

Error types appear in brackets. The outermost brackets indicate the element is
optional.

The catch keyword is followed by an optional list of error type
specifications and a statement list. If a terminating error occurs in the
try block, PowerShell searches for an appropriate catch block. If
one is found, the statements in the catch block are executed.

The catch block can specify one or more error types. An error type is a
Microsoft .NET Framework exception or an exception that is derived from a .NET
Framework exception. A catch block handles errors of the specified .NET
Framework exception class or of any class that derives from the specified
class.

If a catch block specifies an error type, that catch block handles that
type of error. If a catch block does not specify an error type, that catch
block handles any error encountered in the try block. A try statement can
include multiple catch blocks for the different specified error types.

The following shows the finally block syntax:

finally {<statement list>}

The finally keyword is followed by a statement list that runs every time the
script is run, even if the try statement ran without error or an error was
caught in a catch statement.

Note that pressing CTRL+C stops the pipeline. Objects
that are sent to the pipeline will not be displayed as output. Therefore, if
you include a statement to be displayed, such as «Finally block has run», it
will not be displayed after you press CTRL+C, even if the
finally block ran.

Catching errors

The following sample script shows a try block with a catch block:

try { NonsenseString }
catch { "An error occurred." }

The catch keyword must immediately follow the try block or another catch
block.

PowerShell does not recognize «NonsenseString» as a cmdlet or other item.
Running this script returns the following result:

When the script encounters «NonsenseString», it causes a terminating error. The
catch block handles the error by running the statement list inside the block.

Using multiple catch statements

A try statement can have any number of catch blocks. For example, the
following script has a try block that downloads MyDoc.doc, and it contains
two catch blocks:

try {
   $wc = new-object System.Net.WebClient
   $wc.DownloadFile("http://www.contoso.com/MyDoc.doc","c:tempMyDoc.doc")
}
catch [System.Net.WebException],[System.IO.IOException] {
    "Unable to download MyDoc.doc from http://www.contoso.com."
}
catch {
    "An error occurred that could not be resolved."
}

The first catch block handles errors of the System.Net.WebException and
System.IO.IOException types. The second catch block does not specify an
error type. The second catch block handles any other terminating errors that
occur.

PowerShell matches error types by inheritance. A catch block handles errors
of the specified .NET Framework exception class or of any class that derives
from the specified class. The following example contains a catch block that
catches a «Command Not Found» error:

catch [System.Management.Automation.CommandNotFoundException]
{"Inherited Exception" }

The specified error type, CommandNotFoundException, inherits from the
System.SystemException type. The following example also catches a Command
Not Found error:

catch [System.SystemException] {"Base Exception" }

This catch block handles the «Command Not Found» error and other errors that
inherit from the SystemException type.

If you specify an error class and one of its derived classes, place the catch
block for the derived class before the catch block for the general class.

[!NOTE]
PowerShell wraps all exceptions in a RuntimeException type. Therefore,
specifying the error type System.Management.Automation.RuntimeException
behaves the same as an unqualified catch block.

Using Traps in a Try Catch

When a terminating error occurs in a try block with a Trap defined within
the try block, even if there is a matching catch block, the Trap statement
takes control.

If a Trap exists at a higher block than the try, and there is no matching
catch block within the current scope, the Trap will take control, even if
any parent scope has a matching catch block.

Accessing exception information

Within a catch block, the current error can be accessed using $_, which
is also known as $PSItem. The object is of type ErrorRecord.

try { NonsenseString }
catch {
  Write-Host "An error occurred:"
  Write-Host $_
}

Running this script returns the following result:

An Error occurred:
The term 'NonsenseString' is not recognized as the name of a cmdlet, function,
script file, or operable program. Check the spelling of the name, or if a path
was included, verify that the path is correct and try again.

There are additional properties that can be accessed, such as ScriptStackTrace,
Exception, and ErrorDetails. For example, if we change the script to the
following:

try { NonsenseString }
catch {
  Write-Host "An error occurred:"
  Write-Host $_.ScriptStackTrace
}

The result will be similar to:

An Error occurred:
at <ScriptBlock>, <No file>: line 2

Freeing resources using finally

To free resources used by a script, add a finally block after the try and
catch blocks. The finally block statements run regardless of whether the
try block encounters a terminating error. PowerShell runs the finally block
before the script terminates or before the current block goes out of scope.

A finally block runs even if you use CTRL+C to stop the
script. A finally block also runs if an Exit keyword stops the script from
within a catch block.

See also

  • about_Break
  • about_Continue
  • about_Scopes
  • about_Throw
  • about_Trap

Вообще я редко вижу смысл в том чтобы отлавливать ошибки в скриптах, но недавно ко мне попалась задача, где необходимо было обработать ошибки в скрипте PowerShell. Дело в том что данный скрипт использовался как часть работы System Center Orchestrator. Для этого я использовал Try/Catch/Finaly . Но все по порядку.

Немного про ошибки

Ошибки можно условно разделить на две больших категории.

  1. Прерывающие
  2. Не прерывающие

Первые завершают выполнение конвейера с ошибкой. Т.е. дальнейшие команды в конвейере не выполняются. Например, вы не правильно указали имя команды. Вторая категория лишь генерирует ошибку, но конвейер продолжает выполняться далее. Например, вы запросили содержимое не существующего каталога.

В любом случае всю информацию о всех ошибках можно поглядеть в переменной $error. Последняя ошибка идет с индексом 0, т.е. $error[0] — покажет последнюю ошибку. А $error[0].Exception описание последней ошибки.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

PS C:> Get-Command NoCommand,Dir

Get-Command : Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Пров

ерьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытку.

строка:1 знак:1

+ Get-Command NoCommand,Dir

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (NoCommand:String) [Get-Command], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

CommandType     Name                                               ModuleName

                                                   

Alias           dir -> Get-ChildItem

PS C:> $error[0]

Get-Command : Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Пров

ерьте правильность написания имени, а также наличие и правильность пути, после чего повторите попытку.

строка:1 знак:1

+ Get-Command NoCommand,Dir

+ ~~~~~~~~~~~~~~~~~~~~~~~~~

    + CategoryInfo          : ObjectNotFound: (NoCommand:String) [Get-Command], CommandNotFoundException

    + FullyQualifiedErrorId : CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

PS C:> $error[0].Exception

Имя «NoCommand» не распознано как имя командлета, функции, файла сценария или выполняемой программы. Проверьте правильн

ость написания имени, а также наличие и правильность пути, после чего повторите попытку.

Этот же пример, но в виде рисунка для наглядности.

Переменная Error

Для того чтобы выяснить была ли в какой-то части кода ошибка необходимо использовать Try. Это помогает избавиться от неожиданного и некорректного завершение вашего скрипта. Позволяя так же корректно завершить его работу.

Синтаксис выглядит в общем случае так.

Try

{

  часть кода в которой ищем ошибку

}

Catch

{

[тип ошибки, которую ищем] код,

     который будет выполнен когда ошибка будет найдена

}

Finally

{

код, который будет выполнен в любом случае

}

Однако использование Finally и определение типа ошибки — опционально и может не использоваться.

Для проверки напишем вот такой код где используем Try в PowerShell для того чтобы обработать ошибку деления на ноль и вывести информацию об ошибке.

try

{

[float](4/0)

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Как видно я произвожу деление на ноль в блоке try, т.е. совершаю прерывающую ошибку. Только прерывающие ошибку будут отловлены. А далее в блоке catch произвожу уже необходимые отладочные действия, т.е. произвожу обработку ошибки.. В моей исходной задаче я в данном блоке заносил информацию об ошибках в специальный лог файл, но давайте попробуем запустить мой данный пример.

PS C:> .test.ps1

Error!!!

System.Management.Automation.RuntimeException: Попытка деления на нуль. -> System.DivideByZeroException: Попытка делен

ия на нуль.

   Конец трассировки внутреннего стека исключений

   в System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exce

ption)

   в System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)

   в System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

   в System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)

Увы в блоке try в PowerShell должна присутствовать прерывающая ошибка.

Преобразуем не прерывающую ошибку в прерывающую

Существует общий параметр для всех командлетов в PowerShell -ErrorAction. Данный параметр может принимать четыре значения

  • Continue — выводит ошибку и продолжает выполнение
  • SilentlyContinue — не выводит ошибку и продолжает выполнение
  • Stop — завершает выполнение
  • Inquire — спрашивает у пользователя как поступить

В нашем случае подходит действие stop. Если использовать параметр со значением -ErrorAction Stop, то при возникновении ошибки при выполнении команды, данная ошибка прерывает выполнение команды. Ниже пример скрипта, использующего -ErrorAction Stop.

try

{

  Dir NoFolder -ErrorAction Stop

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Ниже результат выполнения данного скрипта

PS C:> .test.ps1

Error!!!

System.Management.Automation.ItemNotFoundException: Не удается найти путь «C:NoFolder»,

так как он не существует.

   в System.Management.Automation.SessionStateInternal.GetChildItems(String path, Boolean recurse, C

mdletProviderContext context)

   в Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()

В моей исходной задаче try в PowerShell необходимо было использовать для всех команд в скрипте. Поскольку обработка ошибки была общей для любой ошибки в скрипте весь скрипт можно поместить в один Try, конечно это не совсем правильно, но зато просто. Чтобы каждый раз не писать -ErrorAction Stop. Можно воспользоваться переменной $ErrorActionPreference, которая имеет те же значения и сходна по действию, однако распространяет свое действие на все командлеты в скрипте.

$ErrorActionPreference = «stop»

try

{

  Dir Folder

  Get-Process -ComputerName TestPC

}

catch

{

  Write-Host «Error!!!»

  Write-Host $error[0].Exception

}

Вместо заключения

Конечно, по началу вы мало будете задумываться об поиске ошибок, используя множество условных конструкций вы их минимизируете. Однако использование try в PowerShell позволит минимизировать случаи неожиданного завершения скрипта.

  • Remove From My Forums
  • Question

  • Sigh.  I have searched for 3 hours to the answer for my question.  I’m new to scripting, so perhaps this is the problem in my not finding a solution.

    In a nutshell, I simply want to gracefully trap command line usage of a script.  I want to have my script accept a parameter (ie. a value) and a switch.

    Example:  <script> -path <path> -set

    The problem is that i cannot trap incorrect usage.  I would prefer <path> to be position one, and -switch to be position 2 of the parameters passed to the script.  I have not tried this «outside» of PS v2.0 ISE (ie. Powershell.exe). 
    Of course, I would love it to work in both environments.

    I KNOW that the ISE will prompt for missing mandatory parameters.  Great.  But incorrectly specified parameters causes Powershell ISE to «bomb-out».  That is, displaying error messages to an uninformed user whom views it as unintelligible.

    Example of incorrect usage:  <script> -pat <path> -set

    Again, I would LOVE to trap this, and display correct USAGE to the screen.  Unfortunately, this produces a Powershell error message which has proved unintelligible to «simple» users.

    Perhaps I must accept that this is not possible in Powershell v2.0.  I simply want to program my script to CATCH this error and take the desired action.

    HELP!!!  To the knowledgeable and generous Scripting Professionals.


    If the directions say go straight, but I turn left, then right: Will I still get there?

    • Changed type

      Monday, January 20, 2014 1:15 AM
      User asked a question

Answers

  • You cannot catch parameter errors at the command line.  PowerShell throws those errors before it enter the script.

    YOU can provide default values and check the parameter collection to see if the parameters were provided.  This has been the approach from PowersShell V1.

    The advanced checks of parameters are only intended to be used calling a CmdLet from inside of PowerShell.

    See the PowerShellTeeam blog for more examples of how to manage commandline parameters.


    ¯_(ツ)_/¯

    • Marked as answer by
      PQSC.Programmer
      Monday, January 20, 2014 11:24 AM

  • Voila!!  A more thorough research on my part found the answer to my own question.  Thanks for the tips, jrv.

    [CmdletBinding()]
    Param(
        [String]$Path = «Param not used»,
        [switch]$Set,
        [parameter(ValueFromRemainingArguments=$true)]
        [String[]]$RemainingArguments
    )

    This allows for ANY and ALL parameters to be passed, regardless of the correctness of the parameter name used.

    In other words:  <script> -xxyy vvv

    will still pass-thru and I can trap via initialized defaults.


    If the directions say go straight, but I turn left, then right: Will I still get there?

    • Marked as answer by
      PQSC.Programmer
      Monday, January 20, 2014 2:32 PM

Аналог «<» для PowerShell

В Linux можно использовать следующую конструкцию:

КОМАНДА1 < ФАЙЛ1

В этом случае КОМАНДА1 будет выполнена с ФАЙЛ1 в качестве источника ввода вместо клавиатуры, которая является обычным источником стандартного ввода.

Оператор < соответствует использованию | для передачи в программу стандартного ввода. Например, следующие команды являются идентичными:

КОМАНДА1 < ФАЙЛ1
cat ФАЙЛ1 | КОМАНДА1

Попытка использовать этой конструкции в PowerShell вызывает ошибку.

Например команда

mysql -uroot < C:UsersMiAlDownloadsall-databases.sql

завершиться следующим сообщением:

ParserError:
Line |
   1 |  mysql -uroot < C:UsersMiAlDownloadsall-databases.sql
     |               ~
     | The '<' operator is reserved for future use.

Аналогичная ошибка в PowerShell 5 (на русском):

строка:1 знак:14
+ mysql -uroot < C:UsersMiAlDownloadsall-databases.sql
+              ~
Оператор "<" зарезервирован для использования в будущем.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : RedirectionNotSupported

Вместо синтаксиса

КОМАНДА1 < ФАЙЛ1

нужно использовать следующую конструкцию:

Get-Content ФАЙЛ1 | КОМАНДА1

Командлет Get-Content прочитает содержимое ФАЙЛА1. Символ «|» (труба, конвейер) означает передать содержимое КОМАНДЕ1.

Таким образом, вместо

mysql -uroot < C:UsersMiAlDownloadsall-databases.sql

нужно использовать следующую команду:

Get-Content C:UsersMiAlDownloadsall-databases.sql | .mysql -uroot

Смотрите также: Как в PowerShell прочитать содержимое файла (аналог cat)

Аналог «./program < input.txt > output.txt» для PowerShell

Рассмотрим конструкцию

./program < input.txt > output.txt

Она означает, что содержимое файла input.txt передаётся на стандартный ввод команды program, а результат выполнения program сохраняется в файл output.txt. Но показанная выше команда не будет работать.

Аналогом рассмотренной конструкции, который будет работать в PowerShell, является следующая команда:

Get-Content INPUT.txt | ./program > output.txt

Либо можно использовать вариант в стиле PowerShell:

Get-Content INPUT.txt | ./program | Out-File output.txt

Смотрите также: Как в PowerShell сохранить вывод в файл (аналоги > и »)

Связанные статьи:

  • Решение проблем с кодировкой вывода в PowerShell и сторонних утилитах, запущенных в PowerShell (81.6%)
  • Как в PowerShell сохранить вывод в файл (аналоги > и >>) (77.9%)
  • Как в PowerShell прочитать содержимое файла (аналог cat) (68.4%)
  • Аналог echo в PowerShell (53.4%)
  • Как в PowerShell менять набор выводимых по умолчанию данных (53.4%)
  • Устранение неполадок, связанных с медленной обработкой GPO и снижением скорости входа в систему (RANDOM — 3.7%)

Рекомендуется Вам:

pEntity

238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

1

02.10.2018, 13:00. Показов 11211. Ответов 32

Метки нет (Все метки)


Студворк — интернет-сервис помощи студентам

Здравствуйте. Поздравьте меня. Я сам, вручную, написал свой первый работающий сценарий

Позвольте задавать вопросы.

1. Синтаксис. Так работает:

PowerShell
1
2
3
$Files = Get-ChildItem -Path C:
 
 FOREACH ($File In $Files) { $File.FullName }

А так уже нет:

PowerShell
1
2
3
4
5
6
$Files = Get-ChildItem -Path C:
 
 FOREACH ($File In $Files) 
 { 
    $File.FullName 
 }
PowerShell
1
2
3
4
5
6
7
PS C:WindowsSystem32WindowsPowerShellv1.0>  }
строка:1 знак:2
+  }
+  ~
Непредвиденная лексема "}" в выражении или операторе.
    + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : UnexpectedToken

И так то же:

PowerShell
1
2
3
4
5
$Files = Get-ChildItem -Path C:
 
 FOREACH ($File In $Files) { 
    $File.FullName 
 }
PowerShell
1
2
3
4
PS C:WindowsSystem32WindowsPowerShellv1.0>     $File.FullName 
C:Windows10Upgrade
 
PS C:WindowsSystem32WindowsPowerShellv1.0>

Выдало значение только из предпоследней ячейки..

Я могу только в строчку писать сценарии ? Во всех книжках СС++ это считается плохим тоном и советуют к конструкции:

C++
1
2
3
{
      \code
}

Тут же я не могу его использовать ?

Миниатюры

Начало с PowerShell
 



0



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 13:23

2

pEntity, судя по скриншоту вы не весь скрипт выполняете (F5), а только выделенный фрагмент (F8). От этого и ошибки



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

02.10.2018, 13:25

 [ТС]

3

Едрен батон. Получилось. А я даже и не обращал внимания на это) Благодарю.



0



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 13:25

4

Вам же по русски пишут что «строка 1, знак 2» — это фигурная скобка «}». Разве в целом вашем скрипте это так?



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

02.10.2018, 13:27

 [ТС]

5

А я думал с $Files = Get-ChildItem -Path C:



0



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 13:30

6

Цитата
Сообщение от pEntity
Посмотреть сообщение

А я думал с $Files = Get-ChildItem -Path C:

И где в этой строке — Непредвиденная лексема «}»? Тогда уж, «строка:1, знак:2» — это «F»



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

02.10.2018, 13:33

 [ТС]

7

KDE777, согласен ) Для теста хочу написать такой сценарий:

От 1января до сегодня пройтись по всем пользавокам АД и выявить учетки, которые были созданы в этом интервале времени и записать в файл.

Каков будет алгоритм ?

1. Получить интервал даты.
2. Пройтись циклом по всем пользавокам.
3. Получить дату создания учетки.
4. Если попадает в интервал даты, записать.

Так?



0



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 13:33

8

В PS_ISE можно использовать Ctrl+J и быстро вставлять уже готовые, синтаксически верные конструкции для всяких foreach, switch и т.п.



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

02.10.2018, 13:41

 [ТС]

9

А Ctrl+J как работает? Он там выдает мне десяток командлетов и всё. Или нужно жать на свой, вставленный и он показывает вариации ?



0



KDE777

1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 13:45

10

Цитата
Сообщение от pEntity
Посмотреть сообщение

От 1января до сегодня пройтись по всем пользавокам АД и выявить учетки, которые были созданы в этом интервале времени и записать в файл.
Каков будет алгоритм ?

В данном случае это одна строчка: Get-ADUser | Where-Object | Select-Object | Export-Csv

PowerShell
1
Get-ADUser -Filter * -Properties createTimeStamp | ? createTimeStamp -GE (date '01.01.2018')| sort createTimeStamp | select Name,SamAccountName,createTimeStamp | Export-Csv C:Tempusers.csv -enc UTF8 -NoType -del ';'

Цитата
Сообщение от pEntity
Посмотреть сообщение

А Ctrl+J как работает? Он там выдает мне десяток командлетов и всё. Или нужно жать на командлет и он показывает вариации ?

Ctrl+J и набираете, например две первые буквы «fo», потом стрелкой на нужный вариант и enter



1



pEntity

238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

02.10.2018, 13:48

 [ТС]

11

Дауж, слишком сложно пока. Я мыслю с языка СС++ поэтапно, структурировано. А тут одна строчка )

Я бы начал вообще с типа такого:

PowerShell
1
2
3
4
5
6
7
8
9
$DataStart = '2018-01-01'
$DataEnd = '2018-02-10'
 
$Difference = New-TimeSpan -Start $DataStart -End $DataEnd
 
if( $Difference ) 
{
Мой промежуток времени.   
}



0



774 / 423 / 137

Регистрация: 03.06.2009

Сообщений: 1,223

Записей в блоге: 4

02.10.2018, 13:54

12

pEntity,

Дело в том, что конвеерный принцип — основополагающий в powershell
Изначально, можете писать промежуточными кусками, необязательно все делать в одну строку.
Здесь больше дело вкуса, слишком длинные строки тоже не всегда удобно.

Для начала, лучше почитать справку, и какую-нибудь литературу для новичков с примерами.
Ну и наверное, что-то про объекты NET, тоже не будет лишним



1



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

02.10.2018, 14:00

13

Цитата
Сообщение от pEntity
Посмотреть сообщение

Дауж, слишком сложно пока.

Как раз проще некуда — найти все AD УЗ (Get-ADUser) | из них выбрать, те у которых дата создания больше или равна заданной (Where-Object) | далее отобрать только нужные свойства пользователя (Select-Object) | и всё что получилось сохранить в csv-таблице (Export-Csv)



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

08.10.2018, 08:29

 [ТС]

14

KDE777, можете помочь написать строчку повершела )) Выгрузить список компьютеров, которые не активны более 5 месяцев ? В OU ENT и ENTH

Они лежат в: domain.ru — Клиентские ПК — эти мои OU.



0



KDE777

1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

08.10.2018, 10:12

15

Цитата
Сообщение от pEntity
Посмотреть сообщение

Выгрузить список компьютеров, которые не активны более 5 месяцев ? В OU ENT и ENTH

PowerShell
1
2
3
4
5
6
$OUs = 'OU=ENT,DC=domain,DC=ru','OU=ENTH,DC=domain,DC=ru'
$OutFile = 'c:datareport.csv'
$Months = -5
 
$OUs | %{ Get-ADComputer -SearchBase $_ -Filter * -prop LastLogonDate,CanonicalName | ?{$_.LastLogonDate -le (Get-Date).AddMonths($Months)}
} | select name,CanonicalName,LastLogonDate | Export-Csv $OutFile -NoType -Delimiter ';' -enc UTF8



0



pEntity

238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

08.10.2018, 11:01

 [ТС]

16

KDE777, у меня так OU не находит. Работает так:

PowerShell
1
2
3
PS C:Usersa.mikhalevskii_adm> $date_with_offset= (Get-Date).AddDays(-150)
 
Get-ADComputer  -SearchBase "OU=ЭНТХ,OU=Клиентские ПК,DC=ekoniva,DC=com" -Properties LastLogonDate -Filter {LastLogonDate -lt $date_with_offset } | Sort LastLogonDate | FT Name, LastLogonDate -Autosize

Можно Вас попросить корректный кусок «OU=ЭНТХ,OU=Клиентские ПК,DC=ekoniva,DC=com» вставить в свой код и еще «OU=ЭНТ,OU=Клиентские ПК,DC=ekoniva,DC=com» ?

А так же можно дополнить, чтоб результат вывода пк писало с полным путем, где он лежит ?



0



KDE777

1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

08.10.2018, 11:10

17

Цитата
Сообщение от pEntity
Посмотреть сообщение

у меня так OU не находит

Пример точно рабочий.

Цитата
Сообщение от pEntity
Посмотреть сообщение

Можно Вас попросить корректный кусок «OU=ЭНТХ,OU=Клиентские ПК,DC=ekoniva,DC=com» вставить в свой код и еще «OU=ЭНТ,OU=Клиентские ПК,DC=ekoniva,DC=com» ?

Нужные OU присваиваете переменой $OUs — просто перечисляете в виде DN (DistinguishedName) в кавычках, разделённые запятой.

PowerShell
1
2
3
4
5
6
$OUs = "OU=ЭНТХ,OU=Клиентские ПК,DC=ekoniva,DC=com","OU=ЭНТ,OU=Клиентские ПК,DC=ekoniva,DC=com"
 
$OutFile = 'c:datareport.csv'
$Months = -5
 
$OUs | %{Get-ADComputer -SearchBase $_ -Filter * -prop * | ?{$_.LastLogonDate -le (Date).AddMonths($Months)}} | select name,CanonicalName,LastLogonDate | Export-Csv $OutFile -NoType -Delimiter ';' -enc UTF8

Цитата
Сообщение от pEntity
Посмотреть сообщение

А так же можно дополнить, чтоб результат вывода пк писало с полным путем, где он лежит ?

Это уже было сделано — AD свойство CanonicalName



1



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

08.10.2018, 11:35

 [ТС]

18

Ошибочка:

Export-Csv : Не удается проверить аргумент для параметра «Encoding». Аргумент «UTF» не принадлежит набору «Unicode,UTF7,UTF8,ASCII,UTF32,BigEndianUnicode,Default,OEM», з
аданному атрибутом ValidateSet. Укажите аргумент, который принадлежит данному набору, после чего повторите выполнение команды.
строка:6 знак:203
+ … miter ‘;’ -enc UTF
+ ~~~
+ CategoryInfo : InvalidData: ( [Export-Csv], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.ExportCsvCommand



0



1882 / 1106 / 426

Регистрация: 22.01.2016

Сообщений: 3,050

08.10.2018, 11:39

19

Цитата
Сообщение от pEntity
Посмотреть сообщение

Ошибочка:

Копипастить надо полностью У меня в примере «UTF8», а в сообщение об ошибке «UTF»



0



238 / 227 / 47

Регистрация: 12.12.2012

Сообщений: 1,943

08.10.2018, 11:46

 [ТС]

20

Я понял, я Лошара )

Как всегда, всё ахрененно работает )) Благодарю!

Добавлено через 5 минут
DKE777, а можно Вас теперь попросить, эти ПК, деактивировать и переместить в Клиентские ПК/!Отключенные

?



0



Понравилась статья? Поделить с друзьями:
  • Powershell вывод в консоль ошибок
  • Powershell все ошибки в файл
  • Prinfix ошибка файл не найден обратитесь к администратору
  • Prince of persia warrior within ошибка русский язык ввода
  • Prince of persia the warrior within синтаксическая ошибка