PowerShell 技能连载 - 识别 PowerShell 宿主和路径

这是一个快速的单行代码,用于标识当前 PowerShell 宿主的完整路径:

1
2
PS> (Get-Process -Id $pid).Path
C:\Program Files\PowerShell\7\pwsh.exe

该路径会告诉您当前宿主的位置,并且您可以检查代码是否在 Windows PowerShell、PowerShell 7 或PowerShell ISE 中执行。

用类似的方法,您还可以按名称查找可执行文件的路径。例如,如果您想知道 PowerShell 7 在系统上的安装位置,请尝试以下操作:

1
2
PS C:\> (Get-Command -Name pwsh).Source
C:\Program Files\PowerShell\7\pwsh.exe

当然,如果找不到可执行文件,此行将产生错误。它必须位于 $env:path 中列出的文件夹之一中。

PowerShell 技能连载 - 使用在线帮助(第 2 部分)

在上一个技能中,我们提到许多 PowerShell 用户更喜欢在线帮助,而不是本地下载的帮助。要默认使用联机帮助文档,请在新的 PowerShell 控制台中尝试以下操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# by default, -? opens LOCAL help
PS> dir -?

NAME
Get-ChildItem

SYNOPSIS
Gets the items and child items in one or more specified locations.


SYNTAX
...


# with this line you tell PowerShell to use the ONLINE help by default
PS> $PSDefaultParameterValues.Add("Get-Help:Online",$true)

# now, whenever you use -?, the ONLINE help opens in a nicely formatted browser window
PS> dir -?

使用 $PSDefaultParameterValues.Add("Get-Help:Online",$true) 命令告诉 PowerShell,Get-Help 命令应始终自动使用 -Online 参数,因此现在您始终可以获得基于浏览器的帮助。

尽管在大多数情况下这很好,但是联机帮助无法自动显示主题。如果需要显示有关主题的信息,只需使用 Get-Help 或带有 -ShowWindow 参数的帮助以显示本地帮助:

1
2
3
4
5
6
# this fails when help defaults to show ONLINE help
PS> help about_for
Get-Help : The online version of this Help topic cannot be displayed because the Internet address (URI) of the Help topic is not specified in the command code or in the help file for the command.

# the -ShowWindow parameter always shows local help in an extra window
PS C:\> help about_for -ShowWindow

PowerShell 技能连载 - 使用在线帮助(第 1 部分)

PowerShell 支持本地帮助文件和联机资源。请看区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# outputs help in same console window
# level of detail depends on whether local help was
# downloaded using Update-Help
PS C:\> help -Name Get-Process

NAME
Get-Process

SYNOPSIS
Gets the processes that are running on the local computer or a remote computer.


SYNTAX
Get-Process [[-Name] <String[]>] [-ComputerName <String[]>] [-FileVersionInfo] [-Module] []
...

# opens help in separate browser window
PS> help -Name Get-Process -Online

默认情况下,”help“(Get-Help 的别名)将帮助信息输出到 PowerShell 的输出窗口中。指定 -Online 开关参数时,浏览器会在单独的窗口中显示帮助文件。在线帮助文​​档采用了较好的格式,并且可以通过“复制”按钮轻松地复制和粘贴示例代码。并且由于联机文档是直接从 Microsoft 加载的,因此它们始终是最新的,因此无需通过 Update-Help 下载帮助。

这就是为什么许多用户喜欢在线帮助资源而不是本地帮助的原因。

线上还有许多有用的“关于”主题。关于主题涵盖了 PowerShell 语言和引擎的各个方面。您会在此处找到所有有关主题的很好的分类:https://docs.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about

PowerShell 技能连载 - 在没有管理员特权的情况下更新帮助

在 Windows PowerShell 中,由于设计缺陷,更新帮助曾经需要管理员权限:帮助必须存储在模块所在的位置。更新 Windows 文件夹中存储的 Microsoft 模块的帮助需要对 Windows 文件夹的写权限。这就是普通用户无法下载和使用本地 PowerShell 帮助的原因。

在 PowerShell 7 中,此设计缺陷已得到纠正,现在可以将帮助安全地存储在用户配置文件中。不再需要涉及 PowerShell 模块的安装文件夹。

在 PowerShell 7 中使用 -Verbose 参数运行 Update-Help 以查看更改:

