在 Powershell 脚本中跟踪输出的来源

Tracing where output is coming from in a Powershell script

是否可以在 Powershell 脚本中跟踪输出(到控制台)的来源?我有一个脚本正在向我输出信息,但我不确定输出的是哪一行。例如,是否可以使用 Set-PSBreakpoint 并告诉它在信息返回到控制台时中断?

干杯


我收到了数百个 "False" 返回的消息。 这是输出来自的代码部分:

    $ar = Function-which_returns_array_of_objects
    $gr = Function-which_returns_array_of_objects

    Write-Host "To begin with..."
    Write-Host "$($ar.count) assets"
    Write-Host "$($gr.count) goods"

    foreach($asset in $ar){
        if(!(Test-NoNA -string $asset.Serial)){continue}

        #See if the particular serial number exists in Goods Received
        $found = @()
        $gr | Where {$_.SerialNumber -eq $asset.serial} | %{
            $found += $_
            # and then mark the entry as one that has to be deleted from GR
            $_.Delete = "YES"
        }
        if($found.count -eq 1){
            #Serial Number has been found once in GR
            #We want to check its PN...
            if(Test-NoNA -string $found.PartNumber -and $found.PartNumber -ne $asset.Model){
                #add it to the asset if its good and not the same as the model number...
                $asset.PartNumber -eq $found.PartNumber
            }
        }elseif(!$found -or $found.count -eq 0){
            #No entries found in GR
            #Shouldn't be the case but doesn't actually do any damage as we'd be deleting the GR entry anyway
        }elseif($found.count -gt 1){
            #More than one match for the SN - probably means a SN like "N/A" has got through the earlier checks
            Write-Warning "More than one match for SN: '$($asset.serial)'"
        }else{
            #Default catcher
            Write-Warning "Unknown Error for SN: '$($asset.serial)'"
        }
    }

此外,这里是 Test-NoNA:

function Test-NoNA($string){
#check that the given string is not blank, N/A, ?, etc. Returns true if string is good
if($string -and $string -ne "" -and $string -ne "N/A" -and $string -ne "NA" -and $string -ne '?' -and $string -isnot [System.DBNull]){return $true}
}

是的,试试这个。这应该在第一次找到写语句的地方中断。

  Set-PSBreakpoint -Script Sample.ps1 -Command "write*"

此命令在 Sample.ps1 脚本中以 write 开头的每个命令设置断点,例如 Write-Host。更多 参考 docs

不幸的是,

  • Set-PSBreakpoint -Commandexplicit cmdlet calls,

    • 例如,在脚本 ./myscript.ps1 中调用 Write-OutputWrite-Host 会导致通过先前的 Set-PSBreakpoint -Command Write-* ./myscript.ps1 调用进入调试器),
  • 但是是否使用隐式输出,来自语句其输出既不被捕获也不被重定向(例如,'foo'1 + 2Get-Date)。

在手头的特定情况下,由于混淆了 -eq 运算符(比较)与 =$asset.PartNumber -eq $found.PartNumber 等语句导致了不需要的输出运算符(赋值),由 Lee_Daily 诊断。 -eq 产生输出(比较的布尔结果),而 = 不产生输出。

解决方法

  • 运行 Set-PSDebug -Trace 1 在调用脚本之前, 在输出之前打印每个源代码行它产生s,如果有的话。 -Trace 2 提供更多详细信息。

  • 使用以下技术,它 告诉您产生成功输出的每个语句的位置和源代码,无论是隐式还是显式:

    ./myscript.ps1 | % { Write-Verbose -vb "Output from $(($entry=(Get-PsCallStack)[1]).Location): $($entry.Position.Text)"; $_ }
    
    • 脚本的成功输出通过 ForEach-Object (%), producing a verbose message reporting the location (script path and line number) as well as the source code of the originating statement (obtained via Get-PSCallStack) 一个对象一个对象地处理,然后将手头的对象 ($_) 通过。
  • 如果您想检查给定行上脚本的运行时状态,请说15:

    • Set-PSBreakpoint -Script ./myscript.ps1 -Line 15

    • 或者,在 PSv5+ 中,如果修改脚本(临时)是一个选项,请在您的脚本中您想要进入调试器的位置放置一个 Wait-Debugger 调用.

  • 使用 Visual Studio Code with the PowerShell extension 的调试功能 设置断点 and/or 逐步执行脚本 逐个陈述。

    • 或者,直接在 PowerShell window.
    • 中使用 Set-PSDebug -Step 进行等效操作