PowerShell:如何在try...catch块正确抛出数组适配日志函数
问题:PowerShell日志函数处理catch块数组输入异常
我需要日志函数支持三种输入场景:单个对象、数组对象作为命名参数、管道输入。当前函数在正常管道传递数组时工作正常,但在try块抛出数组后,catch块中将$_传入函数时,数组会被拼接成单个字符串输出。
原函数代码
function log { param ( [Parameter(Mandatory,ValueFromPipeline)][object[]]$msg, [ValidateSet("FATAL", "ERROR", "WARN", "INFO", "DEBUG")] [string]$level = "INFO", [switch]$quiet ) process { $msg | ForEach-Object { $out = "[$((Get-Date).ToUniversalTime().ToString("u"))] $($level.ToUpper()) $_" if ($quiet) { $out | Out-File -FilePath $logpath -Append } else { $out | Tee-Object -FilePath $logpath -Append } } } }
测试代码
try { $a = @("Test", "Test2") $a | log throw $a } catch { $_ | log exit 1 }
实际输出
[2023-09-19 20:04:46Z] INFO Test [2023-09-19 20:04:48Z] INFO Test2 [2023-09-19 20:04:50Z] INFO Test Test2
问题原因
PowerShell的catch块中,$_是ErrorRecord对象,而非直接抛出的原始数组。当你抛出非Exception类型的对象时,PowerShell会自动将其包装进RuntimeException,原始数组会被转换为字符串作为ErrorRecord的消息内容,所以直接传入$_时,函数处理的是ErrorRecord的字符串表示,而非原始数组。
解决方法
方法1:在catch块中传入原始对象
修改catch块,通过$_.TargetObject获取抛出的原始数组:
catch { $_.TargetObject | log exit 1 }
方法2:优化日志函数自动处理ErrorRecord
修改函数的process块,自动识别ErrorRecord并提取原始对象,这样调用方无需修改代码:
function log { param ( [Parameter(Mandatory,ValueFromPipeline)][object[]]$msg, [ValidateSet("FATAL", "ERROR", "WARN", "INFO", "DEBUG")] [string]$level = "INFO", [switch]$quiet ) process { # 处理ErrorRecord,提取原始抛出对象 $processedItems = $msg | ForEach-Object { if ($_ -is [System.Management.Automation.ErrorRecord]) { $_.TargetObject } else { $_ } } $processedItems | ForEach-Object { $out = "[$((Get-Date).ToUniversalTime().ToString("u"))] $($level.ToUpper()) $_" if ($quiet) { $out | Out-File -FilePath $logpath -Append } else { $out | Tee-Object -FilePath $logpath -Append } } } }
两种方法都能让catch块中的数组被正确拆分输出,和正常管道输入的结果一致。
内容的提问来源于stack exchange,提问作者Appleoddity
相关产品推荐
相关产品推荐