1
2
3
4
5
6
7
8
9
10
11
PS> Update-Help -Verbose
VERBOSE: Resolving URI: "https://go.microsoft.com/fwlink/?LinkId=717973"
VERBOSE: Your connection has been redirected to the following URI:
"https://pshelpprod.blob.core.windows.net/cabinets/powershell-5.1/"
VERBOSE: Performing the operation "Update-Help" on target "Microsoft.PowerShell.LocalAccounts, Current Version: 5.2.0.0, Available Version: 5.2.0.0, UICulture: en-US".
VERBOSE: Microsoft.PowerShell.LocalAccounts: Updated C:\Users\USERNAME\Dokumente\PowerShell\Help\Microsoft.PowerShell.LocalAccounts\1.0.0.0\en-US\Microsoft.Powershell.LocalAccounts.dll-Help.xml. Culture en-US Version 5.2.0.0
VERBOSE: Resolving URI: "https://go.microsoft.com/fwlink/?linkid=2113632"
VERBOSE: Your connection has been redirected to the following URI: "https://pshelp.blob.core.windows.net/powershell/help/7.0/Microsoft.PowerShell.Management/"
VERBOSE: Performing the operation "Update-Help" on target "Microsoft.PowerShell.Management, Current Version: 7.0.1.0, Available Version: 7.0.1.0, UICulture: en-US".
VERBOSE: Microsoft.PowerShell.Management: Updated C:\Users\USERNAME\Dokumente\PowerShell\Help\en-US\Microsoft.PowerShell.Commands.Management.dll-Help.xml. Culture en-US Version 7.0.1.0
...

要使用下载的本地帮助文件,您可以在想了解的命令后添加 “-?“ 通用参数:

1
2
3
4
5
6
7
8
PS> Get-Process -?

NAME
Get-Process

SYNOPSIS
Gets the processes that are running on the local computer or a remote computer.
...

如果您之前未下载本地帮助文件,则 “-“ 参数仅显示有限的语法帮助。

PowerShell 技能连载 - PowerShell技能连载-检查配置文件脚本(第 2 部分)

在上一个脚本中,我们介绍了一一行代码,用于检查哪些配置文件脚本是存在的。但是,此解决方案仅只适用于单个宿主,因为每个宿主都使用自己的特定于宿主的配置文件路径。

这是一种更通用的方法:它列出了系统上存在的所有 PowerShell 宿主的所有配置文件路径。然后,您可以在安全性或健全性检查中检查以下文件:

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
# calculate the parent paths that can contain profile scripts
$Paths = @{
AllUser_WPS = $pshome
CurrentUser_WPS = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath "WindowsPowerShell"
AllUser_PS = "$env:programfiles\PowerShell\*"
CurrentUser_PS = Join-Path -Path ([Environment]::GetFolderPath('MyDocuments')) -ChildPath "PowerShell"
}

# check all paths for PowerShell scripts ending on "profile.ps1"
$Paths.Keys | ForEach-Object {
$key = $_
$path = Join-Path -Path $paths[$key] -ChildPath '*profile.ps1'
Get-ChildItem -Path $Path |
ForEach-Object {
# create a custom object with all relevant details for any
# found profile script

# name of PowerShell host is the prefix of profile file name
if ($_.Name -like '*_*')
{
$hostname = $_.Name.Substring(0, $_.Name.Length-12)
}
else
{
$hostname = 'any'
}
[PSCustomObject]@{
# scope and PowerShell version is found in the
# name of the parent folder
Scope = $key.Split('_')[0]
PowerShell = $key.Split('_')[1]

Host = $hostname
Path = $_.FullName
}
}
}

结果报告了所有主机的现有 PowerShell 配置文件脚本,看起来可能与此类似:

Scope       PowerShell Host                    Path
-----       ---------- ----                    ----
CurrentUser WPS        Microsoft.PowerShellISE C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\Microsoft.PowerShellISE_...
CurrentUser WPS        any                     C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\profile.ps1
CurrentUser PS         Microsoft.VSCode        C:\Users\tobia\OneDrive\Dokumente\PowerShell\Microsoft.VSCode_profile.ps1

PowerShell 技能连载 - PowerShell技能连载-检查配置文件脚本(第 1 部分)

PowerShell 最多使用四个配置文件脚本。当它们存在时,PowerShell 在启动时会静默执行所有内容。

