PowerShell 技能连载 - 探索文件夹结构(第 1 部分)

这是一个快速示例,说明了如何发现文件夹结构。本示例采用任何根文件夹路径,并递归遍历其子文件夹。

对于每个子文件夹,将返回一个新的自定义对象,其中包含文件和子文件夹计数以及相对的子文件夹路径:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# specify the folder that you want to discover
# $home is the root folder of your user profile
# you can use any folder: $path = 'c:\somefolder'
$path = $HOME

# find all subfolders...
Get-ChildItem $path -Directory -Recurse -ErrorAction Ignore |
ForEach-Object {
# return custom object with relative subfolder path and
# file count
[pscustomobject]@{
# use GetFiles() to find all files in folder:
FileCount = $_.GetFiles().Count
FolderCount = $_.GetDirectories().Count
FullName = $_.Fullname.Substring($path.Length+1)
}
}

PowerShell 技能连载 - 保存文本文件时去掉 BOM

在 Windows上,默认情况下,许多 cmdlet 使用BOM (Byte Order Mask) 编码对文本文件进行编码。 BOM 会在文本文件的开头写入一些额外的字节,以标记用于写入文件的编码。

不幸的是,BOM 编码在 Windows 世界之外并未得到很好的采用。如今,当您在 Windows 系统上保存文本文件并将其上传到 GitHub 时,BOM 编码可能会损坏文件或使其完全不可读。

以下是一段可用于确保以与 Linux 兼容的方式,在不使用 BOM 的情况下保存文本文件:

1
2
3
4
5
$outpath = "$env:temp\nobom.txt"
$text = 'This is the text to write to disk.'
$Utf8NoBomEncoding = [System.Text.UTF8Encoding]::new($false)
[System.IO.File]::WriteAllLines($outpath, $text, $Utf8NoBomEncoding)
$outpath

PowerShell 技能连载 - 信任自签名的 HTTPS 证书

如果您需要访问使用自签名测试证书或已过期或不可信的证书的 HTTPS 网站,PowerShell 将拒绝连接。在大多数情况下,这是正确的选择,但有时您知道目标服务器是安全的。

这是一段通过重写证书策略来信任所有 HTTPS 证书的 PowerShell 代码。新的证书策略始终返回 $true 并完全信任任何证书:

1
2
3
4
5
6
7
8
9
class TrustAll : System.Net.ICertificatePolicy
{
[bool]CheckValidationResult([System.Net.ServicePoint]$sp, [System.Security.Cryptography.X509Certificates.X509Certificate]$cert, [System.Net.WebRequest]$request, [int]$problem)
{
return $true
}
}

[System.Net.ServicePointManager]::CertificatePolicy = [TrustAll]::new()

PowerShell 技能连载 - 转换 Word 文档

现在仍然有许多旧文件格式(.doc 而不是 .docx)的 Microsoft Office 文档。

