PowerShell 技能连载 - 参数的智能感知(第 2 部分)

如果输入参数时会为用户建议有效的参数,那岂不是很棒?有时候它们会提示。当您键入以下命令并在 -LogName 之后按空格时,PowerShell ISE 和 Visual Studio Code 会弹出一个 IntelliSense 菜单,其中包含您可以转储的所有日志文件:

1
PS> Get-EventLog -LogName

如果没有弹出自动 IntelliSense(换句话说在 PowerShell 控制台中),则可以按 TAB 键自动完成操作,或者按 CTRL + SPACE 手动强制显示 IntelliSense 选择项。

您可以使用自己的 PowerShell 函数执行相同的操作,并且有多种方法可以执行此操作。在上一个技能中,我们研究了使用枚举类型。但是,如果没有您想要向用户建议的枚举类型定义值,该怎么办?

要么使用“Enum""关键字定义自己的枚举类型(在 PowerShell 5 或更高版本中支持):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Enum MyVendors
{
Microsoft
Amazon
Google
}

function Get-Vendor
{
param(
[Parameter(Mandatory)]
[MyVendors]
$Vendor
)

"Chosen vendor: $Vendor"
}

或使用 Add-Type(所有 PowerShell 版本都支持)使用 C# 创建自己的枚举(请参见下文)。请注意,C# 代码区分大小写,并且枚举内的值以逗号分隔。“enum” 关键字后面的词定义了枚举的类型名称。使用该名称作为参数的数据类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$definition = 'public enum VendorList
{
Microsoft,
Amazon,
Google
}'
Add-Type -TypeDefinition $definition


function Get-Vendor
{
param(
[Parameter(Mandatory)]
[VendorList]
$Vendor
)

"Chosen vendor: $Vendor"
}

还要注意,Add-Type 不能编辑或覆盖类型,因此,如果要在使用枚举后更改枚举,则需要重新启动 PowerShell 或重命名枚举。而使用更新的 PowerShell “enum” 关键字,您可以随时更改枚举。

通过这两种方式,当用户调用您的函数并使用参数时,IntelliSense 都会列出可用的值。

1
2
PS> Get-Vendor -Vendor Amazon
Chosen vendor: Amazon

注意:将函数导出到模块时,请确保还将枚举也添加到模块中。必须先定义枚举类型,才能在调用使用这些枚举的函数。

评论

PowerShell 技能连载 - 参数的智能感知(第 1 部分)

如果输入参数时会为用户建议有效的参数,那岂不是很棒?有时候它们会提示。当您键入以下命令并在 -LogName 之后按空格时,PowerShell ISE 和 Visual Studio Code 会弹出一个 IntelliSense 菜单,其中包含您可以转储的所有日志文件:

1
PS> Get-EventLog -LogName

如果没有弹出自动 IntelliSense(换句话说在 PowerShell 控制台中),则可以按 TAB 键自动完成操作,或者按 CTRL + SPACE 手动强制显示 IntelliSense 选择项。

您可以使用自己的 PowerShell 函数执行相同的操作,并且有多种方法可以执行此操作。今天让我们来看一下使用枚举类型的方法。

将枚举类型分配给参数时,它将自动列出可用值。下面的代码使用了 [System.ConsoleColor] 类型,该类型列出了所有有效的控制台颜色:

1
2
3
4
5
6
7
8
9
10
function Set-ErrorColor
{
param(
[Parameter(Mandatory)]
[System.ConsoleColor]
$Color
)

$Host.PrivateData.ErrorForegroundColor = [string]$Color
}

当您调用 Set-ErrorColor 时,PowerShell 会自动向您建议有效的控制台颜色。当您选择一个时,该函数将此颜色分配给错误前景色。如果您不喜欢粗糙的红色错误颜色,请将错误消息变成绿色以使其更友好:

1
2
3
4
5
6
7
8
9
PS> Set-ErrorColor -Color Green

PS> 1/0
Attempted to divide by zero.
At line:1 char:1
+ 1/0
+ ~~~
+ CategoryInfo : NotSpecified: (:) [], RuntimeException
+ FullyQualifiedErrorId : RuntimeException

旁注:由您来决定对所选类型的处理方式。有时,将其转换为其他类型可能更理想。例如,在上面的示例中,选择的颜色将转换为字符串。为什么呢?

因为只有 PowerShell 控制台窗口支持 ConsoleColor 颜色。而 PowerShell ISE 编辑器等支持更多颜色,并使用 [System.Windows.Media.Color] 类型。