重要的是要知道存在哪个配置文件脚本(如果有),因为它们的内容会减慢 PowerShell 的启动时间,并且恶意代码可以使用它们来偷偷运行。

手动测试配置文件路径可能很麻烦。这是一行有趣的代码,可以为您完成工作:

1
$profile.PSObject.Properties.Name | Where-Object { $_ -ne 'Length' } | ForEach-Object { [PSCustomObject]@{Profile=$_; Present=Test-Path $profile.$_; Path=$profile.$_}}

结果看起来像这样:

Profile                Present Path
-------                ------- ----
AllUsersAllHosts         False C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
AllUsersCurrentHost      False C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1
CurrentUserAllHosts      False C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\profile.ps1
CurrentUserCurrentHost    True C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1

PowerShell 技能连载 - 使用 Profile 脚本

配置文件脚本的工作方式类似于 PowerShell 中的自动启动脚本。它们不一定存在,但是如果存在,PowerShell 会在每次启动时静默执行其内容。最多有四个配置文件脚本,此行代码显示它们的路径:

1
2
3
4
5
6
7
PS> $profile | Select-Object -Property *

AllUsersAllHosts : C:\Windows\System32\WindowsPowerShell\v1.0\profile.ps1
AllUsersCurrentHost : C:\Windows\System32\WindowsPowerShell\v1.0\Microsoft.PowerShellISE_profile.ps1
CurrentUserAllHosts : C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1
Length : 87

不必担心属性 “Length”:它是基于 $profile 是字符串这一事实的产物。PowerShell已在其中添加了四个属性,以返回受支持的配置文件的路径。

请注意,任何包含 “AllHosts” 的配置文件的路径对于所有 PowerShell 宿主都是相同的。您添加到其中的任何内容都可以在任何宿主中执行,包括 powershell.exe、PowerShell ISE、Visual Studio Code 或 PowerShell 7。包含 “CurrentHost” 的属性中的路径仅限于正在执行此行代码的宿主。

默认情况下,所有这些路径哪儿也不指向。要使用一个或多个,请确保创建了路径指向的文件。

PowerShell 技能连载 - 识别用户 Profile

使用 $envuserprofile$home 创建用户文件的路径时要小心。当使用了 OneDrive,文档文件夹可能已重定向到名为“ OneDrive”的子文件夹。这里有些例子:

1
2
3
4
5
6
7
8
9
10
PS> $env:USERPROFILE
C:\Users\tobia

PS> $HOME
C:\Users\tobia

PS> $profile
C:\Users\tobia\OneDrive\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1

PS>

如您所见,PowerShell 配置文件脚本并不直接位于用户配置文件内的 Documents 文件夹中。而是将其改为名为 “OneDrive” 的子文件夹。

要查找当前的 Documents 文件夹,请改用 GetFolderPath()

1
2
PS> [Environment]::GetFolderPath('MyDocuments')
C:\Users\tobia\OneDrive\Documents

您甚至可以使用它来确定 OneDrive 是否重定向了用户文件:

1
2
$redirected = [Environment]::GetFolderPath('MyDocuments') -like '*\OneDrive\*'
$redirected

当 OneDrive 重定向文件夹时,此命令返回 $true,否则返回 $false

PowerShell 技能连载 - 摆脱 Get-EventLog

Get-EventLog 命令可以轻松访问主要的 Windows 事件日志中的事件日志条目,但是它既不能访问许多应用程序级事件日志,也不能在PowerShell 7中使用。

如果计划在 PowerShell 7 中运行代码,则应该开始习惯其后继程序:Get-WinEvent。此cmdlet功能强大,并支持许多参数。这是一个类似于 Get-EventLog 的示例:

1
2
3
Get-WinEvent -FilterHashtable @{Logname = 'System';Level=2,3} -MaxEvents 10 |
Select-Object TimeCreated, LevelDisplayName, Id, ProviderName, Message |
Format-Table

您的查询以哈希表的形式提交,您可以看到如何指定日志名称和想要获取的事件数量。与 Get-EventLog 相比,您现在可以指定和检索任何日志,而不仅仅是少数经典日志。您可能需要运行 Show-EventLog 来打开事件日志查看器,并发现许多可用的应用程序级别的日志。

哈希表 “Level” 键定义您要查看的事件日志条目的类型。数字越低,条目越严重。“2” 代表错误,“3”代表警告。如您所见,您可以将级别组合为逗号分隔的列表。

