14.PowerShell--抛出异常,错误处理
PowerShell – 错误处理
1. What-if 参数 (试运行,模拟操作)
简介:PowerShell 不会执行任何对系统有影响的操作,只会告诉你如果没有模拟运行,可能产生什么影响和后果。
实例:
PS C:\>Stop-Process -name calc -whatif
What if: Performing theoperation "Stop-Process" on target "calc (119000)".
2. -confirm参数 (逐步确认,逐个查询)
简介:PowerShell在使用“*”通配符时,可能会在瞬间产生许多任务。为了防止产生失误操作,可以逐个进行确认,逐个进行放行。
实例:
Stop-Process -Name *cm* -Confirm
确认程序提供了6个选项。
是 – 仅继续执行操作的下一步骤。
全是 – 继续执行操作的所有步骤。
否 – 跳过此操作并继续执行下一操作。
不全是 – 跳过此操作及所有后续操作。
挂起 – 暂停当前管道并返回到命令提示符。键入“exit”可继续执行该管道。
帮助 – 提供帮助信息
3. 跳过PowerShell中的Confirm 提示
解决方案:
可以使用自动化变量$ConfirmPreference来设置:
$ConfirmPreference 是一个枚举类型,分别有None,Low,Medium,High四个级别。在调用前备份$ConfirmPreference,然后将$ConfirmPreference设置为‘None’,在执行完Stop-Process 后,再还原设置,即可。默认为“High”,对有风险的脚本,要设置为High.
#查看$ConfirmPreference支持的设置
[ENUM]::GetNames($ConfirmPreference.GetType())
None
Low
Medium
High
#查看当前的$ConfirmPreference
$ConfirmPreference
High
#修改当前的$ConfirmPreference
$ConfirmPreference=“None”
实例:
PS C:\> $ConfirmPreference="High"
PS C:\> calc
PS C:\> Stop-Process -name calc -confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Stop-Process" on target"calc (87752)".
[Y] Yes [A] Yes toAll [N] No [L] No to All [S] Suspend [?] Help (default is"Y"):
4. 定义PowerShell的容错度
$ErrorView (可以简化输出错误信息)
$ErrorView="categoryview"
实例:
$ErrorView
NormalView
$ErrorView="categoryview"
Remove-Item www.mossfly.com
ObjectNotFound: (E:www.mossfly.com:String) [Remove-Item],ItemNotFoundException
b. $ErrorActionPreference(用于错误发生时候的处理方式)
可以应用于整个脚本(全局设置),或某段函数,某个脚本;
Member name Description
Continue 将错误抛出来,但是脚本会继续往下执行。(默认)
Ignore 直接忽略错误,貌似在Powershell 2.0中已经没有了
Inquire 提供选项由用户选择Error Action。
SilentlyContinue 错误不抛出,脚本也会继续执行。
Stop 错误发生时,终止脚本执行
5. 在PowerShell中识别和处理异常
抑制内置的错误信息;
如:设置$ ErrorActionPreference=“ SilentlyContinue”,让错误信息不输出;
b. 有一个能够发现异常是否发生的机制;
实例一: ($?—返回上一个命名执行成功与否,成功为true;)
Remove-Item "file not exist" -ErrorAction"SilentlyContinue"
If(!$?)
{
"failed to delete the file.";
break;
};
"succeed to delete the file"
输出结果:(由于没有这个文件或文件夹"file not exist")
"failed to delete the file.";
实例二: $Error集合可以记录256条错误记录,$error[0])包含最后一条错误,上一个错误是$error[1])",可以将这个集合看作一个队列)
Remove-Item "file not exist" -ErrorAction"SilentlyContinue"
If(!$?)
{
#"there is an exception, information is $($error[0])";
break;
};
"succeed to delete the file"
输出结果:
there is an exception, information isSystem.Management.Automation.IncompleteParseException: Missing statement blockafter If ( condition ). atSystem.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input) at Microsoft.PowerShell.Executor.ExecuteCommandHelper(PipelinetempPipeline, Exception& exceptionThrown, ExecutionOp
tions options)
6. 使用Traps处理异常
简介: 使用Traps可以捕获异常,在捕获到异常时,可以在做相应的处理。例如我们在PowerShell自动化工作中,出现了异常可以发一封邮件给管理员。
实例一:捕捉发生的异常,不做处理,继续执行后面代码。
trap
{
"you already captured the exception"
}
1/0
"123"
输出结果:
you already captured the exception
Attempted to divide by zero.
At line:5 char:1
+ 1/0
+ ~~~
+ CategoryInfo : NotSpecified: (:) [],RuntimeException
+FullyQualifiedErrorId : RuntimeException
123
实例二:捕捉发生的异常,使用continue继续执行脚本/后面代码。
trap
{
"you already captured the exception";
continue;
}
stop-service -name "123" -erroraction "stop"
write-host "continue to execute"
输出结果:
you already captured the exception
continue to execute
实例三:捕捉发生的异常,使用break中断脚本执行。
trap
{
"you already captured the exception";
break;
}
stop-service -name "123" -erroraction "stop"
write-host "continue to execute"
输出结果:
you already captured the exception
stop-service : Cannot find any service with service name‘123‘.
At line:6 char:1
+ stop-service -name "123" -erroraction"stop"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (123:String)[Stop-Service], ServiceCommandException + FullyQualifiedErrorId :NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.StopServiceCommand
实例四:捕捉发生的异常,查看异常的详细信息。
(PowerShell会自动将异常保存在$_变量中)
trap
{
write-host $_.exception.message;
continue;
}
stop-service -name "123" -erroraction "stop"
write-host "continue to execute"
输出结果:
Cannot find any service with service name ‘123‘.
continue to execute
7.PowerShell 错误记录:详细错误
实例一:将异常重定向,重定向操作符(2>)到变量$myerror中
$myerror= remove-item "NoSuchDirectory" 2>&1
$myerror.exception
输出结果:
Cannot find path ‘D:\NoSuchDirectory‘ because it does not exist.
#清晰查看错误信息
PS D:\> $myerror.FullyQualifiedErrorId
PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
实例二:使用ErrorVariable参数,PowerShell 自动把出现的错误保存在这个变量中,不受ErrorAction配置的影响
PS D:\> Remove-Item "NoSuchDirectory"-ErrorVariable ErrorStore -ErrorAction "SilentlyContinue"
PS D:\> $ErrorStore
Remove-Item : Cannot find path ‘D:\NoSuchDirectory‘ because itdoes not exist. At line:1 char:1
+ Remove-Item "NoSuchDirectory" -ErrorVariableErrorStore -ErrorAction "SilentlyCo ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound:(D:\NoSuchDirectory:String) [Remove-Item], ItemNotFoundException
+ FullyQualifiedErrorId :PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
$ErrorStore.GetType().fullName
# System.Collections.ArrayList
$ErrorStore[0].gettype().fullName
#System.Management.Automation.ErrorRecord
$ErrorStore[0].Exception.Message
#Cannot find path ‘D:\NoSuchDirectory‘ becauseit does not exist.
实例三:使用ErrorVariable参数,并作为数组来保存一次信息
PS C:\Windows\system32> Get-Item"NOSuchDir1","NOSuchDir2","NOSuchDir3"-ErrorAction "SilentlyContinue" -ErrorVariable ErrorStore
PS C:\Windows\system32> $Error.Count
3
实例四:还有一个小技巧,可以给-ErrorVariable参数前加一个“+”,代表追加存储错误,可以将一连串的错误合并在一个数组,后面可以统一进行分析处理,如下:
PS C:\Windows\system32> Get-Item "NOSuchDir1"-ErrorAction "SilentlyContinue" -ErrorVariable +ErrorStore
PS C:\Windows\system32> Remove-Item "NOSuchDir1"-ErrorAction "SilentlyContinue" -ErrorVariable +ErrorStore
PS C:\Windows\system32> Get-Process "NOSuchDir1"-ErrorAction "SilentlyContinue" -ErrorVariable +ErrorStore
PS C:\Windows\system32> $ErrorStore
Get-Item : Cannot find path ‘C:\Windows\system32\NOSuchDir1‘because it does not exist. At line:1 char:1
+ Get-Item "NOSuchDir1" -ErrorAction"SilentlyContinue" -ErrorVariable +ErrorStore
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound:(C:\Windows\system32\NOSuchDir1:String) [Get-Item], ItemNotFoundExceptio
n + FullyQualifiedErrorId :PathNotFound,Microsoft.PowerShell.Commands.GetItemCommand
Remove-Item : Cannot find path ‘C:\Windows\system32\NOSuchDir1‘because it does not exist. At line:1 char:1
+ Remove-Item "NOSuchDir1" -ErrorAction"SilentlyContinue" -ErrorVariable +ErrorSt ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound:(C:\Windows\system32\NOSuchDir1:String) [Remove-Item],ItemNotFoundException +FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.RemoveItemCommand
Get-Process : Cannot find a process with the name"NOSuchDir1". Verify the process name and call the cmdlet again. Atline:1 char:1
+ Get-Process "NOSuchDir1" -ErrorAction"SilentlyContinue" -ErrorVariable +ErrorSt ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (NOSuchDir1:String)[Get-Process], ProcessCommandException
+FullyQualifiedErrorId :NoProcessFoundForGivenName,Microsoft.PowerShell.Commands.GetProcessCommand
PS C:\Windows\system32> $ErrorStore.count
3
实例五:通过$Error查看错误信息
(PowerShell会自动收集异常,存储在自动化常量$Error中,$Error是一个数组,把每次最后发生的一次保存在索引为0的位置,存储异常时候,会占用资源,使用$Error.Clean()来清空异常,这个数组也有最大值的,最大值存储在$MaximumErrorCount自动化变量中,默认为256.)
$MaximumErrorCount
# 256
$MaximumErrorCount=267
$MaximumErrorCount
# 267
8. 理解PowerShell中的异常
PowerShell的Exception和.NET的Exception对应
运行程序中在发生错误的时候,会抛出一个异常来弥补
开发者应能够捕获和处理潜在的异常;
实例一:#查看最后的异常
$Error[0].Exception.Message
#找不到路径“Cddd”,因为该路径不存在。
实例二:#列出当前Error变量中存储的Exception类型
#当$Error中Exception为null时,不能调用Message,否则会报错。
$Error | where {$_.Exception -ne $null} | foreach {$_.Exception.GetType().fullName}
System.Management.Automation.RuntimeException
System.Management.Automation.RuntimeException
System.Management.Automation.ItemNotFoundException
System.Management.Automation.CommandNotFoundException
实例三:#处理特定的异常(类型.NET中的try一样捕获特定的异常)
Trap [System.DivideByZeroException] {
#"除数为空!";
"divider could not be null";
Continue;
}
Trap [System.Management.Automation.ParameterBindingException] {
#"参数不正确!";
"parameter was wrong";
Continue;
}
Trap [System.Net.WebException]{
#"网络异常!"
"network error";
Continue;
}
1/$null
Dir -MacGuffin
$wc = new-object System.Net.WebClient
$wc.DownloadFile("http://www.mossfly.com/powershell.txt","e:ps.txt")
#除数为空!
#参数不正确!
#网络异常!
实例四:#抛出自定义的异常信息(throw)
PS C:\Windows\system32> Function Func-Test($a,$b)
>> {
>> if($b -eq $null)
>> {
>> #throw "参数b 不能为空!"
>> throw "parameter b could not be null"
>> }
>> "{0}+{1}={2}" -f $a,$b,($a+$b)
>> }
>> Func-Test -a 10
>>
parameter b could not be null
At line:6 char:1
+ throw "parameter b could not be null"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (parameter bcould not be null:String) [], RuntimeException
+FullyQualifiedErrorId : parameter b could not be null
实例五:#在函数参数中默认值为抛出一个异常,如果没有传入参数的话(throw)
PS C:\Windows\system32> Function Func-Test($a,$b=$(throw"parameter b could not be null"))
>> {
>> "{0}+{1}={2}" -f $a,$b,($a+$b)
>> }
>> Func-Test -a 10 -b 9
>> Func-Test -a 10
>>
10+9=19
parameter b could not be null
At line:1 char:28
+ Function Func-Test($a,$b=$(throw "parameter b could notbe null"))
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (parameter bcould not be null:String) [], RuntimeException
+FullyQualifiedErrorId : parameter b could not be null
9. PowerShell在函数中捕获异常
实例一:Trap中的continue使用
如果将Trap放在函数的调用者中,并跟上Continue,这样函数中第一条错误发生,脚本就会终止执行,并且屏蔽Powershell默认的错误输出。
function Caller
{
Trap
{
"Trap Error:$($_.Exception.Message)";
Continue
}
Test-Func
}
function Test-Func
{
1/$null
Get-Process "nosuchthing"-ea Stop
Dir xyz: -ea Stop
}
Caller
Trap Error: Attempted todivide by zero.
#Trap Error: 试图除以零。
实例二:Trap中的break使用
如果你想让脚本在第一次遇到异常就停止工作,可以在Trap中添加Break,如下:
Function Test-Func
{
Trap {
"Trap到了异常:$($_.Exception.Message)";
Break
}
1/$null
Get-Process "NoSuchProcess"-ErrorAction Stop
Dir MossFly: -ErrorActionStop
}
Test-Func
Trap到了异常:试图除以零。
试图除以零。
所在位置E:MyScript.ps1:8 字符: 3
+ 1/ <<<<$null
+ CategoryInfo :NotSpecified: (:) [], ParentContainsErrorRecordExc
eption+ FullyQualifiedErrorId :RuntimeException
实例三:嵌套函数中的异常捕获
在Powershell中还可以嵌套函数,也就是函数中定义函数。Trap 定义在外部函数,内部 函数的异常,会在外部被捕获。此时的内部函数就像一连串的脚本块。
function test-func
{
# 将 Trap 定义在函数外面:
Trap {"Trap Error:$($_.Exception.Message)"; Continue}
# 内部函数
function InnerCore
{
1/$null
Get-Process "nosuchthing"-ea Stop
Dir xyz: -ea Stop
}
InnerCore
}
test-func
Trap Error: Attempted todivide by zero.
#Trap Error: 试图除以零。
实例四:通过&符号定义脚本块,来调用异常;
function test-func
{
# 将Trap 定义在函数外面:
Trap {"Trap Error:$($_.Exception.Message)"; Continue}
# 内部函数
&{
#1/$null
Get-Process"nosuchthing" -ea Stop
Dir xyz: -ea Stop
}
}
test-func
Trap Error: Attempted todivide by zero.
#Trap Error: 试图除以零。
实例五:决定异常产生后脚本是继续执行还是停止与ErrorAction和Traps有关;
因为Traps运行在ErrorAction之后,即使ErrorAction的参数为Stop,也有可能被Trap的设置覆盖。
因为系统中$ErrorActionPreference的默认值为Continue,下面函数中的脚本遇到错误时,会继续执行。但是Trap只会执行一次。
Function Test-Func
{
Trap { "Trap 到异常了." }
1/$null
Get-Process "NoSuchProcess"
Dir MossFly:
}
Test-Func
Trap 到异常了.
试图除以零。
+ 1/ <<<< $null
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。
+ Get-Process <<<< "NoSuchProcess"
+ CategoryInfo : ObjectNotFound: (NoSuchProcess:String)[Get-Proc
ess], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.
Commands.GetProcessCommand
Get-ChildItem : 找不到驱动器。名为“MossFly”的驱动器不存在。
+ Dir <<<< MossFly:
+ CategoryInfo : ObjectNotFound: (MossFly:String)[Get-ChildItem]
, DriveNotFoundException
+ FullyQualifiedErrorId :DriveNotFound,Microsoft.PowerShell.Commands.GetC
hildItemCommand
一旦将ErrorAction设置为Stop,则会每次报告异常,每次都会被Trap到。下面函数中的脚本遇到错误时,会继续执行。但是Trap每次都执行一次。
Function Test-Func
{
Trap { "Trap 到异常了." }
1/$null
Get-Process "NoSuchProcess" -ErrorAction Stop
Dir MossFly: -ErrorAction Stop
}
Test-Func
Trap 到异常了.
试图除以零。
+ 1/ <<<< $null
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException
Trap 到异常了.
Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。
+ Get-Process <<<<"NoSuchProcess" -ErrorAction Stop
+ CategoryInfo : ObjectNotFound: (NoSuchProcess:String)[Get-Proc
ess], ProcessCommandException
+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.
Commands.GetProcessCommand
Trap 到异常了.
Get-ChildItem : 找不到驱动器。名为“MossFly”的驱动器不存在。
+ Dir <<<< MossFly: -ErrorAction Stop
+ CategoryInfo : ObjectNotFound: (MossFly:String) [Get-ChildItem]
, DriveNotFoundException
+ FullyQualifiedErrorId :DriveNotFound,Microsoft.PowerShell.Commands.GetC
hildItemCommand
如果在Trap中使用了Continue,可以屏蔽默认的异常输出,也可以定制自己的异常。
Function Test-Func
{
Trap {
"Trap到了异常: $($_.Exception.Message)";
Continue
}
1/$null
Get-Process "NoSuchProcess" -ErrorAction Stop
Dir MossFly: -ErrorAction Stop
}
Test-Func
Trap到了异常: 试图除以零。
Trap到了异常: 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet。
Trap到了异常: 找不到驱动器。名为“MossFly”的驱动器不存在。
10. PowerShell 中的断点执行
PowerShell中实现调试的目的有两种:
在脚本或函数中使用断点停止脚本执行;
直接输出一些调试信息。
实例一:调试信息的输出,PowerShell中的$DebugPreference
Write-debug 的行为受$DebugPreference的影响,$DebugPreference值默认为”SilentlyContinue”,此时Write-debug不会输出任何信息。
$DebugPreference可选的配置如下:
SilentlyContinue:调试关闭
Stop:输出调试信息,终止脚本执行
Continue:输出调试信息,继续执行脚本
Inquire:输出调试信息,询问用户是否继续执行。
可以通过下面的例子对比:
PS C:> $DebugPreference="silentlycontinue"
PS C:> Write-Debug "输入一行调试信息"; Write-Host "伦敦奥运会女子体操决赛"
伦敦奥运会女子体操决赛
PS C:> $DebugPreference="stop"
PS C:> Write-Debug "输入一行调试信息"; Write-Host "伦敦奥运会女子体操决赛"
调试: 输入一行调试信息
Write-Debug : 已停止执行命令,因为首选项变量“DebugPreference”或通用参数被设置为 Stop。
所在位置 行:1 字符: 12
+ Write-Debug <<<< "输入一行调试信息" ; Write-Host "伦敦奥运会女子体操决赛" +CategoryInfo : OperationStopped:(:) [Write-Debug], ParentContainsErrorRecordExceptio + FullyQualifiedErrorId : ActionPreferenceStop,Microsoft.PowerShell.Commands.WriteDebugCommandPS C:> $DebugPreference="continue"
PS C:> Write-Debug "输入一行调试信息"; Write-Host "伦敦奥运会女子体操决赛"
调试: 输入一行调试信息
伦敦奥运会女子体操决赛
PS C:> $DebugPreference="inquire"
PS C:> Write-Debug "输入一行调试信息"; Write-Host "伦敦奥运会女子体操决赛"
调试: 输入一行调试信息
确认
是否继续执行此操作?
[Y] 是(Y) [A] 全是(A) [H] 终止命令(H) [S] 挂起(S) [?] 帮助 (默认值为“Y”): y
伦敦奥运会女子体操决赛
实例二:PowerShell中的一些自动化变量
ConfirmPreference:设置提问确认的级别
DebugPreference:设置debug信息的显示级别,参考本文上面的信息。
ErrorActionPreference:设置发生错误后的执行动作
ErrorView:设置错误的显示模式,
ProgressPreference:设置进度条的显示模式,
ReportErrorShowExceptionClass:显示异常所在的类。
ReportErrorShowInnerException:显示异常内部异常信息。
ReportErrorShowSource:显示异常的来源。
ReportErrorShowStackTrace:显示异常的错误跟踪栈。
VerbosePreference:设置详细信息的显示模式。
WarningPreference:设置警告信息的显示模式。
实例三:单步跟踪:逐行执行
我们可以在 Powershell ISE 中通过F9断点执行Powershell脚本。但是即使没有ISE也可以单步跟踪。只需要Set-PSDebug -step,Powershell会每只行一段代码,就会向用户询问是否继续执行。
PSC:\Windows\system32> Set-PSDebug -step
PSC:\Windows\system32> write-host "continue to execute"
Continuewith this operation?
1+ >>>> write-host "continue to execute"
[Y]Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):write-host "continue to execute"
a
[Y]Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): a
DEBUG: 1+ >>>> write-host "continue to execute"
continueto execute
参考:http://www.pstips.net/powershell-online-tutorials/
本文出自 “Ricky's Blog” 博客,请务必保留此出处http://57388.blog.51cto.com/47388/1640402