在使用 PowerShell 的过程中,发现它的异常处理并不像想象中的那么直观,所以在这里总结一下。

Terminating Errors

通过 ThrowTerminatingError 触发的错误称为 Terminating Errors。本质上它是创建了一个异常,所以我们可以使用 catch 语句来捕获 Terminating Errors。因此 Terminating Errors 的另外一个名字叫 Exceptions。默认情况下,Terminating Errors 不影响后面命令的执行!

把下面的代码保存到文件 exception.ps1 中:

# 下面的命令不存在
Get-TerminatingError Write-Host 'hello world'

然后执行脚本 exception.ps1:

注意最后输出的 "hello world",虽然执行过程中出现了错误,但是错误后面的代码依然被执行了。
Terminating Errors 的特点是默认情况下你可以通过 catch 语句捕获它,从而控制代码的执行流。
把下面的代码保存到文件 exception.ps1 中:

Try{
# 下面的命令不存在
Get-TerminatingError
}
Catch{
Write-Host 'got you'
exit 1
}
Write-Host 'hello world'

然后执行脚本 exception.ps1:

这样就好多了,我们预测了代码中可能产生的问题,并且在发生了错误的情况下果断的结束了脚本的执行。

虽然 Terminating Errors 不能中断脚本的执行,但是却可以中断 pipeline 的执行。从 Terminating Errors 的文档中我们可以看到,其内部抛出了 PipelineStoppedException 异常,并且 PowerShell 内部处理了这个异常。所以正在执行的 pipeline 会被中断掉,然后继续执行后面的其它代码。

Non-Terminating Errors

通过 Write-Error 触发的错误称为 Non-Terminating Errors。本质上它只是把错误信息写入了输出流中而没有产生异常,所以默认情况下 catch 语句无法捕获 Non-Terminating Errors。默认情况下,Non-Terminating Errors 不影响后面命令的执行!

把下面的代码保存到文件 exception.ps1 中:

# C:\xxx 不存在
Copy-Item C:\xxx
Write-Host 'hello world'

然后执行脚本 exception.ps1:

注意最后输出的 "hello world",虽然执行过程中出现了错误,但是错误后面的代码依然被执行了。

Non-Terminating Errors 的特点是默认情况下 catch 语句无法捕获它!
把下面的代码保存到文件 exception.ps1 中:

Try{
# C:\xxx 不存在
Copy-Item C:\xxx
}
Catch{
Write-Host 'got you'
exit 1
}
Write-Host 'hello world'

然后执行脚本 exception.ps1,结果和上面是一样的,错误后面的代码依然会被执行。

ErrorAction 选项的秘密

Non-Terminating Errors 默认只是通过 Write-Error 把错误信息写入了输出流中而没有产生异常,所以 catch 语句无法捕获 Non-Terminating Errors。但是我们却可以通过 -ErrorAction 选项改变 WriteError 的默认行为。
ErrorAction 选项主要用来改变命令的 non-terminating errors 的行为(它不会对 Terminating Errors 产生影响)!
ErrorAction 选项的工作原理为:用指定的参数覆盖当前命令的 $ErrorActionPreference 变量。默认情况下  $ErrorActionPreference 变量的值为 Continue。

可以为 -ErrorAction 选项指定下面的参数:

-ErrorAction[:{Continue | Ignore | Inquire | SilentlyContinue | Stop | Suspend }]

它们表示的含义如下:
Continue   显示错误信息并继续执行后面的命令,这是默认值。
Ignore       这个值是在 PowerShell 3.0 引入的。它不显示错误信息并继续执行后面的命令。与 SilentlyContinue 不同的是,它也不会把错误信息添加到 $Error 变量中。
Inquire      显示错误信息并弹框与用户交互。
SilentlyContinue   不显示错误信息并继续执行后面的命令。
Stop          显示错误信息并且退出脚本的执行。
Suspend    这个值只适用于 workflow。当 terminating error 发生时执行会暂停下来,然后决定是否恢复执行。

这里我们重点关注使用比较多的 stop, 它会让 Write-Error 等原本产生 non-terminating error 的命令产生 terminating error!所以我们就可以用 catch 语句来捕获异常了。把下面的代码保存到文件 exception.ps1 中:

