PowerShell 技能连载 - 高效创建新的对象

多数时候,大部分新对象都是静态数据,以属性的方式表示。一个特别有效的创建新的包含新属性的对象是将哈希表转换为对象——我们早些时候转换过:

1
2
3
4
5
$conf = [PSCustomObject]@{
Name = 'Tobias'
Conf = 'psconf.eu'
Url = 'http://psconf.eu'
}

输出的结果是一个简单的对象,没有任何特别的方法:

1
2
3
4
5
PS C:\> $conf

Name Conf Url
---- ---- ---
Tobias psconf.eu http://psconf.eu

要增加方法,请在随后使用 Add-Member 修饰该对象。这行代码增加一个新的 Register() 方法:

1
2
$object |
Add-Member -MemberType ScriptMethod -Name Register -Value { Start-Process -FilePath $this.url }

请注意脚本块代码如何通过 Register() 方法来存取 $this$this 变量代表对象自身,所以即便您晚些时候才决定改变 “Url“ 属性,Register() 方法将仍然可以工作。

当您运行 Register() 方法,该对象打开 “Url“ 属性指定的 URL:

1
PS C:\> $conf.Register()

PowerShell 技能连载 - 在 PowerShell ISE 中添加单行注释

在前一个技能中,我们学习了针对 PowerShell ISE 的命令扩展。以下是另一个例子,增加 CTRL+K 键盘快捷键,在选中的每一行尾部添加注释 (#)。

1
2
3
4
5
6
7
8
function Invoke-Comment
{
$file = $psise.CurrentFile
$comment = ($file.Editor.SelectedText -split '\n' | ForEach-Object { "#$_" }) -join "`n"
$file.Editor.InsertText($comment)
}

$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Comment Out', { Invoke-Comment }, 'CTRL+K')

PowerShell 技能连载 - 在 PowerShell ISE 中切换注释

PowerShell ISE 暴露了一些可扩展的组件。例如,如果您希望按下 CTRL+K 切换选中文本的注释状态,请试试这段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Toggle-Comment
{
$file = $psise.CurrentFile
$text = $file.Editor.SelectedText
if ($text.StartsWith("<#")) {
$comment = $text.Substring(3).TrimEnd("#>")
}
else
{
$comment = "<#" + $text + "#>"
}
$file.Editor.InsertText($comment)
}

$psise.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Toggle Comment', { Toggle-Comment }, 'CTRL+K')

它基本上是使用 $psise 来操作 ISE 对象模型,然后安装一个快捷键为 CTRL+K 的新的菜单命令来调用 Toggle-Comment 函数。

在位于 $profile 的用户配置文件脚本中(这个路径可能还不存在)增加这段代码,PowerShell ISE 每次启动的时候就会自动运行这段代码。

PowerShell 技能连载 - 将哈希表转换为 JSON

在前一个技能中我们大量操作了哈希表,甚至从 .psd1 文件中读取。如果您需要不同格式的数据,例如 JSON,那么转换工作很简单。需要做的只是先将哈希表转换为一个对象:

1
2
3
4
5
6
7
8
9
$hash = @{
Name = 'Tobias'
ID = 12
Path = 'c:\windows'
}

$object = [PSCustomObject]$hash

$object | ConvertTo-Json

当哈希表转换为一个对象以后,您可以将它用管道传递给 ConvertTo-Json,或其它的 ConvertTo-* 指令。

PowerShell 技能连载 - 在 PowerShell 5+ 中读取 .PSD1 文件

在前一个技能中我们介绍了通过 Import-LocalizedData 读取存储在 .psd1 文件中的数据。

从 PowerShell 5 开始,有一个新的cmdlet名为 Import-PowerShellDataFile。您可以用它安全地从 .psd1 文件中读取数据。类似 Import-LocalizedData,这个cmdlet只接受没有活动内容(没有命令和变量)的 .psd1 文件。

以下是您需要的脚本:

1
2
$path = "$PSScriptRoot\data.psd1"
$infos = Import-PowerShellDataFile -Path $path

将数据文件存放在相同文件夹下,将它命名为 data.psd1,然后设为如下内容:

1
2
3
4
5
@{
Name = 'Tobias'
ID = 12
Path = 'c:\Windows'
}

当您运行这段脚本时,它将 .psd1 文件中的数据以哈希表的形式返回。

PowerShell 技能连载 - 从 .PSD1 文件中读取数据

一个脚本有多种方法可以保存数据信息。有一种方式特别方便。以下是实现的代码:

1
2
3
Import-LocalizedData -BaseDirectory $PSScriptRoot -FileName data.psd1 -BindingVariable Info

$Info

请确保将这段代码保存为一个脚本。然后在同一个文件夹中创建另一个文件,并命名为 “data.psd1”,然后增加这段内容:

1
2
3
4
5
@{
Name = 'Tobias'
ID = 12
Path = 'c:\Windows'
}

当两个文件都放在目录下时,运行脚本。它将读取 data.psd1 并将它的内容返回为一个哈希表。请注意 Import-LocalizedData 默认情况下并不能将 .psd1 文件作为活动的内容来处理。当 data.psd1 中的哈希表包含命令和变量时,它不可以读取——防止黑客纂改数据文件内容。

如果您在文件夹中添加了子文件夹,并且命名为语言区域性 ID,例如 “de-de” 和 “en-us”,Import-LocalizedData 将会自动检测合适的子目录并且从中读取文件(假设您将数据文件的本地化拷贝放在这些文件夹中)。该 cmdlet 将使用 $PSCulture 中提供的语言区域设置,或者如果指定了 -UICulture,将使用该设置。

PowerShell 技能连载 - 理解 PowerShell 中 .NET 类型名称的变体

PowerShell 使用 .NET 类型名,例如将值转换为指定的类型。脚本中常常可以使用各种格式来定义 .NET 类型。以下是它们各自的用意和含义:

1
2
3
4
5
6
7
8
# short name for "Integer" data type
[int]12.4
# official .NET type name
[system.int32]12.4
# here is how you get there
[int].FullName
# with official names, the namespace "System" is always optional
[int32]12.4

简单来说,PowerShell 维护着它自己的“类型加速器”:.NET 类型的别名。查看任意类型的 FullName 属性,可以获得完整正式的 .NET 类型名。类型名前面的 “System.” 是可以省略的。

PowerShell 技能连载 - 极简的错误处理

错误处理不必做的很复杂。它可以简单到检测上一条命令是否执行成功:

1
2
3
4
5
6
7
# suppress errors by default
$ErrorActionPreference = 'SilentlyContinue'
# if a command runs into an error...
Get-Process -Name zumsel
# ...then $? is $false, and you can exit PowerShell
# with a return value, i.e. 55
if (!$?) { exit 55 }

PowerShell 将上一个命令是否遇到错误的信息记录在 $? 变量中。在这个例子中,返回的是 $false。使用 exit 加上一个正数,就可以退出脚本,并且将退出码返回给调用者。

PowerShell 技能连载 - 临时禁用 PSReadLine 模块

从 PowerShell 5 开始,PowerShell 控制台支持彩色文本特性,以及一系列由 PSReadLine 模块提供的新特性。

如果您从更早的 PowerShell 版本升级到 PowerShell 5,而丢失了彩色文本功能,那么您可以从 PSGallery 下载和安装 PSReadLine 模块:

1
PS C:\> Install-Module -Name PSReadLine -Scope CurrentUser

类似地,如果您的 PS5+ 控制台和以前的行为不一致,例如不会执行粘贴入的代码块,那么您可以临时禁止该模块:

1
2
3
4
5
# disable PS5+ console handler temporarily
Remove-Module psreadline

# re-enable PS5+ console handler again
Import-Module psreadline

PowerShell 技能连载 -用 Windows 事件日志记录脚本日志

使用内置的 Windows 事件日志架构来记录脚本日志是很棒的方法,而且非常简单。以下是准备日志记录的初始步骤(需要管理员特权):

1
2
3
4
#requires -runasadministrator

New-EventLog -LogName PSScriptLog -Source Logon, Installation, Misc, Secret
Limit-EventLog -LogName PSScriptLog -MaximumSize 10MB -OverflowAction OverwriteAsNeeded

您可能需要改变日志的名称以及(或)错误源的名称。如果名字没有被占用,这些源可以起任意名称。

现在,每个普通用户可以使用以下代码来写入新的事件日志:

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*