PowerShell 技能连载 - Automating User Confirmation

Some commands seem to require user input no matter what. While you can try parameters such as -Confirm:$false to get rid of default confirmations, some commands either do not support that parameter, or show their very own user requests. Here is an example:

PS> Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

When you run this command (elevated) on Windows 10 or 11, at the end of the process the cmdlet wants to know whether a restart is OK:

Do you want to restart the computer to complete this operation now?
[Y] Yes  [N] No  [?] Help (default is "Y"):

The cmdlet halts until the user either enters “Y” or “N”.

To fully automate cmdlets like this, either take a closer look at its remaining parameters. Often, there are ways to articulate your choice and leave no room for ambiguities that need manual resolution. In the example above, by adding “-NoRestart”, you could deny automatic restarts and then explicitly restart the machine using Restart-Computer.

Or, you can pipe user input to a new PowerShell instance. PowerShell takes the input and places it into the keyboard input buffer. Whenever a command requests user input, it is taken from this buffer. Use comma-separated values to submit multiple items of user input to PowerShell.

Here is an example illustrating how you can submit a “N” to the command above:

PS> "N" | powershell.exe -noprofile -command Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Hyper-V -All

PowerShell 技能连载 - Using Predictive IntelliSense

Predictive IntelliSense is a new feature in PSReadLine 2.1 and was improved in version 2.2. As such, it is available in all PowerShell consoles starting in PowerShell version 5.1. If you are uncertain whether your PowerShell console is using the latest version of PSReadLine, try this:

PS> Update-Module -Name PSReadLine

If you can’t update the module because it shipped with Windows, or you are missing privileges, try and freshly install it like so:

PS> Install-Module -Name PSReadLine -Scope CurrentUser -Force

Next, restart you PowerShell console.

The reason why you may not have heard anything about “predictive IntelliSense” is that it is turned off by default. To turn it on, run this:

PS> Set-PSReadLineOption -PredictionSource HistoryAndPlugin

In Windows PowerShell, you are limited to the option “History” only:

PS> Set-PSReadLineOption -PredictionSource History

Immediately thereafter, when you type commands in your console, you start seeing shadowed (darker) IntelliSense suggestions while you type. These suggestions are taken primarily from your command history so PowerShell starts suggesting command parameters that you commonly use. The auto-suggestion is an individualized experience, and the actual suggestions depend on your previous PowerShell commands:

PS> Get-Service | import-database -Database $db

If you don’t like this “real-time” IntelliSense, turn it off again like so:

PS> Set-PSReadLineOption -PredictionSource None

PowerShell 技能连载 - Update PowerShell’s PSReadLine

Do you know the PSReadLine module? It’s included in PowerShell 5 and 7 by default, and this module is responsible for the convenient color coding in PowerShell consoles, among a number of additional benefits that makes handling code easier. PowerShell loads this module by default in console-based environments (it’s not being used in the PowerShell ISE).

To check the current version, run this:

PS> try { (Get-Module -Name PSReadLine).Version.ToString() } catch { Write-Warning 'PSReadLine not used in this host' }
2.1.0

The line either returns the current PSReadLine version used by your PowerShell host, or emits a warning that PSReadline isn’t used by your host (i.e. inside the PowerShell ISE host which takes care of color coding internally).

You should make sure you are using the latest version of PSReadline. This line would try and update it to the latest version:

PS> Update-Module -Name PSReadLine

Just in case you can’t update the module because it shipped with Windows, try and freshly install it like so:

PS> Install-Module -Name PSReadLine -Scope CurrentUser -Force

Make sure you relaunch PowerShell after you have updated PSReadLine to load the latest version.

PSReadLine comes with powerful new features such as “predictive IntelliSense” and dynamic help that are explained here: https://devblogs.microsoft.com/powershell/psreadline-2-2-ga/

ReTweet this Tip!

PowerShell 技能连载 - 在 PowerShell 使用高效的列表

