tl; dr :
Используйте 2>$null
для подавления вывода stderr при вызове внешней программы (например, schtasksk.exe
)
- Чтобы обойти ошибку, присутствующую, по крайней мере, до PowerShell [Core] 7.0 (см. Ниже), убедитесь, что
$ErrorActionPreferece
не , а не установлено 'Stop'
.
# Execute with stderr silenced.
# Rely on the presence of stdout output in the success case only
# to make the conditional true.
if (schtasks /query /TN 'SOMETASK' 2>$null) { # success, task exists
"Processing removal of scheduled task`n"
# ...
}
Для справочной информации и более общих случаев использования читайте дальше.
Учитывая, как строка из потока stderr внешней программы проявляется, как показано в вашем вопросе, это звучит как вы используете свой код в PowerShell ISE , от которого я предлагаю отказаться от: PowerShell ISE устарел и следует избегать в дальнейшем (нижняя часть связанного ответа).
То, что поверхность линий stderr ISE появляется через поток ошибок PowerShell по умолчанию , особенно проблематично c - см. эту проблему GitHub .
Обычная консоль этого не делает, удача ately - он передает строки stderr через хост (консоль) и печатает их обычно (не красным цветом), что является правильным решением, учитывая, что вы обычно не можете предполагать что все выходные данные stderr представляют ошибок (несмотря на имя потока).
В случае с хорошо работающими внешними программами вы должны только когда-либо получать успех или неудачу из их процесса код выхода (как отражено в автоматической переменной c $LASTEXITCODE
[1] ), а не из-за наличия вывода stderr. : код выхода 0
указывает на успех, любой ненулевой код выхода (обычно) указывает на ошибку.
Что касается заданного вами c case:
В обычной консоли значение предпочтительной переменной $ErrorActionPreference
не применяется к внешним программам , таким как schtasks.exe
, кроме как в форме ошибки , когда вы также используете перенаправление 2>
(начиная с PowerShell [Core] 7.0) - см. этот выпуск GitHub .
Поскольку ваша schtasks /query /TN 'SOMETASK'
команда работает как test , вы можете сделать следующее:
# Execute with all streams silenced (both stdout and stderr, in this case).
# schtask.exe will indicate the non-existence of the specified task
# with exit code 1
schtasks /query /TN 'SOMETASK' *>$null
if ($LASTEXITCODE -eq 0) { # success, task exists
"Processing removal of scheduled task`n"
# ...
}
# You can also squeeze it into a single conditional, using
# $(...), the subexpression operator.
if (0 -eq $(schtasks /query /TN 'SOMETASK' *>$null; $LASTEXITCODE)) { # success, task exists
"Processing removal of scheduled task`n"
# ...
}
В вашем конкретном случае c возможно более краткое решение, которое опирается на Ваша schtasks
команда (a) выдает stdout выходные данные в случае успеха (если задача существует) и (b) only делает так в случае успеха:
# Execute with stderr silenced.
# Rely on the presence of stdout output in the success case only
# to make the conditional true.
if (schtasks /query /TN 'SOMETASK' 2>$null) { # success, task exists
"Processing removal of scheduled task`n"
# ...
}
Если schtasks.exe
производит вывод stdout (который сопоставляется с потоком успешных выходных данных PowerShell, 1
), неявное преобразование PowerShell в Boolean будет считать условным $true
(см. Нижний раздел этот ответ для обзора правил преобразования PowerShell в Boolean).
Обратите внимание, что условие всегда действует только на выходной поток success (1
), другие потоки проходят через , например, вывод stderr (2
) в этом случае (как вы уже видели).
2>$null
заставляет замолчать вывод stderr , перенаправляя его на нулевое устройство.
1
и 2
- номера потоков вывода / ошибок PowerShell соответственно; в случае внешних программ они ссылаются на свои потоки stdout (стандартный вывод) и stderr (стандартная ошибка) соответственно - см. about_Redirection
.
Вы также можете захватить вывод stderr с перенаправлением 2>
, если вы хотите сообщить об этом позже (или вам нужно проверить это специально для плохой программы, которая не использует коды выхода должным образом) ,
2> stderr.txt
отправляет строки stderr в файл sdterr.txt
; к сожалению, в настоящее время нет способа перехватить stderr в переменной - см. это предложение для GitHub , которое предлагает синтаксис 2>&variableName
для этого.
- Как следует из вышеупомянутой ошибки, вы должны убедиться, что
$ErrorActionPreference
не не установлен на 'Stop'
, потому что 2>
будет по ошибке вызвать ошибку завершения скрипта.
Помимо вышеупомянутой ошибки, использование 2>
в настоящее время (начиная с v7.0) имеет еще один неожиданный побочный эффект: строки stderr неожиданно также добавляются в коллекцию automati c $Error
, как будто это ошибки (которых они не могут считать).
- Причина обеих проблем root заключается в том, что строки stderr неожиданно маршрутизируются через поток ошибок PowerShell , даже если нет веских причин для этого - см. этот выпуск GitHub .
[1] Обратите внимание, что автоматы c $?
переменная, которая указывает успех или неудачу как логическое значение ($true
/ $false
), также установлена, но ненадежно, поэтому : поскольку вывод stderr в настоящее время (v7.0) неожиданно маршрутизируется через поток ошибок PowerShell , если перенаправлен с 2>&
, присутствие любого вывода stderr неизменно устанавливает $?
в $false
, даже если внешняя программа сообщает об общем успехе через $LASTEXITCODE
, сообщая 0
. Таким образом, единственный надежный способ проверки успеха - это $LASTEXITCODE -eq 0
, а не $?
.