PowerShell 技能连载 - 将哈希表转换为 JSON
在前一个技能中我们大量操作了哈希表,甚至从 .psd1 文件中读取。如果您需要不同格式的数据,例如 JSON,那么转换工作很简单。需要做的只是先将哈希表转换为一个对象:
1 | $hash = @{ |
当哈希表转换为一个对象以后,您可以将它用管道传递给 ConvertTo-Json
,或其它的 ConvertTo-*
指令。
在前一个技能中我们大量操作了哈希表,甚至从 .psd1 文件中读取。如果您需要不同格式的数据,例如 JSON,那么转换工作很简单。需要做的只是先将哈希表转换为一个对象:
1 | $hash = @{ |
当哈希表转换为一个对象以后,您可以将它用管道传递给 ConvertTo-Json
,或其它的 ConvertTo-*
指令。
在前一个技能中我们介绍了通过 Import-LocalizedData
读取存储在 .psd1 文件中的数据。
从 PowerShell 5 开始,有一个新的cmdlet名为 Import-PowerShellDataFile
。您可以用它安全地从 .psd1 文件中读取数据。类似 Import-LocalizedData
,这个cmdlet只接受没有活动内容(没有命令和变量)的 .psd1 文件。
以下是您需要的脚本:
1 | $path = "$PSScriptRoot\data.psd1" |
将数据文件存放在相同文件夹下,将它命名为 data.psd1,然后设为如下内容:
1 | @{ |
当您运行这段脚本时,它将 .psd1 文件中的数据以哈希表的形式返回。
一个脚本有多种方法可以保存数据信息。有一种方式特别方便。以下是实现的代码:
1 | Import-LocalizedData -BaseDirectory $PSScriptRoot -FileName data.psd1 -BindingVariable Info |
请确保将这段代码保存为一个脚本。然后在同一个文件夹中创建另一个文件,并命名为 “data.psd1”,然后增加这段内容:
1 | @{ |
当两个文件都放在目录下时,运行脚本。它将读取 data.psd1 并将它的内容返回为一个哈希表。请注意 Import-LocalizedData
默认情况下并不能将 .psd1 文件作为活动的内容来处理。当 data.psd1 中的哈希表包含命令和变量时,它不可以读取——防止黑客纂改数据文件内容。
如果您在文件夹中添加了子文件夹,并且命名为语言区域性 ID,例如 “de-de” 和 “en-us”,Import-LocalizedData
将会自动检测合适的子目录并且从中读取文件(假设您将数据文件的本地化拷贝放在这些文件夹中)。该 cmdlet 将使用 $PSCulture
中提供的语言区域设置,或者如果指定了 -UICulture
,将使用该设置。
PowerShell 使用 .NET 类型名,例如将值转换为指定的类型。脚本中常常可以使用各种格式来定义 .NET 类型。以下是它们各自的用意和含义:
1 | # short name for "Integer" data type |
简单来说,PowerShell 维护着它自己的“类型加速器”:.NET 类型的别名。查看任意类型的 FullName
属性,可以获得完整正式的 .NET 类型名。类型名前面的 “System.” 是可以省略的。
错误处理不必做的很复杂。它可以简单到检测上一条命令是否执行成功:
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
直接写到宿主的信息,所有输入输出信息都将被记录下。这些信息只能在屏幕上看到。