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

PowerShell 技能连载 - 删除 Microsoft Teams 缓存数据

如果您使用 Microsoft Teams 进行视频会议,则有时可能需要清理缓存文件并删除驻留在许多子文件夹中的残留数据。

您可以调整上一个示例中的代码来进行清理:

1
2
3
4
5
6
7
8
9
# the folder that contains the Microsoft Teams data
$parentFolder = "$env:userprofile\AppData\Roaming\Microsoft\Teams\*"
# list of subfolders that cache data
$list = 'application cache','blob storage','databases','GPUcache','IndexedDB','Local Storage','tmp'

# delete the folders found in the list
Get-ChildItem $parentFolder -Directory |
Where-Object name -in $list |
Remove-Item -Recurse -Verbose

如果您具有管理员权限,并想为所有用户删除缓存的 Microsoft Teams 数据,请按如下所示更改 $parentFolder

1
$parentFolder = "c:\users\*\AppData\Roaming\Microsoft\Teams\*"

PowerShell 技能连载 - 删除多个子文件夹

有时,可能有必要删除给定文件夹中的一组子文件夹。这是一段简单的代码,可从文件夹名称列表中删除文件夹。

警告:此代码将删除 $list 中列出的子文件夹,而无需进一步确认。如果子文件夹没有退出,则什么也不会发生。

1
2
3
4
5
6
7
8
9
10
11
# the folder that contains the subfolders to remove
# (adjust to your needs)
$parentFolder = $env:userprofile

# list of folder names to remove (adjust to your needs)
$list = 'scratch', 'temp', 'cache'

# delete the folders found in the list
Get-ChildItem $parentFolder -Directory |
Where-Object name -in $list |
Remove-Item -Recurse -Force -Verbose

如果要删除父文件夹内任何位置的子文件夹,请通过向 Get-ChildItem 添加 -Recurse 来扩展搜索以通过子文件夹进行递归。

下面的示例在父文件夹的文件夹结构内的任何位置删除 $list 中的子文件夹。

请注意,这样做可能有风险,因为您现在正在查找可能并不是由您所有并控制的文件夹内的子文件夹,这就是为什么我们向 -Remove-Item 添加 -WhatIf 的原因:该代码实际上不会删除子文件夹,而只是报告其内容完成了。如果您知道自己在做什么,请删除该参数:

1
2
3
4
5
6
7
8
9
# the folder that contains the subfolders to remove
$parentFolder = $env:userprofile
# list of folder names to remove
$list = 'scratch', 'temp', 'cache'

# delete the folders found in the list
Get-ChildItem $parentFolder -Directory -Recurse |
Where-Object name -in $list |
Remove-Item -Recurse -Verbose -WhatIf

PowerShell 技能连载 - 管理自启动项

要在 Windows 上管理自动启动程序,不必费心编写大量脚本。 PowerShell 可以直接打开任务管理器中包含的自动启动管理器,您只需执行以下操作即可:

1
PS C:\> Taskmgr /7 /startup

这将打开一个窗口,并列出所有自动启动程序及其对启动时间的影响。要阻止这些程序中的任何一个自动启动,请单击列表中的一个程序,然后单击右下角的“禁用”按钮。

如果您愿意,可以将命令转换为函数,然后将其放入配置文件脚本中,以备不时之需:

1
2
3
4
function Show-Autostart
{
Taskmgr /7 /startup
}

PowerShell 技能连载 - 下载有用的脚本

PowerShell Gallery 不仅提供带有新 PowerShell 命令的公共模块,而且还提供公共脚本。在投入时间之前,您可能希望调查是否有人创建了可以执行所需功能的 PowerShell 代码。

这是一个简单的示例,说明了如何通过 PowerShell Gallery 搜索和下载脚本的工作方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
# create temporary folder
$destination = Join-Path -Path $env:temp -ChildPath Scripts
$exists = Test-Path -Path $destination
if (!$exists) { $null = New-Item -Path $destination -ItemType Directory }

# offer to download scripts
Find-Script -Name Get-* | Select-Object -Property Name, Description |
Out-GridView -Title 'Select script to download' -PassThru |
ForEach-Object {
Save-Script -Path $destination -Name $_.Name -Force
$scriptPath = Join-Path -Path $destination -ChildPath "$($_.Name).ps1"
ise $scriptPath
}

当您运行此代码时,Find-Script 将查找使用 Get 动词的任何脚本。您当然可以更改此设置并搜索您喜欢的任何内容。接下来,所有与您的搜索匹配的脚本都将显示在网格视图窗口中。现在,您可以选择一个或多个听起来很有趣的东西。

然后,PowerShell 将所选脚本下载到一个临时文件夹,然后在 PowerShell ISE 中打开这些脚本。现在,您可以查看源代码并从中选择有用的内容。

注意:由于 Out-GridView 中的 bug,您需要等待所有数据到达后才能选择脚本。如果选择脚本并在 Out-GridView 仍在接收数据的同时单击“确定”,则不会传递任何数据,也不会下载脚本。

要解决此问题,请等待足够长的时间以完全填充网格视图窗口,或者通过首先收集所有数据然后仅在网格视图窗口中显示数据来关闭实时模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# create temporary folder
$destination = Join-Path -Path $env:temp -ChildPath Scripts
$exists = Test-Path -Path $destination
if (!$exists) { $null = New-Item -Path $destination -ItemType Directory }

# offer to download scripts
Write-Warning "Retrieving scripts, hang on..."
# collecting all results in a variable to work around
# Out-GridView bug
$all = Find-Script -Name Get-* | Select-Object -Property Name, Description
$all | Out-GridView -Title 'Select script to download' -PassThru |
ForEach-Object {
Save-Script -Path $destination -Name $_.Name -Force
$scriptPath = Join-Path -Path $destination -ChildPath "$($_.Name).ps1"
ise $scriptPath
}