由于可以将字符串转换为这两种类型,但是 ConsoleColor 不能直接转换为 Windows.Media.Color,因此您可以将其转换为更通用的类型字符串,实现同时在控制台和 PowerShell ISE 中使用用户输入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# string converts to ConsoleColor
PS> [ConsoleColor]'red'
Red

# string converts to System.Windows.Media.Color
PS> [System.Windows.Media.Color]'red'


ColorContext :
A : 255
R : 255
G : 0
B : 0
ScA : 1
ScR : 1
ScG : 0
ScB : 0

# ConsoleColor DOES NOT convert to System.Windows.Media.Color
PS> [System.Windows.Media.Color][ConsoleColor]'red'
Cannot convert value "Red" to type "System.Windows.Media.Color". Error: "Invalid cast from 'System.ConsoleColor' to
'System.Windows.Media.Color'."
At line:1 char:1
+ [System.Windows.Media.Color][ConsoleColor]'red'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvalidCastIConvertible
评论

PowerShell 技能连载 - 区分 IPv4 和 IPv6

假设您要获取所有网卡的IP地址,但按地址类型将它们分开。这是一种仅使用 Select-Object 的实现方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Get-IPAddress
{
Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration |
Where-Object { $_.IPEnabled -eq $true } |
# add two new properties for IPv4 and IPv6 at the end
Select-Object -Property Description, MacAddress, IPAddress, IPAddressV4, IPAddressV6 |
ForEach-Object {
# add IP addresses that match the filter to the new properties
$_.IPAddressV4 = $_.IPAddress | Where-Object { $_ -like '*.*.*.*' }
$_.IPAddressV6 = $_.IPAddress | Where-Object { $_ -notlike '*.*.*.*' }
# return the object
$_
} |
# remove the property that holds all IP addresses
Select-Object -Property Description, MacAddress, IPAddressV4, IPAddressV6
}

Get-IPAddress

结果看起来类似这样:

Description                          MacAddress        IPAddressV4   IPAddressV6
-----------                          ----------        -----------   -----------
Realtek USB GbE Family Controller #3 00:E0:4C:F4:A9:35 10.4.121.75   fe80::8109:a41e:192b:367
评论

PowerShell 技能连载 - 安装并试运行 Windows Terminal

Windows Terminal 是一个新的多选项卡的用于基于控制台的外壳程序。它可以通过 Microsoft Store 正式获得,当前需要 Windows 10 1903 或更高版本。

要从 Microsoft Store 安装它,您首先需要注册,这很令人沮丧。如果要匿名安装 Windows Terminal(并且已在上一个技巧中安装Chocolatey),只需从提升的 PowerShell 中运行以下代码:

1
2
3
4
5
6
7
# download installation code
$code = Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' -UseBasicParsing
# invoke installation code
Invoke-Expression $code

# install windows terminal
choco install microsoft-windows-terminal -y

一旦 Windows Terminal 安装好,您可以通过 “wt” 命令启动它。

评论

PowerShell 技能连载 - 安装免费的 Chocolatey 包管理器

Chocolatey 是一个软件包管理系统,可以帮助您下​​载和安装软件包。与 PowerShell Gallery 不同,Chocolatey 不仅限于 PowerShell 模块和脚本,还可以安装各种软件,包括 Notepad ++、Acrobat Reader 或 Chrome 浏览器之类的工具。

如果您准备在具有提升至完整管理员权限的 Shell 中运行 Chocolatey,则很简单。尽管有说明如何在没有完全特权的情况下使 Chocolatey 工作,但几乎肯定会遇到问题。

要在 PowerShell 中使用Chocolatey,请下载其安装脚本并运行它。这需要管理员特权:

1
2
3
4
5
# download installation code
$code = Invoke-WebRequest -Uri 'https://chocolatey.org/install.ps1' -UseBasicParsing

# invoke installation code
Invoke-Expression $code

这步之后,您可以在 PowerShell 中使用新的“choco”命令。只需确保在提升权限的 Shell 中运行即可。

可以在此处找到可安装软件包的列表(例如 Acrobat Reader 或 Google Chrome):

https://chocolatey.org/packages

例如,要安装 Chrome 浏览器,请运行以下命令:

1
choco install googlechrome -y

同样,当您从未提升的 PowerShell 中运行“choco”时,您会收到一条警告消息,并且大多数软件包将无法正确安装。

评论

PowerShell 技能连载 - 获取原始的 PowerShell 语言说明书

PowerShell 团队曾经发布了丰富而详细的 PowerShell 3 语言参考,并且由于核心语言从未更改,因此该文档仍然非常有价值,并且充满了隐藏的宝藏。

