PowerShell 命令加了 -ErrorAction SilentlyContinue 照樣出錯
0 |
PowerShell 有個 -ErrorAction SilentlyContinue
參數可在出錯時隱藏錯誤訊息,並繼續執行命令。
今天發現,ErrorAction 參數不是對所有命令都有效,以下是個簡單測試,用 Get-LocalGroup 跟 Get-ADGroup 查詢本機及 AD 群組,故意輸入不存在的群組名稱會出現錯誤訊息。Get-LocalGroup 可加上 -ErrorAction SilentlyContinue 不顯示錯誤,但 Get-ADGroup 加了卻沒效。
查了文件發現,PowerShell 命令有兩種拋出錯誤的方式,Cmdlet.ThrowTerminatingError(ErrorRecord) 跟 ICommandRuntime.WriteError(ErrorRecord),ErrorAction 參數只對後者有效,前者會中斷程式,但可以用 Try Catch 捕捉例外,所以真要出錯時繼續,用 Try Catch 包起來就對了。
Try {
$Grp = Get-ADGroup 'NoSuchGroup'
}
Catch {
# NOT FOUND OR OTHER ERROR
}
好奇心起,追了一下原始碼找到 Get-ADGroup 是用 ThrowTerminatingError 的證據:
Microsoft.ActiveDirectory.Management.Commands.ADCmdletBase 型別
internal virtual void ProcessError(Exception e)
{
if (e is RuntimeException)
{
throw e;
}
bool flag = true;
this._recordExceptionHandler.ProcessingRecord = this._processingRecord;
if (this != null && ((IADCustomExceptionFiltering)this).ExceptionFilter.FilterException(e, ref flag) && !flag)
{
this.WriteErrorBuffered(this.ConstructErrorRecord(e));
return;
}
base.ThrowTerminatingError(this.ConstructErrorRecord(e));
}
Micrsoft.PowerShell.LocalAccounts.GetLocalGroupCommand 則是用 WriteError:
private void ProcessNames()
{
if (this.Name != null)
{
foreach (string text in this.Name)
{
try
{
if (WildcardPattern.ContainsWildcardCharacters(text))
{
WildcardPattern pattern = new WildcardPattern(text, WildcardOptions.Compiled | WildcardOptions.IgnoreCase);
Sam sam = this.sam;
Predicate<string> pred;
Predicate<string> <>9__0;
if ((pred = <>9__0) == null)
{
pred = (<>9__0 = ((string n) => pattern.IsMatch(n)));
}
using (IEnumerator<LocalGroup> enumerator = sam.GetMatchingLocalGroups(pred).GetEnumerator())
{
while (enumerator.MoveNext())
{
LocalGroup sendToPipeline = enumerator.Current;
base.WriteObject(sendToPipeline);
}
goto IL_A7;
}
}
base.WriteObject(this.sam.GetLocalGroup(text));
IL_A7:;
}
catch (Exception ex)
{
base.WriteError(ex.MakeErrorRecord(null));
}
}
}
}
打完收工。
The reason why ErrorAction SilentlyContinue doesn't work on some cmdlets is because it depends on whether the cmdlets use WriteError or ThrowTerminatingError. For the latter, you need to use a try-catch block.
Comments
Be the first to post a comment