Windows PowerShell中Exchange隐式远程警告捕获与隐藏共存问题求解
在本地部署的Exchange 2016 CU19环境中使用Microsoft ExchangePowerShell,需要同时实现两个需求:
- 捕获警告输出用于日志记录(通常使用
-WarningVariable参数) - 隐藏警告输出(通常使用
-WarningAction参数或3>$null重定向实现)
当前环境为Windows PowerShell 5.1版本,ExchangePowerShell安装在未完整部署Exchange的管理服务器上,无法同时实现上述两个需求,需要解决方案或原理说明。
组合使用-WarningAction与-WarningVariable参数
Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningVariable +warnings -WarningAction SilentlyContinue
警告被隐藏,但$warnings变量为空
Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningVariable +Global:warnings
警告被打印输出,$warnings变量成功赋值
Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningVariable +warnings
警告被打印输出,$warnings变量为空
使用Invoke-Command包裹CmdLet
Invoke-Command { Set-Mailbox -Identity $identity -PrimarySmtpAddress $address } -WarningVariable +warnings -WarningAction SilentlyContinue
警告被打印输出,$warnings变量成功赋值
Invoke-Command { Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningVariable +warnings -WarningAction SilentlyContinue } Invoke-Command { Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningAction SilentlyContinue } -WarningVariable +warnings Invoke-Command { Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningAction SilentlyContinue } -WarningVariable +Global:warnings
警告被隐藏,但$warnings变量为空
Invoke-Command { Set-Mailbox -Identity $identity -PrimarySmtpAddress $address -WarningVariable +warnings } -WarningAction SilentlyContinue
警告被打印输出,$warnings变量为空
使用输出重定向
在上述所有示例中添加*>$null均无效果,警告仍会打印输出。无法理解为什么-WarningAction可以生效,但输出重定向却不起作用。
使用偏好变量
无任何效果
直接操作远程会话设置偏好变量或重写Write-Warning
该方案不可行,因为远程会话处于NoLanguage Mode,仅允许运行Exchange CmdLet。
使用反射重定向consolehost输出
未找到实现方法,公开的解决方案中的签名与类型定义与当前环境不匹配,无法适用。
你遇到的问题是Exchange 2016非完整部署的远程PowerShell代理模块的固有设计导致的:
Exchange代理模块的Cmdlet并没有通过PowerShell标准的警告流输出警告,而是由本地代理代码直接调用当前PowerShell Host的$host.UI.WriteWarning()方法将警告内容打印到控制台。仅当-WarningAction参数未设置为SilentlyContinue时,代理代码才会额外将警告对象写入-WarningVariable指定的变量,因此两个参数无法同时生效。
而输出重定向仅对标准PowerShell流生效,对直接写入Host UI的内容无效,这就是*>$null无法隐藏警告的原因。
在本地PowerShell会话层面临时替换Host的WriteWarning方法,捕获所有写入的警告内容,同时不输出到控制台,该方案不受远程会话NoLanguage模式限制:
# 备份原生WriteWarning实现 $originalWriteWarning = $host.UI.WriteWarning # 初始化警告捕获数组 $capturedWarnings = @() # 替换为自定义实现,仅捕获不输出 $host.UI | Add-Member -MemberType ScriptMethod -Name WriteWarning -Value { param($message) $script:capturedWarnings += $message } -Force # 执行Exchange Cmdlet,无需添加任何警告相关参数 Set-Mailbox -Identity $identity -PrimarySmtpAddress $address # 执行完成后恢复原生实现,避免影响后续其他命令 $host.UI | Add-Member -MemberType ScriptMethod -Name WriteWarning -Value $originalWriteWarning -Force # 所有警告内容已存储在$capturedWarnings数组中,可直接用于日志记录
内容的提问来源于stack exchange,提问作者Gregory_Ott