既然文档仍然可用,就获取免费获取它:https://www.microsoft.com/en-us/download/confirmation.aspx?id=36389

评论

PowerShell 技能连载 - 下载 PowerShell 语言参考(或任意文件)

Invoke-WebRequest 可以轻松下载文件。下面的代码下载由 PowerShell Magazine 发布的PowerShell语言参考,并使用关联的程序将其打开:

1
2
3
4
5
6
7
8
9
10
11
12
13
$url = "https://download.microsoft.com/download/4/3/1/43113f44-548b-4dea-b471-0c2c8578fbf8/powershell_langref_v4.pdf"

# get desktop path
$desktop = [Environment]::GetFolderPath('Desktop')
$destination = "$desktop\langref.pdf"

# enable TLS1.2 for HTTPS connections
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12

# download PDF file
Invoke-WebRequest -Uri $url -OutFile $destination -UseBasicParsing
# open downloaded file in associated program
Invoke-Item -Path $destination

请注意这段代码如何启用 TLS 1.2。是否需要该协议取决于您的连接类型和防火墙。在以上示例中,并不是必须的。对于其它下载链接,可能是必须的。

评论

PowerShell 技能连载 - 在 Windows PowerShell 和 PowerShell Core 中共享模块

许多 PowerShell 用户开始研究 PowerShell 7,并与内置的 Windows PowerShell 并行运行。

两个 PowerShell 版本都在自己的位置维护各自的 PowerShell 模块。因此当您添加新模块(即通过 Install-Module)时,需要分别对两个版本的 PowerShell 执行此操作。

不过 Windows PowerShell 和 PowerShell 7 共享同一个文件夹路径:尽管是 Windows PowerShell 引入了该目录,但 PowerShell 7 也会检查此文件夹并自动加载位于其中的模块:

C:\Program Files\WindowsPowerShell\Modules

要在两个 PowerShell 版本中同时使用某个模块,请确保将模块复制到此文件夹。使用 Install-Module 时,请使用 -Scope AllUsers(或忽略整个参数)。

由于该文件夹影响所有用户,因此该文件夹受到保护,并且您需要管理员权限才能向其中添加模块。

请注意,PowerShell 还会在另外一个路径中查找模块:

C:\Windows\system32\WindowsPowerShell\v1.0\Modules

这是所有 Microsoft 模块所在的位置。该路径也会和 PowerShell 7 共享。

评论

PowerShell 技能连载 - 安装 ActiveDirectory 模块

这是一个对所有处理 Active Directory 的 PowerShell 用户的好消息:在最新的 Windows 10 版本(企业版、专业版)中,Microsoft 提供了 RSAT 工具,因此不需要另外下载。要将使用 AD 的 PowerShell 命令,只需启用 RSAT 功能(请参见下文)。

此外,PowerShell 7 终于原生支持 Active Directory 模块!如果您开始将新的 PowerShell 与Windows PowerShell 并行使用,则现在可以在 PowerShell 7 中使用以前仅在 Windows PowerShell 中工作的所有 AD cmdlet。

在提升权限的 PowerShell 中运行此命令,以查看可用的 RSAT 组件:

1
2
Get-WindowsCapability -Online |
Where-Object Name -like Rsat*

要使用 Active Directory 和组策略 PowerShell 模块,请启用 RSAT 功能

1
2
3
4
Get-WindowsCapability -Online |
Where-Object Name -like Rsat* |
Where-Object State -ne Installed |
Add-WindowsCapability -Online

完成后,Windows PowerShell 中将同时提供 Active DirectoryGroupPolicy PowerShell 模块。在 PowerShell 7 中,只能使用 ActiveDirectory 模块。

1
2
3
4
5
6
7
8
9
10
PS> Get-Module -Name ActiveDirectory, GroupPolicy -ListAvailable


Directory: C:\Windows\system32\WindowsPowerShell\v1.0\Modules


ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Manifest 1.0.1.0 ActiveDirectory {Add-ADCentralAccessPolicyMember, Add-ADCom...
Manifest 1.0.0.0 GroupPolicy {Backup-GPO, Block-GPInheritance, Copy-GPO...
评论

PowerShell 技能连载 - 测试等待重启

当 Windows 安装了更新或对操作系统做了相关改变,改变可能需要在重启以后才能生效。当有一个挂起的重启时,操作系统可能不能被完全保护,而且可能无法安装其它软件。

可以通过测试指定的注册表项来确定是否有挂起的重启:

1
2
3
$rebootRequired = Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"

"Pending reboot: $rebootRequired"

如果 $rebootRequired 的值是 $true,那么就存在一个挂起的重启。

评论