默认情况下,当您定义列表、命令返回多个结果或需要在变量中存储多个内容时,PowerShell 使用简单的“对象数组”。

默认对象数组是可以的,但是一旦你创建了它们,它们的容量就不能增长。如果仍然尝试使用 “+=“ 运算符,脚本可能会突然花费很长时间或永远不会完成:

1
2
3
4
5
6
7
8
9
10
# default array
$array = @()

1..100000 | ForEach-Object {
# += is actually creating a new array each time with one more entry
# this is very slow
$array += "adding $_"
}

$array.count

那是因为 “+=“ 其实是个谎言,PowerShell 实际上需要创建一个新的更大的数组并将内容从旧数组复制到新数组。如果只是几个元素,那么还好但是如果要添加的元素较多,就会导致指数级延迟。

最常见的解决方法是使用可以动态增长的 System.Collections.ArrayList 类型。您可以简单地将默认数组强制转换为这种类型。

这是一种常用的方法,速度更快:

1
2
3
4
5
6
7
8
9
10
# use a dynamically extensible array
$array = [System.Collections.ArrayList]@()

1..100000 | ForEach-Object {
# use the Add() method instead of "+="
# discard the return value provided by Add()
$null = $array.Add("adding $_")
}

$array.count

请注意它如何使用 Add() 方法而不是 “+=“ 运算符。

不过,System.Collections.ArrayList 有两个缺点:它的 Add() 方法返回添加新元素的位置,并且由于此信息没有意义,因此需要手动丢弃它,即将其分配给 $null。并且 ArrayLists 不是特定于类型的。它们可以存储任何数据类型,这使得它们虽然灵活但效率不高。

泛型列表要好得多,使用它们只是使用不同类型的问题。一方面,泛型列表可以限制为给定类型,因此它们可以以最有效的方式存储数据并提供类型安全。以下是字符串列表的示例:

1
2
3
4
5
6
7
8
9
10
# use a typed list for more efficiency
$array = [System.Collections.Generic.List[string]]@()

1..100000 | ForEach-Object {
# typed lists support Add() as well but there is no
# need to discard a return value
$array.Add("adding $_")
}

$array.count

如果您需要一个整形列表,只需替换泛型列表类型名称中的类型:

1
[System.Collections.Generic.List[int]]

强类型限制只是“可以”,而不是“必须”。如果您希望泛型列表与 ArrayList 一样灵活并接受任何类型,请使用 “object“ 类型:

1
[System.Collections.Generic.List[object]]

PowerShell 技能连载 - 从 Internet 下载文件

Invoke-WebRequest 不仅能向 web 服务发送请求。此 cmdlet 可以与远程系统通信并来回传输数据。这就是为什么您可以使用它以非常简单直接的方式从 Internet 下载文件:

1
2
3
4
5
6
7
$url = 'https://www.nasa.gov/sites/default/files/thumbnails/image/iss065e009613.jpg'
$destination = "$env:temp\picture_nasa.jpg"

Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $destination


Invoke-Item -Path $destination

第一部分下载 NASA 图片并将其保存在本地,下一部分在您的默认查看器中打开下载的图像。

请注意,Invoke-WebRequest 可能不适用于较旧的网络和 TLS 协议。

这里还有两点需要注意:

  • -UseBasicParsing 阻止 cmdlet 使用旧的和已弃用的 “Internet Explorer” 对象模型,这种方法在近期可能导致问题。使用 IE 库从网站解析原始 HTML 曾经很有用。
  • Invoke-WebRequest 有个大哥叫 Invoke-RestMethod。两者的工作方式相同,但 Invoke-RestMethod 会自动将下载的数据转换为正确的格式,即 XML 或 JSON。对于此处示例中的简单二进制下载,该方法没有帮助。

PowerShell 技能连载 - Defender: 清空威胁列表和相关设置