结果看起来像这样:

TimeCreated         LevelDisplayName    Id ProviderName                     Message
-----------         ----------------    -- ------------                     -------
04.08.2020 13:03:42 Warning          10016 Microsoft-Windows-DistributedCOM The Anwendungsspezifisch permission settings do...
04.08.2020 13:03:20 Error                1 MTConfig                         An attempt to configure the input mode of a mul...
04.08.2020 13:03:19 Error                1 MTConfig                         An attempt to configure the input mode of a mul...
04.08.2020 12:58:18 Error                1 MTConfig                         An attempt to configure the input mode of a mul...
04.08.2020 11:53:38 Error            10010 Microsoft-Windows-DistributedCOM The server Microsoft.SkypeApp_15.61.100.0_x86__...
04.08.2020 11:23:48 Error            10010 Microsoft-Windows-DistributedCOM The server microsoft.windowscommunicationsapps_...
04.08.2020 11:23:41 Error            10010 Microsoft-Windows-DistributedCOM The server Microsoft.SkypeApp_15.61.100.0_x86__...
04.08.2020 11:23:37 Warning            701 Win32k                           Power Manager has not requested suppression of ...
04.08.2020 11:23:37 Warning            701 Win32k                           Power Manager has not requested suppression of ...
04.08.2020 11:23:37 Error            10317 Microsoft-Windows-NDIS           Miniport Microsoft Wi-Fi Direct Virtual Adapter...

PowerShell 技能连载 - 设置和清除信任的主机

PowerShell 远程处理在客户端(发出命令并在服务器上进行身份验证的计算机)上维护受信任的 IP 地址和/或计算机名称的列表。此列表对您很重要,因为它控制着您如何对远程计算机进行身份验证。

默认情况下,PowerShell 仅支持 Kerberos 身份验证,因为它最安全,并且可以同时对客户端和服务器进行身份验证。但是,它需要一个 Active Directory,并且不能与 IP 地址一起使用。

1
2
# execute PowerShell code remotely
Invoke-Command { Get-Service } -ComputerName storage2 -Credential AdminUser

在此示例中,AdminUser 必须是在 storage2 上具有适当权限才能访问的域帐户。

通过将 IP 地址和/或计算机名称添加到 TrustedHosts,您也可以使用 NTLM身份验证。这样,您可以使用本地帐户进行身份验证,并使用远程帐户访问独立系统,域外的系统以及通过IP地址指定的系统。

也允许使用通配符,因此当将 TrustedHosts 设置为 “*” 时,任何计算机都可以使用 NTLM 身份验证。但是,这并不太明智,因为现在黑客可以断开服务器并用另一台机器代替它来捕获密码,因为您不会注意到它不再是您要访问的机器。因此,仅对于您知道的位于“信任”的安全环境中的计算机,对 TrustedHosts 进行更改。

仅管理员和 WinRM 服务运行时才能访问 TrustedHosts 列表。启动提升的 PowerShell 环境,并确保 WinRM 服务正在运行:

1
PS> Start-Service -Name WinRM

要查看 TrustedHosts 的当前内容,请运行以下命令:

1
2
3
4
5
6
7
8
PS> Get-ChildItem -Path WSMan:\localhost\Client\TrustedHosts


WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client

Type Name SourceOfValue Value
---- ---- ------------- -----
System.String TrustedHosts

默认情况下,列表为空。要重置其内容(即指定IP范围),请使用 Set-Item

1
PS> Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value 192.168.* -Force

要添加更多条目,请添加 -Concatenate 参数。这将添加一个不同的计算机名称:

1
PS> Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value storage2 -Concatenate -Force

现在尝试转储更改的内容。结果是一个逗号分隔的列表,支持通配符:

1
2
3
4
5
6
7
8
PS> Get-ChildItem -Path WSMan:\localhost\Client\TrustedHosts


WSManConfig: Microsoft.WSMan.Management\WSMan::localhost\Client

Type Name SourceOfValue Value
---- ---- ------------- -----
System.String TrustedHosts 192.168.*,storage2

要将 TrustedHosts 还原为默认值并将其清空,请使用 Clear-Item 命令:

1
PS> Clear-Item -Path WSMan:\localhost\Client\TrustedHosts -Force
PowerShell 技术 QQ 群