Try{
# C:\xxx 不存在
Copy-Item C:\xxx -ErrorAction Stop
}
Catch{
Write-Host 'got you'
exit 1
}
Write-Host 'hello world'

注意我们为 Copy-Item 命令添加了 -ErrorAction Stop 选项,然后执行脚本 exception.ps1:

哈哈,这次捕获到异常了,并且最后也没有输出 "hello world"。

如果需要给每个命令都添加 -ErrorAction 选项可不是什么好玩的事情,好在我们可以在脚本中设置 $ErrorActionPreference 变量来完成同样的功能:

$ErrorActionPreference = 'Stop'

这样在当前的脚本中,所有原本的 non-terminating error 都会变成 terminating error。

Try/Catch/Finally

在异常处理中不介绍 Try/Catch/Finally 语句是不完整的。Catch 语句用来捕获 Try 块中产生的异常,当然我们可以指定只捕获那些我们感兴趣的异常。
Finally 块也是非常重要的,它能保证一些必要的逻辑被执行,比如释放数据库连接。下面的 demo 演示了如何在脚本中设置 $ErrorActionPreference 变量:

$eap = $ErrorActionPreference
Try{
$ErrorActionPreference = 'Stop'
# do something
}
Catch{
Write-Host "error !"
Exit 1
}
Finally{
$ErrorActionPreference = $eap
}

在 Finally 块中把 $ErrorActionPreference 变量还原,保证我们自己设置的 $ErrorActionPreference 变量只影响 Try/Catch 块中的语句。

$PSItem 变量

$PSItem 是一个 ErrorRecord 类型的变量,它会保存异常的详细信息。在捕获到异常时,我们可以把异常相关的信息输出或保存到日志中:

$eap = $ErrorActionPreference
Try{
$ErrorActionPreference = 'Stop'
# 下面的命令不存在
Get-TerminatingError
}
Catch{
# 比较简洁的信息
Write-Output $PSItem.ToString()
}
Finally{
$ErrorActionPreference = $eap
}

$PSItem.ToString() 中只有错误的描述,看起来会比较简洁。执行上面的脚本:

红框中的信息就是 $PSItem.ToString() 提供的。
仅有错误信息并不总是能够很好的帮助调查问题的根源,如果有出错的行号和异常堆栈会好很多:

$eap = $ErrorActionPreference
Try{
$ErrorActionPreference = 'Stop'
# 下面的命令不存在
Get-TerminatingError
}
Catch{
# 包含堆栈的信息
Write-Output $PSItem
}
Finally{
$ErrorActionPreference = $eap
}

这次我们直接输出了 $PSItem,执行上面的代码会得到下面的输出:

这下好多了,有了出错的行号和调用堆栈就可以很容易的看到出错的原因。

结论

作为一门脚本语言,PowerShell 对异常的支持还是非常强大的。不过像 Terminating Errors 和 Non-Terminating Errors 这样的特性也会给我们带来不少的困扰。希望本文介绍的内容可以帮助大家更好的理解 PowerShell 中异常相关的概念。

