tl;dr:
使用2>$null 抑制调用外部程序时的标准错误输出(例如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 是 obsolescent 和 should be avoided going forward(底部链接的答案)。
ISE 通过 PowerShell 的错误流默认显示 stderr 线特别成问题 - 请参阅 this GitHub issue。
幸运的是,常规控制台不会这样做 - 它会将 stderr 行传递到主机(控制台),然后正常打印它们(不是红色),这是正确的做法,因为您通常不能假设所有 stderr 输出都代表 错误(尽管有流的名称)。
对于表现良好的外部程序,您应该只从其进程退出代码中得出成功与失败的结果(如自动 $LASTEXITCODE 变量中所反映的那样[1] ),而不是因为存在 stderr 输出。:退出代码 0 表示成功,任何非零退出代码(通常)表示失败。
至于你的具体情况:
在常规控制台中,$ErrorActionPreference 首选项变量的值不适用于外部程序,例如schtasks.exe,除了 错误 当您还使用 2> 重定向时(从 PowerShell [Core] 7.0 开始) - 请参阅 this GitHub issue;从 PowerShell 7.1.0-preview.6 开始;更正后的行为可作为 experimental feature PSNotApplyErrorActionToStderr 使用。
由于您的schtasks /query /TN 'SOMETASK' 命令用作测试,您可以执行以下操作:
# 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"
# ...
}
在您的具体情况下,更简洁的解决方案是可能的,它依赖于您的 schtasks 命令 (a) 在成功的情况下生成 stdout 输出(如果任务存在)和 (b ) 只有在成功的情况下这样做:
# 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 的隐式到布尔转换将考虑条件$true(请参阅this answer 的底部以了解PowerShell 的 to-Boolean 转换规则)。
请注意,条件只作用于成功输出流的输出 (1),其他流通过,例如 stderr 输出 (@987654349 @) 在这种情况下(正如您所经历的那样)。
2>$null silences stderr 输出,将其重定向到空设备。
1和2分别是PowerShell的成功输出/错误流的数量;对于外部程序,它们分别引用其 stdout(标准输出)和 stderr(标准错误)流 - 请参阅 about_Redirection。
您也可以捕获带有2> 重定向的stderr 输出,如果您想稍后报告它(或需要专门检查它是否有行为不端的程序没有正确使用退出代码)。
-
2> stderr.txt 将标准错误行发送到文件sdterr.txt;不幸的是,目前没有办法在 变量 中捕获 stderr - 请参阅 this suggestion on GitHub,它为此建议使用语法 2>&variableName。
- 正如上述错误所暗示的,您必须确保
$ErrorActionPreference 不设置为'Stop',因为2> 将错误地触发脚本终止错误。李>
-
除了上述错误之外,当前使用 2>(从 v7.0 开始)还有另一个意想不到的副作用:stderr 行也意外地添加到自动 $Error 集合中,就好像它们是错误一样(他们不能假设是)。
[1] 请注意,指示成功与失败的自动 $? 变量作为 布尔值 ($true / $false) 也是 已设置,但不可靠:由于当前 (v7.0) 意外通过 PowerShell 的错误流路由 stderr 输出如果使用 2>& 重定向,则任何 stderr 的存在即使外部程序通过$LASTEXITCODE 报告0 报告总体成功,输出也始终将$? 设置为$false。因此,测试成功的唯一可靠方法是$LASTEXITCODE -eq 0,而不是$?。