这是一个简单的 PowerShell 函数,它将旧的 .doc Word 文档转换为 .docx 格式并保存。如果未锁定旧的 Word 文档,则此过程是完全不可见的,并且可以在无人值守的情况下运行:

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
function Convert-Doc2Docx
{
param
(
[Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
[string]
[Alias('FullName')]
$Path,

[string]
$DestinationFolder

)
begin
{
$word = New-Object -ComObject Word.Application
}

process
{


$pathOut = [System.IO.Path]::ChangeExtension($Path, '.docx')
if ($PSBoundParameters.ContainsKey('DestinationFolder'))
{
$exists = Test-Path -Path $DestinationFolder -PathType Container
if (!$exists)
{
throw "Folder not found: $DestinationFolder"
}
$name = Split-Path -Path $pathOut -Leaf
$pathOut = Join-Path -Path $DestinationFolder -ChildPath $name
}
$doc = $word.Documents.Open($Path)
$name = Split-Path -Path $Path -Leaf
Write-Progress -Activity 'Converting' -Status $name
$doc.Convert()
$doc.SaveAs([ref]([string]$PathOut),[ref]16)
$word.ActiveDocument.Close()

}
end
{
$word.Quit()
}
}

PowerShell 技能连载 - 使用编码标准

使用文本文件时,务必始终使用相同的文本编码进行读取和写入,否则特殊字符可能会损坏,或者文本文件可能变得不可读,这一点很重要。

在 PowerShell 7 中,除非您指定其他编码,否则所有 cmdlet 以及重定向操作符都将使用默认的 UTF8 文本编码。那挺好的。

在W indows PowerShell 中,不同的 cmdlet 使用不同的默认编码。所以,要为所有 cmdlet 和重定向操作符建立通用的默认默认编码,您应该为带有参数 -Encoding 的任何命令设置默认参数值。

将以下行放入您的配置文件脚本中:

1
$PSDefaultParameterValues.Add('*:Encoding', 'UTF8')

此外,在 Windows PowerShell 中,无论 cmdlet 是否具有参数 -Encoding,都指定一个唯一的值。当前推荐的编码为UTF8。

PowerShell 技能连载 - 修复 VSCode PowerShell 问题(第 2 部分)

如果在编辑 PowerShell 脚本时 VSCode 不会启动 PowerShell 引擎,而状态栏中的黄色消息“正在启动 PowerShell”不会消失,则可能的解决方法是使用全新独立的可移植 PowerShell 7 安装作为 VSCode 中的默认 PowerShell 引擎。

首先,运行以下这行代码以创建 Install-PowerShell cmdlet :

1
Invoke-RestMethod -Uri https://aka.ms/install-powershell.ps1 | New-Item -Path function: -Name Install-PowerShell | Out-Null

接下来,在本地文件夹中安装 PowerShell 7 的新副本,例如:

1
Install-PowerShell -Destination c:\portablePowerShell

安装完成后,请确保可以手动启动新的 PowerShell 实例:

1
c:\portablePowerShell\pwsh

现在,继续告诉 VSCode,您要在编辑 PowerShell 脚本时使用此新的 PowerShell 实例运行:在 VSCode 中,选择“文件/首选项/设置”,单击设置左栏中的“扩展”,然后单击子菜单中的“PowerShell 配置”。

接下来,搜索设置“PowerShell 默认版本”,然后输入任何名称,即“portable PowerShell 7”。在上面的“PowerShell Additional Exe Paths”部分中,单击链接“Edit in settings.json”。这将以 JSON 格式打开原始设置文件。

其中,新设置部分已经插入,需要像这样完成:

1
2
3
4
5
6
"powershell.powerShellAdditionalExePaths": [
        {
            "exePath": "c:\\portablePowerShell\\pwsh.exe",
            "versionName": "portable PowerShell 7"
        }
    ]

注意:所有标记和关键字均区分大小写,并且在路径中,反斜杠需要由另一个反斜杠转义。在 “exePath” 中,在下载的可移植 PowerShell 文件夹中指定 pwsh.exe 文件的路径。确保路径不仅指向文件夹,而且指向 pwsh.exe

在 “versionName” 中,使用之前在 “PowerShell Default Version” 中指定的相同标签名称。

保存 JSON 文件后,重新启动 VSCode。该编辑器现在使用您的 portable PowerShell 7,并且在许多情况下,这解决了 PowerShell 启动卡住的问题。

如果您想手动将其他 PowerShell 版本添加到 VSCode,则上面的方法也很有用。当您单击 VSCode 状态栏中的绿色 PowerShell 版本时,任何手动添加的 PowerShell 将出现在选择对话框中(除非已被使用,在这种情况下,该菜单将显示 PowerShell 类型和版本,而不是您的标签名称)。

PowerShell 技能连载 - 修复 VSCode PowerShell 问题(第 1 部分)

有时,VSCode 在尝试启动 PowerShell 引擎时停止,或者报告诸如 “Language Server Startup failed” 之类的错误。

如果您遇到后一种异常,则可能与企业中的安全设置有关。要解决此问题,请在 PowerShell 控制台中运行以下行(这是一长行代码):

1
Import-Module $HOME\.vscode\extensions\ms-vscode.powershell*\modules\PowerShellEditorServices\PowerShellEditorServices.psd1

如果您没有得到提示,那么这不是造成问题的原因。如果确实收到提示要求确认导入此模块的提示,则只需允许运行“来自不受信任的发布者的软件”。该确认仅需要一次,因此下次 VSCode 尝试使用此模块启动 PowerShell 引擎时,很可能会解决您的问题。

PowerShell 技能连载 - 查找 PowerShell 命令

Get-Command 可以帮助您查找给定任务的 PowerShell 命令,但是此 cmdlet 只能搜索命令名称和参数中的关键字。

可以从 PowerShell Gallery 中安装更复杂的搜索命令:

1
Install-Module -Name PSCommandDiscovery -Scope CurrentUser -Verbose

Find-PowerShellCommand 使用关键字并返回与此关键字相关的所有命令。它在命令名称,命令参数以及返回的对象属性中搜索关键字。如果找到的命令类型是已编译的应用程序,则该命令还将返回命令的类型(GUI 或基于控制台的命令)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS> Find-PowerShellCommand -Keyword user -CommandType Function,Cmdlet,Application

Command MatchType Member
------- --------- ------
Add-WinADUserGroups CommandName
Get-ComputerInfo Property [string] CsUserName (read/write)
Get-ComputerInfo Property [Nullable`1[[System.UInt32, Syst
Get-ComputerInfo Property [Nullable`1[[System.UInt32, Syst
Get-ComputerInfo Property [string] OsRegisteredUser (read/…
Get-ComputerInfo Property [Nullable`1[[Microsoft.PowerShel
Get-Credential Property [string] UserName (readonly)
Get-Culture Property [bool] UseUserOverride (readonly)
Get-LocalUser CommandName
Get-PnPAADUser CommandName
Get-PnPTeamsUser CommandName
Get-PnPUser CommandName
Get-PnPUserOneDriveQuota CommandName
Get-PnPUserProfileProperty CommandName
Get-Process Property [timespan] UserProcessorTime (re
Get-UICulture Property [bool] UseUserOverride (readonly)
DevModeRunAsUserConfig.msc Command .msc: DevModeRunAsUserConfig (Un
DsmUserTask.exe Command .exe: DsmUserTask (x64) [Gui] 10
quser.exe Command .exe: quser (x64) [Console] 10.0
(...)

MatchType“ 属性报告匹配的种类。可以根据命令名称,参数名称或返回对象的任何属性名称中的关键字匹配找到命令。

有关其他示例,源代码和所有参数的说明,请参见 https://github.com/TobiasPSP/PsCommandDiscovery

PowerShell 技能连载 - 修复 Install-Module (PowerShellGet)

使用 Install-Module ,您可以轻松地从 PowerShell Gallery (www.powershellgallery.com) 下载和安装其他 PowerShell 模块。但是,在 Windows 系统上,此命令可能会中断。许多 Windows 系统仍随附 1.x 版本,并且 PowerShell Gallery 已切换到 Internet 协议 TLS 1.2,较早的 Windows 版本不会自动支持该协议。

要解决 Install-Module 的问题,您应确保 PowerShell 可以使用 TLS 1.2 来访问 PowerShell Gallery:

1
2
3
[System.Net.ServicePointManager]::SecurityProtocol =
[System.Net.ServicePointManager]::SecurityProtocol -bor
[System.Net.SecurityProtocolType]::Tls12

接下来,您应该像这样手动重新安装 PowerShellGet 和 Packagemanagement 模块的当前版本(不需要管理员权限):

1
2
Install-Module -Name PowerShellGet -Scope CurrentUser -Force -AllowClobber
Install-Module -Name Packagemanagement -Scope CurrentUser -Force -AllowClobber

这应该能为大多数用户解决问题。

如果根本无法使用 Install-Module,则可以手动将 PowerShellGet 和 Packagemanagement 的模块文件夹从更新的 Windows 版本复制到另一个版本。运行以下行以查找可以在何处找到最新版本的 PowerShellGet:

1
Get-Module -Name powershellget -ListAvailable | Sort-Object -Property Version -Descending | Select-Object -First 1

最新版本是 2.2.5,并且您不应使用低于 2.x 的版本。如果您的 PowerShell 报告系统上同时存在版本 1.x 和 2.x,则一切正常。PowerShell始终会自动选择最新版本。

PowerShell 技能连载 - 跨平台的 Out-GridView

Out-GridView 是最常用的 cmdlet 之一,它会打开一个通用选择对话框。不幸的是,PowerShell 只能在 Windows 操作系统上显示图形元素,例如窗口。在 Linux 和 macOS 上,图形 cmdlet(例如 Out-GridView)不可用。

您可能想尝试使用新的基于文本的 Out-ConsoleGridView。此 cmdlet 仅适用于PowerShell 7(在Windows PowerShell中不起作用)。像这样安装它:

1
Install-Module -Name Microsoft.PowerShell.ConsoleGuiTools -Scope CurrentUser

安装完成后,在许多情况下,您现在可以轻松地将 Out-GridView 替换为 Out-ConsoleGridView,并享受类似于旧版 Norton Commander 的基于文本的选择对话框。这是旧版 Windows PowerShell 脚本,无法在 Linux 上使用:

1
2
3
4
5
6
Get-Process |
Where-Object MainWindowHandle |
Select-Object -Property Name, Id, Description |
Sort-Object -Property Name |
Out-GridView -Title 'Prozesse' -OutputMode Multiple |
Stop-Process -WhatIf

只需将 Out-GridView 替换为 Out-ConsoleGridView,便一切就绪。