有没有办法进入PowerShell调试器以响应错误? ErrorAction
参数有几个值,但我没有看到Debug
之类的内容。我想要打开调试器,就像我设置了断点一样,但只有在发生错误时才会打开(例如,Write-Error
)。
修改 我应该澄清一下:我主要是一个C#开发人员,对PowerShell来说有点新,我期待的行为类似于Visual Studio调试器为您提供的“未处理的异常”。看起来PowerShell命令更常见的是抛出异常,而自定义脚本似乎主要使用Write-Error。我不认为我特别注意区分这两者,但我想处理两者。
Trevor Sullivan在下面的回答中提到你可以使用Set-PSBreakpoint -Command Write-Error -Action { break; };
,这似乎可以很好地捕捉这些案例。虽然,我发现在很多情况下,它实际上是一个抛出异常的命令,我想打破它。如果你设置$ErrorActionPreference = "stop"
,Roman Kuzmin的答案似乎有效,但是,我有一个问题,我无法单步执行该程序,它似乎突破了该位置并结束了脚本。如果$ErrorActionPreference = "continue"
它对我不起作用。陷阱通常似乎有一个类似的问题,它们突破了任何嵌套的范围,这是不希望的。
答案 0 :(得分:26)
当然。您可以使用Set-PSBreakpoint
cmdlet在PowerShell中创建条件断点。请考虑以下代码。将其另存为脚本文件,然后执行它。有一些内嵌评论可以帮助您了解正在发生的事情。
请记住,有三种不同类型的断点:
此代码示例使用命令断点类型,因为我告诉它只在Get-WmiObject
命令上设置断点。您可以交替指定特定的行号或变量断点类型。您可以使用-Action
参数指定要在其下设置断点的条件。您必须在break
-Action
内的某处使用ScriptBlock
关键字,以指示调试器暂停执行PowerShell脚本。
# 1. Reset $Error to $null
$WmiError = $null;
# 2. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;
# 3. Set breakpoint, but only on Get-WmiObject commands, when the $WmiError variable is not $null
Set-PSBreakpoint -Command Get-WmiObject -Action { if ($WmiError) { break; } };
# 4. Failed Get-WmiObject command
Get-WmiObject -Class Win32_NonExistentClass -ErrorVariable WmiError;
# 5. Successful Get-WmiObject command
# PowerShell breaks here, because:
# - It's a Get-WmiObject command
# - The $WmiError variable is not null
Get-WmiObject -Class Win32_BIOS;
由于您提到使用Write-Error
,因此您可以在显示PSBreakpoint
的行上设置Write-Error
。以下是如何执行此操作的示例:
Set-PSBreakpoint -Command Write-Error -Action { break; };
很简单,对吧?
此示例使用变量PSBreakpoint
类型,但仅在修改变量的内容时使用。您可以使用-Mode
参数来确定命中变量断点的条件:
代码:
# 1. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;
# 2. Set a PSBreakpoint of type "variable" on a variable named "Data," but only when it has changed
Set-PSBreakpoint -Action { Write-Host -ForegroundColor Green -Object ('The $Data variable has changed! Value is: {0}' -f $Data); break; } -Variable Data -Mode Write;
# 3. No break on this line, because we are not changing the variable
Write-Host -Object $Data;
# 4. Execution is paused on this line, because we change the variable
$Data = 1;
现在我们已经查看了变量和命令 PSBreakpoint
类型,要探索的最后一种断点是行强>断点。如果您要复制/粘贴下面的代码,保存并执行它,您会看到Write-Host行上的代码中断(恰好是第9行),但仅限于Name
属性$Service
变量的值等于WinRM
。这就是-Action
参数ScriptBlock
中的条件语句定义的内容。
# 1. Clean up any existing breakpoints
Get-PSBreakpoint | Remove-PSBreakpoint;
# 2. Set a PSBreakpoint of type "line" on line #8, but only if the $Service variable's Name property equals 'winrm'
Set-PSBreakpoint -Action { if ($Service.Name -eq 'winrm') { break; } } -Line 9 -Script $MyInvocation.MyCommand.Path;
# 3. Get a list of Windows Services and iterate over them
foreach ($Service in (Get-WmiObject -Class Win32_Service)) {
Write-Host -Object ('Service name is: {0}' -f $Service.Name);
}
答案 1 :(得分:19)
是的,有一种简单的方法可以在错误中闯入调试器。看起来像
每次发生错误时,变量StackTrace
都会更新。所以我
使用这个技巧:在我的个人资料中,我有这两个功能(开关):
<#
.Synopsis
Sets $StackTrace breakpoint
.Link
rbps
#>
function sbps {
$null = Set-PSBreakpoint -Variable StackTrace -Mode Write
}
<#
.Synopsis
Removes $StackTrace breakpoint
.Link
sbps
#>
function rbps {
Get-PSBreakpoint -Variable StackTrace | Remove-PSBreakpoint
}
当第一个被调用时,实际上是在出错时进入调试器
启用。在写入错误StackTrace
时会触发断点。
第二个函数在关闭错误时会进入调试器。
在大多数情况下,这种方法对我很有用。
<强>更新强>
为了在没有配置文件功能的情况下使用这种技术,可以使用辅助脚本
Debug-Error.ps1
可以使用。理想情况下,它应该位于路径中,以便命令
<{1}}和Debug-Error
始终可用。
另见blog post。
Connect上的一些相关门票:
答案 2 :(得分:6)
您可以创建一个函数,在变量上设置断点,然后更改变量的值。
function Debug-Here {
if(!(Get-PSBreakpoint -Variable DebugHereCount)) {
$SCRIPT:DebugHere= Set-PSBreakpoint -Variable DebugHereCount
}
$DebugHereCount++
}
然后从脚本顶部的陷阱调用该函数以捕获所有终止错误。
trap { Debug-Here }
或者从try-catch
声明中调用它。
Get-Item DoesNotExist.txt -ErrorAction Stop
try {
$x = 0
$y = 1/$x
}
catch {
Debug-Here
}
进入调试模式后,请检查$Error[0]
以查看触发断点的内容。
答案 3 :(得分:2)
有点hokey但是在写错误或throw语句上工作:
$error.clear()
$global:errcnt=0
Set-PSBreakpoint -Command * -action {if ($error.count -ne $global:errcnt) {$global:errcnt=$error.count;break}}