默认情况下,Windows Defender 会在 15 天后自动清除它识别为威胁的项目。可以使用 PowerShell 直接配置此首选项以及许多其他首选项。只需确保启动提升权限的 PowerShell。

此示例查询清除间隔,然后设置新的清除时间间隔并对其进行验证:

1
2
3
4
5
6
7
PS> (Get-MpPreference).ScanPurgeItemsAfterDelay
15

PS> Set-MpPreference -ScanPurgeItemsAfterDelay 10

PS> (Get-MpPreference).ScanPurgeItemsAfterDelay
10

PowerShell 技能连载 - 复位防火墙策略

如果您想在 Windows 10 或 11 上将防火墙规则恢复为出厂默认设置,请让 PowerShell 运行相应的 netsh.exe 命令:

1
PS> netsh advfirewall reset

需要提升权限的 PowerShell。该命令将撤消自安装操作系统以来您(或安装程序)对 Windows 防火墙所做的任何更改。

PowerShell 技能连载 - 复位防火墙策略

如果您想在 Windows 10 或 11 上将防火墙规则恢复为出厂默认设置,请让 PowerShell 运行相应的 netsh.exe 命令:

1
PS> netsh advfirewall reset

需要提升权限的 PowerShell。该命令将撤消自安装操作系统以来您(或安装程序)对 Windows 防火墙所做的任何更改。

PowerShell 技能连载 - 管理 Bitlocker

最好确保笔记本上的本地驱动器已加密。这可以保护您的个人数据,以防有一天笔记本被盗或被丢入垃圾堆中。

大多数现代商务笔记本都配备 TPM 芯片并支持硬盘驱动器的实时加密。Windows 附带管理硬盘加密的 PowerShell 模块 “Bitlocker”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
PS> Get-Command -Module bitlocker

CommandType Name Version Source
----------- ---- ------- ------
Function Add-BitLockerKeyProtector 1.0.0.0 bitlocker
Function Backup-BitLockerKeyProtector 1.0.0.0 bitlocker
Function BackupToAAD-BitLockerKeyProtector 1.0.0.0 bitlocker
Function Clear-BitLockerAutoUnlock 1.0.0.0 bitlocker
Function Disable-BitLocker 1.0.0.0 bitlocker
Function Disable-BitLockerAutoUnlock 1.0.0.0 bitlocker
Function Enable-BitLocker 1.0.0.0 bitlocker
Function Enable-BitLockerAutoUnlock 1.0.0.0 bitlocker
Function Get-BitLockerVolume 1.0.0.0 bitlocker
Function Lock-BitLocker 1.0.0.0 bitlocker
Function Remove-BitLockerKeyProtector 1.0.0.0 bitlocker
Function Resume-BitLocker 1.0.0.0 bitlocker
Function Suspend-BitLocker 1.0.0.0 bitlocker
Function Unlock-BitLocker 1.0.0.0 bitlocker

确保在尝试任何这些命令之前启动提升权限的 PowerShell。例如,Get-BitlockerVolume 转储当前设置和保护状态:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PS> Get-BitLockerVolume | Select-Object -Property *


ComputerName : DELL7390
MountPoint : C:
EncryptionMethod : XtsAes128
AutoUnlockEnabled :
AutoUnlockKeyStored : False
MetadataVersion : 2
VolumeStatus : FullyEncrypted
ProtectionStatus : On
LockStatus : Unlocked
EncryptionPercentage : 100
WipePercentage : 0
VolumeType : OperatingSystem
CapacityGB : 938,0381
KeyProtector : {Tpm, RecoveryPassword}

该 cmdlet 显示当前的保护状态、采用的保护方法,EncryptionPercentage 指示加密是已完成还是仍在处理您的数据。

如果您的硬盘驱动器未加密,则应首先阅读有关 TPM 和加密的更多信息。虽然您可以使用 Enable-Bitlocker 开始加密您的硬盘驱动器,但重要的是您要完全了解所有加密原理,以免意外地把自己的电脑锁定。