PowerShell 异常处理的更多相关文章

  1. PowerShell的异常处理办法

    $ErrorActionPreference = 'Stop' Try{     # C:\xxx 不存在     Copy-Item C:\xxx -ErrorAction Stop } Catch ...

  2. PowerShell 并行执行任务

    在 PowerShell 中可以轻松的执行后台任务并且让多个后台任务并行执行.本文介绍 PowerShell 中 Job 相关的一些命令,并通过 demo 演示如何在后台同时执行多个任务. Power ...

  3. powershell脚本之windows服务与进程

    powershell脚本之windows服务与进程 服务与进程的区别: Windows服务是指系统自动完成的,不需要和用户交互的过程,可长时间运行的可执行应用程序 进程是程序运行的实例,系统会给运行中 ...

  4. Powershell渗透测试系列–进阶篇

    原文来自:https://bbs.ichunqiu.com/thread-41561-1-1.html i春秋作家:anyedt 0×00 引言 经过基础篇的学习我们已经对powershell有了一个 ...

  5. 【错误记录】PowerShell 超级无语的语法错误(令人怀疑人生)

    曾经做过测试,本文是本章优秀测试人员的精神,必须定位到原因,不然吃不下饭.其实可以很容易绕过这种问题. 环境: PowerShell 5.1.16299.64 Windows 10 现有代码如下: # ...

  6. python的异常处理和模块发布安装

    1.完整的异常处理 异常处理能够保证程序出错是也能够完整运行,不会应为bug而停止运行,这里介绍下获取异常的完整格式 try: num = int(input("输入整数:")) ...

  7. Powershell基础学习

    从吐司偷来的图片,拿来当做引导吧: 0x01 简介 Windows PowerShell 是一种命令行外壳程序和脚本环境,使命令行用户和脚本编写者可以利用 .NET Framework的强大功能.当然 ...

  8. PowerShell入门学习

    一.概要 Powershell是运行在windows机器上实现系统和应用程序管理自动化的命令行脚本环境. powershell需要.NET环境的支持,同时支持.NET对象.之所以将Powershell ...

  9. 关于.NET异常处理的思考

    年关将至,对于大部分程序员来说,马上就可以闲下来一段时间了,然而在这个闲暇的时间里,唯有争论哪门语言更好可以消磨时光,估计最近会有很多关于java与.net的博文出现,我表示要作为一个吃瓜群众,静静的 ...

随机推荐

  1. 对vuex的认识和简单理解

    vuex概述 Vuex 是一个主要应用在中大型单页应用的类似于 Flux 的数据管理架构.它主要帮我们更好地组织代码,以及把应用内的的状态保持在可维护.可理解的状态. 但如果是简单的应用 ,就没有必要 ...

  2. angular4.0 安装最新版本的nodejs、npm、@angular/cli的方法

    在使用ng项目的ui框架时,比如ng-zorro.angular Material,需要安装最新版本的@angular/cli: 配置ng-zorro框架 ng-zorro官网:https://ng. ...

  3. C#Winform 自定义透明按钮和单窗体模块化实现

    技术看点 WinForm自定义控件的使用 WinForm单窗体应用如何模块化 需求及效果 又来一波 C# GDI自定义控件show .这个控件已经使用几年了,最近找出来重构一下.原来是没有边框的,那么 ...

  4. Centos6.4三种更改hostname的方法之间的对比

    首先,利用hostname命令查看一下当前主机的主机名,在终端输入hostname,会发现显示的是完整的主机名称(主机名.域名),其中主机名与进入终端后:登录名@主机名,显示的一致,如下图所示: 其次 ...

  5. 数据结构4——浅谈DancingLinks的思想及应用

    在学习DancingLinks之前,我们先来回顾一下我们以前学过的回溯法. 我们学习基础的回溯法的时候,我们都是先判断是否达到解,然后继续搜索. 对于搜到的下一个点,将他标记为使用过( vis[i]= ...

  6. screen使用

    远程连接Linux系统后,需要在后台运行一下程序,nohup呢感觉不大直观,打心里不信任它..那么screen就是很棒的工具,除了"后台"运行程序,还能做到分屏等等. 下面介绍一下 ...

  7. office漏洞利用--获取shell

    环境: kali系统, windows系统 流程: 在kali系统生成利用文件, kali系统下监听本地端口, windows系统打开doc文件,即可中招 第一种利用方式, 适合测试用: 从git下载 ...

  8. VS Code 快捷键(中英文对照版)

    原文地址:https://segmentfault.com/a/1190000007688656 常用 General 按 Press 功能 Function Ctrl + Shift + P,F1 ...

  9. Asp.net SignalR 让实时通讯变得简单

    巡更项目中,需要发送实时消息,以及需要任务开始提醒,于是便有机会接触到SignalR,在使用过程中,发现用SignalR实现通信非常简单,下面我思明将从三个方面分享一下: 一.SignalR是什么 A ...

  10. windows平台python 2.7环境编译安装zbarlight

    类似于前一篇博文,http://www.cnblogs.com/zhongtang/p/7148082.html中描述的情况. 编译zbarlight同样出现问题,简要处理步骤如下: 1.到https ...