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 技能连载 - 在 PowerShell ISE 中使用 PowerShell 7

Windows 内置的 PowerShell ISE 仅能与 Windows PowerShell 一起使用,并且停留在 PowerShell 5.1 版。通常,当您想使用编辑器编写 PowerShell 7 代码时,可以使用 Visual Studio Code 和 PowerShell 扩展。

尽管如此,您仍可以使 PowerShell ISE 兼容 PowerShell 7。然后,它为 PowerShell 7 提供了丰富的 IntelliSense,并包含 PowerShell 7 中引入的所有语言功能。

为此,您可以从 PowerShell ISE 中启动本地远程会话,并指定配置名称 “powershell.7”。

1
PS> Enter-PSSession -ComputerName localhost -ConfigurationName powershell.7

当然,这需要满足一些先决条件:

  • 您需要先安装 PowerShell 7,然后才能使用它。 Windows 7 并不附带 PowerShell 7。
  • 您需要在 PowerShell 7中启用远程处理。您可以在安装期间通过选中安装对话框中的相应框来执行此操作。或者,您从提升权限的 PowerShell 7 控制台运行此命令:Enable-PSRemoting -SkipNetworkProfileCheck -Force
  • 您可能需要在提升权限的 Windows PowerShell 中再次运行此行命令:Enable-PSRemoting -SkipNetworkProfileCheck -Force

现在您已经准备就绪,并使用上述参数运行 Enter-PSSession 时,您将远程连接到 PowerShell 7。

如果您当前的用户不是管理员,或者您使用电子邮件地址和 Microsoft 帐户登录,则需要创建一个具有管理员权限的本地用户帐户,并将其明确用于身份验证:

1
PS> Enter-PSSession -ComputerName localhost -ConfigurationName powershell.7 -Credential localAdminUser

PowerShell 技能连载 - 使用 $Is* 变量

在PowerShell 7 中,有一组新的变量都以 “Is” 开头。它们可帮助您了解脚本运行的环境:

1
2
3
4
5
6
7
PS> Get-Variable -Name is*
Name Value
---- -----
IsCoreCLR True
IsLinux False
IsMacOS False
IsWindows True

在 Windows 附带的 Windows PowerShell 中,这些变量尚不存在。这是可以理解的,因为 Windows PowerShell 是 Windows 的一部分,而且无论如何都不能跨平台兼容。

要在Windows(或任何其他受支持的平台)上运行PowerShell 7,请访问发布页面https://github.com/PowerShell/PowerShell/releases ,向下滚动到 “Assets” 标题,然后下载最适合您的安装软件包。

在 Windows PowerShell中,只需运行以下代码即可:

1
iex "& { $(irm https://aka.ms/install-powershell.ps1) } -UseMSI"

要启动 PowerShell 7,请运行 pwsh.exe

PowerShell 技能连载 - 启用或禁用实时防病毒保护

如果您以完全管理员权限运行,则可以使用 PowerShell 启用和禁用实时防病毒保护。当明确需要运行可能会被阻止的合法脚本时,暂时禁用实时防病毒保护有时可能会有所帮助。通常,实时保护很有价值,只有在有充分理由的情况下才应将其禁用。

要禁用实时保护,请运行以下命令:

1
Set-MpPreference -DisableRealtimeMonitoring $true

要启用它,请将 $true 替换为 $false

PowerShell 技能连载 - 检测防病毒引擎状态

在上一个技能中,我们学习了如何查询 WMI 来查找 Windows 计算机上存在的防病毒产品:

1
2
3
$info = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct

$info

ProductState 属性对其他信息进行编码,告诉您防病毒引擎是否可运行并使用最新的签名。不过该信息是一个数字,并且是一个位标记:

1
2
3
4
PS> $info = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct

PS> $info.productState
397568

要解密数字中各个位的含义,可以使用 PowerShell 对枚举类型新支持。定义好位及其含义,并用 [Flags()] 属性修饰枚举(表明可以设置多个位):

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
# define bit flags

[Flags()] enum ProductState
{
Off = 0x0000
On = 0x1000
Snoozed = 0x2000
Expired = 0x3000
}

[Flags()] enum SignatureStatus
{
UpToDate = 0x00
OutOfDate = 0x10
}

[Flags()] enum ProductOwner
{
NonMs = 0x000
Windows = 0x100
}

# define bit masks

[Flags()] enum ProductFlags
{
SignatureStatus = 0x00F0
ProductOwner = 0x0F00
ProductState = 0xF000
}

# get bits
$info = Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct
[UInt32]$state = $info.productState

# decode bit flags by masking the relevant bits, then converting
[PSCustomObject]@{
ProductState = [ProductState]($state -band [ProductFlags]::ProductState)
SignatureStatus = [SignatureStatus]($state -band [ProductFlags]::SignatureStatus)
Owner = [ProductOwner]($state -band [ProductFlags]::ProductOwner)
}

要检查位组的状态,请屏蔽与您要执行的操作相关的位,然后将这些位转换为枚举。结果是当前设置的位的明文名称。结果看起来像这样:

ProductState SignatureStatus   Owner
------------ ---------------   -----
          On        UpToDate Windows

如果您使用的是 Windows 10 上内置的防病毒引擎 “Defender”,则无需使用上面的通用防病毒界面。而是使用内置的 Get-MpPreference cmdlet,它提供了更多详细信息。

PowerShell 技能连载 - 检测已安装的防病毒产品

这行 PowerShell 代码可以帮助您识别 Windows 系统中安装的防病毒产品:

1
PS> Get-CimInstance -Namespace root/SecurityCenter2 -ClassName AntiVirusProduct

添加 -ComputerName 参数以查询远程系统。

请注意,此行仅返回正确注册的防病毒产品。结果看起来类似这样,并为您提供了防病毒产品和安装位置:

1
2
3
4
5
6
7
displayName              : Windows Defender
instanceGuid : {D68DDC3A-831F-4fae-9E44-DA132C1ACF46}
pathToSignedProductExe : windowsdefender://
pathToSignedReportingExe : %ProgramFiles%\Windows Defender\MsMpeng.exe
productState : 397568
timestamp : Wed, 29 Jul 2020 18:37:24 GMT
PSComputerName