如何获取调用PowerShell函数时使用的原始表达式?
PowerShell 函数获取完整原始调用表达式解决方案
已知局限说明
$MyInvocation.Line仅能返回调用表达式的第一行内容,无法识别带换行转义符、未闭合括号/引号的多行调用场景。
实现思路
根据调用来源的不同分别处理:
- 调用来自脚本文件时:通过调用栈拿到脚本路径和表达式起始行号,逐行向后扫描判断括号、引号、换行转义符的闭合状态,直到完整捕获整个表达式
- 调用来自交互式终端时:直接读取最后一条命令历史记录,即可拿到完整的输入内容
完整实现代码
function Get-OriginalCallExpression { $invocationContext = $MyInvocation $callerStackFrame = (Get-PSCallStack)[1] # 处理脚本文件内调用场景 if ($callerStackFrame.ScriptName) { $scriptAllContent = Get-Content -Path $callerStackFrame.ScriptName -Raw $scriptLineArr = $scriptAllContent -split "`r?`n" $startLineIndex = $callerStackFrame.ScriptLineNumber - 1 $currentLineIndex = $startLineIndex $curlyBracketCount = 0 $parenthesesCount = 0 $quoteStatus = 0 # 0:无引号 1:双引号 2:单引号 $expressionLineList = do { $currentLine = $scriptLineArr[$currentLineIndex] # 逐字符扫描判断语法闭合状态 for ($charIdx = 0; $charIdx -lt $currentLine.Length; $charIdx++) { $char = $currentLine[$charIdx] switch ($char) { '"' { if ($quoteStatus -ne 2) { $quoteStatus = $quoteStatus -eq 1 ? 0 : 1 } } "'" { if ($quoteStatus -ne 1) { $quoteStatus = $quoteStatus -eq 2 ? 0 : 2 } } '(' { if ($quoteStatus -eq 0) { $parenthesesCount++ } } ')' { if ($quoteStatus -eq 0) { $parenthesesCount-- } } '{' { if ($quoteStatus -eq 0) { $curlyBracketCount++ } } '}' { if ($quoteStatus -eq 0) { $curlyBracketCount-- } } } } $expressionLineList += $currentLine $currentLineIndex++ } while ($parenthesesCount -gt 0 -or $curlyBracketCount -gt 0 -or $currentLine.TrimEnd().EndsWith('`')) return $expressionLineList -join "`n" } # 处理交互式终端调用场景 else { return (Get-History -Count 1).CommandLine } }
测试方法
你可以用下面的多行调用验证效果:
Get-OriginalCallExpression ` -Param1 "测试字符串" ` -Param2 @(1,2,3,4) ` -Param3 @{key = "value"}
调用后会返回完整的4行原始调用内容,不会被截断为第一行。
注意事项
- 脚本场景下如果调用表达式本身存在语法错误(比如未闭合的括号),会导致读取范围超出预期
- 交互式场景下如果同一行用分号分隔了多个命令,会返回整行所有命令内容,你可以根据函数名自行截取对应片段
- 该实现兼容大多数常规的多行调用场景,特殊的语法结构可以根据需求自行调整扫描规则
内容的提问来源于stack exchange,提问作者Clay Sweetser
相关产品推荐
相关产品推荐

