如何在 PowerShell 中打印脚本块内容

How can I print script block content in PowerShell

提问人:Maximus Gebo 提问时间:11/3/2023 最后编辑:mklement0Maximus Gebo 更新时间:11/6/2023 访问量:75

问:

嗨,大家好,我想创建一个函数,该函数将检查所选命令的执行情况,如果捕获失败,请重试 3 次,并显示带有重试消息的命令名称。我在要评估的函数括号之间放置了一个测试命令“测试连接”,重试似乎有效,但是我无法打印要打印的命令名称。我尝试使用“$($MyInvocation.MyCommand.ScriptBlock)”,但它打印出我正在检查的已执行行的整个函数。任何人都可以在这里提供建议吗? 提前非常感谢

function Execute-WithRetry([ScriptBlock]$command) {

    $Stoploop = $false
    $count = 0
 
    do {
        try {
            & $command
            Write-Host "Download completed"
            $Stoploop = $true
        }
        catch {
            if ($count -eq 3) {
               
                Write-Host "Could not download after 3 retries."
                $Stoploop = $true
            }
            else {
                Write-Host "Could not download the files retrying in 5 seconds..."
                Write-Host "Executing: $($MyInvocation.MyCommand.ScriptBlock)"
                Start-Sleep -Seconds 5
            }
        }
        $count++
    }
    While  ($Stoploop -eq $false)
    pause

    }


Execute-WithRetry {
  Test-Connection -ComputerName 192.10.129.15 -ErrorAction Stop
}
PowerShell 函数 错误处理 重试逻辑 脚本块

评论

0赞 Mathias R. Jessen 11/3/2023
听起来你正在找$MyInvocation.Line
0赞 Maximus Gebo 11/3/2023
它只会显示一个行号,而不是一个完整的命令,在我的情况下是“Test-Connection -....”
0赞 Mathias R. Jessen 11/3/2023
你错了,该属性包含一个字符串 - 引发错误的语句开始的行。如果未提供任何信息,请尝试直接从错误记录中获取调用信息:Line$MyInvocationtry {Test-Connection nonexistingfqdn -ErrorAction Stop}catch {Write-Host "Failed at '$($_.InvocationInfo.Line |% Trim)'"}
0赞 Maximus Gebo 11/4/2023
当然,我会尝试的。
0赞 Maximus Gebo 11/4/2023
它向我显示以下内容:在“&$command”处失败

答:

1赞 mklement0 11/4/2023 #1

前言:

  • 这个答案解决了所提出的问题:如何获取其调用触发错误的脚本块的整个源代码表示

  • Mathias 的有用回答演示了如何提取触发错误的脚本块源代码中的特定行


看起来您正在寻找存储在 中的脚本块源代码表示形式。$command

调用脚本块只返回 (没有括号 和 ),因此,只需引用 中的脚本块 ,即可扩展的字符串具有相同的效果。.ToString(){}"..."

因此,这应该做你想要的(周围和只是为了给出原始脚本块文字的完整外观):{}

Write-Host "Executing: {$command}"

注意:

  • 字符串表示正是您放置在其中的内容,即脚本块文本,因此可以包含换行符。{...}

一个简化的例子:

# Sample function that prints the source code of a given script block.
function Foo { param([scriptblock] $Command) "Source code: {$Command}" }

# Sample call
# ->
#  "Source code: { Get-Date -Format 'yyyy' }" 
Foo -Command { Get-Date -Format 'yyyy' }

直接调用脚本块文本使行为显而易见:.ToString()

# -> " Get-Date -Format 'yyyy' "
{ Get-Date -Format 'yyyy' }.ToString()
3赞 Mathias R. Jessen 11/4/2023 #2

如注释中所述,如果您只想从脚本块中获取“冒犯”行,请从块内的错误记录中获取调用信息(而不是 ),并使用该属性获取失败的语句开始的catch$MyInvocationLine

function Invoke-Retry {
  param([scriptblock]$Command)

  $stop = $false
  $count = 0

  $ErrorActionPreference = 'Stop'

  do {
    try {
      &$Command

      Write-Host "Download completed"
      $stop = $true
    }
    catch {
      if ($count -ge 3) {
        Write-Host "Could not download after 3 retries."
        $stop = $true
      }
      else {
        Write-Host "Could not download the files, retrying in 5 seconds"
        Write-Host "Error occurred while executing: `n>> $($_.InvocationInfo.Line)" -ForegroundColor Red
        Start-Sleep -Seconds 5
      }
    }
    $count++
  } while (-not $stop)
  pause
}

这应该给你脚本块中的实际行:

PS ~> Invoke-Retry {
  Test-Connection -ComputerName doesntexist
}
Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download the files retrying in 5 seconds
Error occurred while executing:
>>   Test-Connection -ComputerName doesntexist

Could not download after 3 retries.
Press Enter to continue...:

注: 从版本 7.4 开始,调用 info 类还通过 Statement 属性公开任何多行语句的完整范围

评论

0赞 mklement0 11/6/2023
做得很好(我的回答从字面上回答了这个问题)。很高兴知道 ;从 PowerShell 7.4.0-rc.1 开始,它有一个(小)问题:请参阅 GitHub 问题 #20638.InvocationInfo.Statement
1赞 Mathias R. Jessen 11/6/2023
@mklement0 感谢您的提醒,看来我们需要更多的测试 ^_^