You’re way off track here. Silencing errors is almost never a good idea, and manually checking $?
explicitly after every single command is enormously cumbersome and easy to forget to do (error prone). Don’t set yourself up to easily make a mistake. If you’re getting lots and lots of red, that means your script kept going when it should have stopped instead. It can no longer do useful work if most of its commands are failing. Continuing a program when it and the system are in an unknown state will have unknown consequences; you could easily leave the system in a corrupt state.
The correct solution is to stop the algorithm on the first error. This principle is called «fail fast,» and PowerShell has a built in mechanism to enable that behavior. It is a setting called the error preference, and setting it to the highest level will make your script (and the child scopes if they don’t override it) behave this way:
$ErrorActionPreference = 'Stop'
This will produce a nice, big error message for your consumption and prevent the following commands from executing the first time something goes wrong, without having to check $?
every single time you run a command. This makes the code vastly simpler and more reliable. I put it at the top of every single script I ever write, and you almost certainly should as well.
In the rare cases where you can be absolutely certain that allowing the script to continue makes sense, you can use one of two mechanisms:
catch
: This is the better and more flexible mechanism. You can wrap atry
/catch
block around multiple commands, allowing the first error to stop the sequence and jump into the handler where you can log it and then otherwise recover from it or rethrow it to bubble the error up even further. You can also limit thecatch
to specific errors, meaning that it will only be invoked in specific situations you anticipated rather than any error. (For example, failing to create a file because it already exists warrants a different response than a security failure.)- The common
-ErrorAction
parameter: This parameter changes the error handling for one single function call, but you cannot limit it to specific types of errors. You should only use this if you can be certain that the script can continue on any error, not just the ones you can anticipate.
In your case, you probably want one big try
/catch
block around your entire program. Then your process will stop on the first error and the catch
block can log it before exiting. This will remove a lot of duplicate code from your program in addition to cleaning up your log file and terminal output and making your program less likely to cause problems.
Do note that this doesn’t handle the case when external executables fail (exit code nonzero, conventionally), so you do still need to check $LASTEXITCODE
if you invoke any. Despite this limitation, the setting still saves a lot of code and effort.
Additional reliability
You might also want to consider using strict mode:
Set-StrictMode -Version Latest
This prevents PowerShell from silently proceeding when you use a non-existent variable and in other weird situations. (See the -Version
parameter for details about what it restricts.)
Combining these two settings makes PowerShell much more of fail-fast language, which makes programming in it vastly easier.
- Remove From My Forums
-
Question
-
Hello. My script generates many strings to ouput making it unreadable.
Is there any way to hide output but leave error messages and variables?
Answers
-
Hi,
Based on my research, I recommend adding [void] for the lines which display outputs, and it won’t hide the error. For example:
[void] (New-item -Path C:Test -ItemType Directory)If you need further help, please feel free to let us know.
Best Regards,
Albert
Please remember to mark the replies as an answers if they help.
If you have feedback for TechNet Subscriber Support, contact
tnmff@microsoft.com-
Edited by
Friday, January 19, 2018 7:51 AM
-
Marked as answer by
pawellrus
Thursday, January 25, 2018 11:14 AM
-
Edited by
I am trying to see if a process is running on multiple servers and then format it into a table.
get-process -ComputerName server1,server2,server3 -name explorer | Select-Object processname,machinename
Thats the easy part — When the process does not exist or if the server is unavailable, powershell outputs a big ugly error, messes up the the table and doesn’t continue. Example
Get-Process : Couldn't connect to remote machine.At line:1 char:12 + get-process <<<< -ComputerName server1,server2,server3 -name explorer | format-table processname,machinename
+ CategoryInfo : NotSpecified: (:) [Get-Process], InvalidOperatio nException + FullyQualifiedErrorId : System.InvalidOperationException,Microsoft.Power Shell.Commands.GetProcessCommand
How do I get around this? If the I would still like to get notified if the process isn’t available or Running.
I have the following PowerShell script. It picks up the NetBIOS name of computers within a given IP address. I’m using a pipe so as to dump the results into a text file. The problem is that if an IP address is not available, a warning is printed.
This is the PowerShell script:
function Get-ComputerNameByIP {
param( $IPAddress = $null )
BEGIN {
$prefBackup = $WarningPreference
$WarningPreference = 'SilentlyContinue'
}
PROCESS {
if ($IPAddress -and $_) {
throw ‘Please use either pipeline or input parameter’
break
} elseif ($IPAddress) {
([System.Net.Dns]::GetHostbyAddress($IPAddress))
}
} else {
$IPAddress = Read-Host “Please supply the IP Address”
[System.Net.Dns]::GetHostbyAddress($IPAddress)
}
}
END {
$WarningPreference = $prefBackup
}
This is the error message I wish to ignore:
WARNING: The requested name is valid, but no data of the requested type was found
asked Jun 8, 2015 at 13:02
1
You can use common parameter -WarningAction:SilentlyContinue
with the command that generates warning. It’s better than separately overriding $WarningPreference
before executing the command and reverting it back afterwards as was suggested above — this parameter basically does that for you.
The WarningAction parameter overrides the value of the
$WarningPreference
variable for the current command. Because the default value of the$WarningPreference
variable is Continue, warnings are displayed and execution continues unless you use the WarningAction parameter.
See more here.
answered Jun 18, 2020 at 22:51
miguellomiguello
5145 silver badges14 bronze badges
You want to suppress warnings, not errors. Warnings can be silenced completely by setting the $WarningPreference
variable to SilentlyContinue
:
PS C:> Write-Warning 'foo'
WARNING: foo
PS C:> $prefBackup = $WarningPreference
PS C:> $WarningPreference = 'SilentlyContinue'
PS C:> Write-Warning 'foo'
PS C:> $WarningPreference = $prefBackup
PS C:> Write-Warning 'foo'
WARNING: foo
The setting pertains to the current scope, so if you want to suppress all warnings for your function you’d simply set the preference at the beginning of your function:
function Get-ComputerNameByIP {
param( $IPAddress = $null )
BEGIN {
$WarningPreference = 'SilentlyContinue'
}
PROCESS {
if ($IPAddress -and $_) {
throw ‘Please use either pipeline or input parameter’
break
} elseif ($IPAddress) {
[System.Net.Dns]::GetHostbyAddress($IPAddress)
}
[System.Net.Dns]::GetHostbyAddress($_)
} else {
$IPAddress = Read-Host "Please supply the IP Address"
[System.Net.Dns]::GetHostbyAddress($IPAddress)
}
}
END {}
}
If you want warnings suppressed for specific statements only, a simpler way is to redirect the warning output stream to $null
:
[System.Net.Dns]::GetHostbyAddress($IPAddress) 3>$null
Warning stream redirection is only available in PowerShell v3 and newer, though.
answered Jun 8, 2015 at 13:56
Ansgar WiechersAnsgar Wiechers
191k24 gold badges246 silver badges321 bronze badges
3
$ErrorActionPreference = 'SilentlyContinue'
This global var controls error output of those commands that provide intermittent (non-terminating) errors and warnings. Your error is of this kind, so set preference to silently continue to suppress these warnings.
JohnB
17.8k16 gold badges98 silver badges110 bronze badges
answered Jun 8, 2015 at 13:06
VesperVesper
18.6k6 gold badges37 silver badges60 bronze badges
8
You could use a try/catch block for something like this. Consider the following example using a proper formed IP address but had no associated record.
try{
[System.Net.Dns]::GetHostbyAddress("127.0.0.56")
} Catch [System.Management.Automation.MethodInvocationException]{
Write-Host "Nothing Record Found"
}
When I tested this the error you were seeing was being caught as [System.Management.Automation.MethodInvocationException]
so I checked for that specific error type. Based on it’s name I’m sure there are other reasons for it to be called. It is possible to just omit that part altogether and it will catch all errors. Since you account for some other possibilities maybe you don’t need it.
If that was a concern you could check the text of the $_.Exception.InnerException
to see if it matches the error as well. In the above case it contains the text «The requested name is valid, but no data of the requested type was found
«.
This might be wrong because I am curious as to why your error is prefixed with «WARNING» where mine is not. A little more research on both our parts might be needed.
answered Jun 8, 2015 at 13:32
MattMatt
44.6k8 gold badges77 silver badges118 bronze badges
1
You can trap the error and force PowerShell to do nothing with it, kind of like a Try/Catch but global for the whole script:
TRAP {"" ;continue}
[System.Net.Dns]::GetHostbyAddress($IPAddress)
answered Jun 8, 2015 at 13:59
Rafał SaltarskiRafał Saltarski
7071 gold badge8 silver badges20 bronze badges
Для начала определимся, что такое обработка ошибок вообще. В общем случае ошибка — это поведение программы или скрипта, отличное от запланированного. Совсем избежать ошибок не очень возможно, поэтому надо предвидеть, где они могут возникнуть и писать код так, чтобы при возникновении ошибки можно было перехватить ее, проанализировать и определить дальнейшее поведение скрипта. Именно это обычно и подразумевается под обработкой ошибок.
В PowerShell ошибки делятся на два типа: прерывающие (Terminating) и непрерывающие (Non-Terminating). Как следует из названия, непрерывающие ошибки позволяют продолжить выполнение команды, тогда как при возникновении прерывающей ошибки дальнейшее продолжение выполнения команды невозможно. К примеру, у нас есть файл со списком служб, которые необходимо перезапустить следующей командой:
Get-Content -Path C:Filesservices.txt | Restart-Service
Предположим, что перезапуск одной из перечисленных служб по какой либо причине невозможен. Тем не менее можно продолжать выполнение задачи, поскольку остальные службы доступны и их можно перезапустить. Это пример непрерывающей ошибки.
А теперь представьте, что у нас нет прав на открытие этого файла, и соответственно прочитать список служб мы не можем. В этой ситуации продолжение работы невозможно, т.е. это прерывающая ошибка.
PowerShell позволяет обрабатывать оба эти типа ошибок. Большинство ошибок в PowerShell непрерывающие, и сегодня речь пойдет о том, как их обрабатывать.
Обработка непрерывающих ошибок
Для получения ошибки возьмем службу с ″оригинальным″ названием Service. Поскольку службы этой на сервере нет, то обращение к ней стабильно будет генерировать ошибку. Запросим данные о нескольких службах командой:
Get-Service service,spooler
Как видно из примера, PowerShell не нашел службу Service, о чем выдал ошибку и затем продолжил выполнение команды. Давайте разберемся, почему команда повела себя именно так и как это поведение изменить.
За поведение команды при возникновении ошибки отвечает параметр ErrorAction, который может принимать одно из пяти значений:
• Continue;
• SilentlyContinue;
• Stop;
• Ignore;
• Inquire.
Примечание. Еще у ErrorAction может быть значение Suspend. Но это значение может применяться только к рабочим процессам (workflows), поэтому в рамках данной статьи речь о нем не пойдет.
Значение Continue означает, что при возникновении ошибки информация об этом будет выведена на экран (отправлена в поток вывода Error) и добавлена в автоматическую переменную $Error, после чего выполнение команды будет продолжено. Надо сказать, что Continue — это действие, определенное в сеансе по умолчанию, поэтому его можно не указывать явно.
При значении SilentlyContinue информация об ошибке добавляется в переменную $Error, но не выводится на экран. При этом команда продолжает выполняться дальше, также как и в предыдущем случае.
Значение Stop останавливает дальнейшее выполнение команды при возникновении ошибки. И наоборот, значение Ignore полностью игнорирует возникновение ошибки, при этом не выводится сообщение на экран и не производится запись в $Error. Это значение появилось в PowerShell 3.0.
Inquire — наиболее интересное значение ErrorAction. Если задать это значение, то при возникновении ошибки предлагается на выбор несколько действий: продолжить (Yes), продолжить не смотря на эту и все последующие ошибки (Yes to All), остановить (Halt) или приостановить (Suspend) выполнение команды.
Самый необычный эффект дает Suspend, при выборе которого открывается параллельный сеанс (Nested Namespace). Определить его можно по значку >>. Nested Namespace представляет из себя дочерний процесс, в котором можно полноценно работать — выполнять команды, запускать скрипты и т.п. Этот режим удобно использовать для отладки скриптов, например можно по быстрому исправить причину ошибки и продолжить выполнение. Для выхода из Nested Namespace достаточно набрать exit и выбрать необходимое действие.
Примечание. У параметра 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 нужное значение.
Все ошибки PowerShell сохраняет в автоматическую переменную $Error. Это глобальная переменная, которая представляет из себя массив строк, содержащий записи обо всех ошибках в текущем сеансе. Каждая новая ошибка добавляется в начало массива, соответственно для просмотра последней ошибки надо обратиться к самому первому элементу массива $Error[0].
$Error имеет свои свойства и методы, которые можно использовать. Например, посмотреть общее количество ошибок в текущем сеансе можно командой $Error.Count, а очистить список — командой $Error.Clear().
Переменная $Error не безразмерна, по умолчанию она хранит не более 256 ошибок. При превышении этого количества наиболее старые ошибки будут затираться. При необходимости количество записей в переменной $Error можно увеличить, изменив значение другой переменной $MaximumErrorCount.
Кроме $Error для хранения ошибок допускается задавать собственные переменные. Сделать это можно с помощью параметра ErrorVariable, например так:
Get-Service service,spooler -ErrorAction SilentlyContinue -ErrorVariable var
Обратите внимание, что имя переменной в команде задается без знака $, хотя в дальнейшем к ней обращаемся как к обычной переменной $var.
В отличие от глобальной переменной $Error заданные вручную переменные хранят только ошибки той команды, в которой они определены. Кроме того, по умолчанию эти переменные каждый раз перезаписываются и поэтому хранят только последнюю ошибку. Если вы хотите, чтобы новые ошибки добавлялись в переменную, не перезаписывая ее содержимое, то перед именем переменной надо поставить знак +, например +var.
Пока все, а в следующей части пойдет о способах обработки прерывающих ошибок.