PowerShell 技能连载 - More Control with Strict Mode

有时,PowerShell 可能会出现意外行为。例如,当您输入一个不带引号的 IPv4 地址时,PowerShell 能够正常地接受它,但什么也不做。为什么?

1
PS> 1.2.3.4

在这种情况下,激活“严格模式”可能会有好处,当出现问题时会发出更严格的异常:

1
2
3
4
5
PS> Set-StrictMode -Version Latest

PS> 1.2.3.4
The property '3.4' cannot be found on this object. Verify that the property exists.
At line:1 char:1

启用严格模式后,PowerShell 会这样解释输入“1.2.3.4”:获取到浮点数 1.2,然后查询其中的 “3” 属性和其中的 “4” 属性。当然,这些属性是不存在的。禁用严格模式后,PowerShell 不会抱怨不存在的属性,只会返回“什么也没有”。这就是所发生的事情。

启用严格模式还有助于识别代码中的拼写错误。只需确保您在脚本开发机器上专门启用严格模式即可。永远不要将它添加到生产代码中。严格模式只是脚本开发人员的帮手。一旦脚本完成并移交给其他用户,请不要将开发工具留在其中。

Set-StrictMode 永远不应该放在您的代码中(并且始终以交互方式输入或作为配置文件脚本的一部分)的原因很简单:其他 PowerShell 脚本开发人员可能故意选择依赖松散的异常,并且当您的脚本强制严格模式,它也适用于从那里使用的所有代码(和模块)。在生产中启用严格模式可能会使运行良好的代码突然产生过多的红色异常。

评论

PowerShell 技能连载 - Managing Wi-Fi Profiles

On Windows, you can use old console commands to discover Wi-Fi profiles:

PS> netsh wlan show profiles  

From here, you can even view individual profile details and get to the cached clear text passwords. Yet all of this is console based, so it is not object oriented, requires a lot of string operations and may return unexpected information when profiles use special characters or your computer uses a different locale.

A much better approach is using the native Windows API. There is a public module available on PowerShell Gallery that you can use. Install it like this:

PS> Install-Module -Name WifiProfileManagement -Scope CurrentUser  

The rest is trivial. To dump all saved Wi-Fi profiles (including those with special characters in their name) use Get-WiFiProfile:

    PS C:\> Get-WiFiProfile 

ProfileName               ConnectionMode Authentication Encryption Password
-----------               -------------- -------------- ---------- --------
HOTSPLOTS_WR_Muehlenberg  manual         open           none
Zudar06_Gast              auto           WPA2PSK        AES
management                auto           WPA3SAE        AES
MagentaWLAN-X5HZ          auto           WPA3SAE        AES
Alando-Whg.17             auto           WPA2PSK        AES 
internet-cafe             auto           WPA2PSK        AES
Training                  manual         WPA2PSK        AES
QSC-Guest                 auto           open           none
ibisbudget                manual         open           none
Leonardo                  auto           open           none  
ROOMZ-GUEST               auto           open           none 
Freewave                  auto           open           none

Thumbsup

Thumbsup

Thumbsup

PS Saturday auto WPA2PSK AES
WIFIonICE manual open none
Airport Hotel auto WPA2PSK AES

And to see the cached Wi-Fi passwords, simply add the -ClearKey parameter. The cached passwords will now appear in clear text in the “Password” column.

Should you be interested to use this functionality directly inside your own code, simply look at the source code in the module. It is highly complex yet native PowerShell. Anyone looking for native API ways to talk directly to the Wi-Fi subsystem should dive into the code.

评论

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 技能连载 - Using Dynamic Help in PowerShell Console

评论

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 博客文章汇总 (2021-04 ~ 2022-03)

2021 年 04 月

2021 年 05 月

2021 年 06 月

2021 年 07 月

2021 年 08 月

2021 年 09 月

2021 年 10 月

2021 年 11 月

2021 年 12 月

2022 年

2022 年 01 月

2022 年 02 月

2022 年 03 月

评论

PowerShell 技术互动社区发展状况(2022 年 3 月)

至 2022 年 3 月,“PowerShell 技术互动”社区人数已达到 1998 人,十分接近社区最大容量(2000 人),保持 PowerShell 最大中文社区的位置。根据腾讯社交平台的策略,社区人数的上限为 2000 人,我们会尽可能保留机会给活跃用户。

QQ Group

如您遇到 PowerShell 方面的技术问题,或有好的资源希望分享,请加入我们。QQ 群号:271143343

或者用手机 QQ 扫描二维码:

QR

评论

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。对于此处示例中的简单二进制下载,该方法没有帮助。
评论