• 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的容错度

  1. $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中识别和处理异常

  1. 抑制内置的错误信息;

如:设置$ 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类型

#$ErrorExceptionnull时,不能调用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/ &lt;&lt;&lt;&lt; $null

+ CategoryInfo : NotSpecified: (:) [], RuntimeException

+ FullyQualifiedErrorId : RuntimeException 

Trap 到异常了.

Get-Process : 找不到名为“NoSuchProcess”的进程。请验证该进程名称,然后再次调用 cmdlet

+ Get-Process &lt;&lt;&lt;&lt;"NoSuchProcess" -ErrorAction Stop

+ CategoryInfo : ObjectNotFound: (NoSuchProcess:String)[Get-Proc

ess], ProcessCommandException

+ FullyQualifiedErrorId : NoProcessFoundForGivenName,Microsoft.PowerShell.

Commands.GetProcessCommand

Trap 到异常了.

Get-ChildItem : 找不到驱动器。名为“MossFly”的驱动器不存在

+ Dir &lt;&lt;&lt;&lt; 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中实现调试的目的有两种:

  1. 在脚本或函数中使用断点停止脚本执行;

  2. 直接输出一些调试信息。

实例一:调试信息的输出,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/