PowerShell 技能连载 - 极简的错误处理
错误处理不必做的很复杂。它可以简单到检测上一条命令是否执行成功:
1 | # suppress errors by default |
PowerShell 将上一个命令是否遇到错误的信息记录在 $?
变量中。在这个例子中,返回的是 $false
。使用 exit
加上一个正数,就可以退出脚本,并且将退出码返回给调用者。
错误处理不必做的很复杂。它可以简单到检测上一条命令是否执行成功:
1 | # suppress errors by default |
PowerShell 将上一个命令是否遇到错误的信息记录在 $?
变量中。在这个例子中,返回的是 $false
。使用 exit
加上一个正数,就可以退出脚本,并且将退出码返回给调用者。
从 PowerShell 5 开始,PowerShell 控制台支持彩色文本特性,以及一系列由 PSReadLine 模块提供的新特性。
如果您从更早的 PowerShell 版本升级到 PowerShell 5,而丢失了彩色文本功能,那么您可以从 PSGallery 下载和安装 PSReadLine 模块:
1 | PS C:\> Install-Module -Name PSReadLine -Scope CurrentUser |
类似地,如果您的 PS5+ 控制台和以前的行为不一致,例如不会执行粘贴入的代码块,那么您可以临时禁止该模块:
1 | # disable PS5+ console handler temporarily |
使用内置的 Windows 事件日志架构来记录脚本日志是很棒的方法,而且非常简单。以下是准备日志记录的初始步骤(需要管理员特权):
1 | #requires -runasadministrator |
您可能需要改变日志的名称以及(或)错误源的名称。如果名字没有被占用,这些源可以起任意名称。
现在,每个普通用户可以使用以下代码来写入新的事件日志:
1 | Write-EventLog -LogName PSScriptLog -Source Logon -EntryType Warning -EventId 123 -Message "Problem in script $PSCommandPath" |
请注意 Write-EventLog
使用和前面定义相同的 logfile,并且 source 名称必须是前面定义过的之一。
但脚本写入信息到日志文件后,您可以搜索日志或者用 Get-EventLog
创建报告:
1 | PS C:\> Get-EventLog -LogName PSScriptLog -EntryType Error -Message *test.ps1* |
By converting a path to a FileInfo object, you can easily determine the path parent folder or file extension. Have a look:
([IO.FileInfo]'c:\test\abc.ps1').Extension
([IO.FileInfo]'c:\test\abc.ps1').DirectoryName
Often, code needs to check on files, and for example test whether the file exists or exceeds a given size. Here is some commonly used code:
$logFile = "$PSScriptRoot\mylog.txt"
$exists = Test-Path -Path $logFile
if ($exists)
{
$data = Get-Item -Path $logFile
if ($data.Length -gt 100KB)
{
Remove-Item -Path $logFile
}
}
By immediately converting a string path into a FileInfo object, you can do more with less:
[System.IO.FileInfo]$logFile = "$PSScriptRoot\mylog.txt"
if ($logFile.Exists -and $logFile.Length -gt 0KB) { Remove-Item -Path $logFile }
You can convert any path to a FileInfo object, even if it is not representing a file. That’s what the property “Exists” is for: it tells you whether the file is present or not.
ReTweet this Tip!
从 PowerShell 5 开始,您可以在任何宿主中使用 Strart-Transcript
来记录脚本的所有输出内容。以下是向各种脚本轻松添加日志的方法:
1 | # add this: ############################ |
只需要将注释块中的代码添加到脚本的开始和结束处。日志文件将会在脚本所在的目录创建。由于 $logFile
使用 $PSScriptRoot
(脚本的当前文件夹),请确保已经将脚本保存并以脚本的方式运行。否则,$PSScriptRoot
变量可能为空。
只需要确保脚本输出所有您需要的信息,就可以在 logfile 中看到它。例如将赋值语句放在括号中,PowerShell 将不只是赋值,而且将它们输出到 output。
警告:除了用 Write-Host
直接写到宿主的信息,所有输入输出信息都将被记录下。这些信息只能在屏幕上看到。
在 Windows 10 上,操作系统自带了一系列高质量的文本转语言引擎,而且不局限于英文。可用的 TTS 引擎数量依赖于您所安装的语言。
PowerShell 可以发送文本到这些 TTS 引擎,并且通过 tag 可以控制使用的语言。所以如果您同时安装了英语和德语的 TTS 引擎,您可以像下面这样混用不同的语言:
1 | $text = "<LANG LANGID=""409"">Your system will restart now!</LANG> |
如果您希望使用不同的语言,只需要将 LANGID 数字调整为您希望使用的文化代号。
有时候,您也许听说过 Trim()
、TrimStart()
和 TrimEnd()
可以 移除字符串中的文本。并且它们工作起来很正常:
1 | PS C:\> $testvalue = "this is strange" |
但是这个呢:
1 | PS C:\> $testvalue = "this is strange" |
实际情况是 Trim()
方法将您的参数视为一个字符的列表。所有这些字符都将被移除。
如果您只是想从字符串的任意位置移除文本,请使用 Replace()
来代替:
1 | PS C:\> $testvalue.Replace(" strange", "") |
如果您需要进一步的控制,请使用正则表达式和锚定。要只从字符串的尾部移除文本,以下代码可以实现这个功能。只有结尾部分的 “strange” 字符串会被移除。
1 | $testvalue = "this is strange strange strange" |
在前一个技能中您学习到了如何使用 Export-CliXml
命令来序列化数据并且用 Compress-Archive
将巨大的 XML 文件压缩成远远小于原始文件的尺寸。
今天,我们进行相反的操作:假设获得一个包含 XML 序列化数据的 ZIP 文件,然后恢复序列化的对象。当然这假设您已基于昨天的技能创建了这样的文件。
1 | # path to existing ZIP file |
通过 Export-CliXml
命令可以很方便地将处理结果保存到文件通过 Import-CliXml
命令,序列化的信息可以同样方便地恢复。然而,生成的 XML 文件可能非常大。
幸运的是,在 PowerShell 5 中有一个新的命令名叫 Compress-Archieve
。当您创建了 XML 文件之后,您可以自动地将它转为一个 ZIP 文件。
以下是一些演示代码:它获取一个进程列表并且保存到 XML 文件。然后将 XML 文件压缩为 ZIP,并且删除原始的 XML 文件。
这么做的效率很高,因为 XML 是文本文件。您常常能看到压缩率在 3-5%(ZIP 的文件大小是原始文件的 3-5%):
1 | $Path = "$env:TEMP\data1.xml" |