PowerShell 技能连载 - 检测泄露的密码(第 1 部分)

密码复杂时也不一定是安全的。相反,您需要确保密码没有受到破坏,并且不在默认的攻击者词典中。如果自动攻击经常检查该密码,那么即使是最复杂的密码也不安全。

要确定密码是否被泄露,请使用以下功能:

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
function Test-Password
{
[CmdletBinding()]
param
(
[Parameter(Mandatory, Position=0)]
[System.Security.SecureString]
$Password
)

# take securestring and get the entered plain text password
# we are using a securestring only to get a masked input box
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password)
$plain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

# hash the password
$bytes = [Text.Encoding]::UTF8.GetBytes($plain)
$stream = [IO.MemoryStream]::new($bytes)
$hash = Get-FileHash -Algorithm 'SHA1' -InputStream $stream
$stream.Close()
$stream.Dispose()

# separate the first 5 hash characters from the rest
$first5hashChars,$remainingHashChars = $hash.Hash -split '(?<=^.{5})'

# send the first 5 hash characters to the web service
$url = "https://api.pwnedpasswords.com/range/$first5hashChars"
[Net.ServicePointManager]::SecurityProtocol = 'Tls12'
$response = Invoke-RestMethod -Uri $url -UseBasicParsing

# split result into individual lines...
$lines = $response -split '\r\n'
# ...and get the line where the returned hash matches your
# remainder of the hash that you kept private
$filteredLines = $lines -like "$remainingHashChars*"

# return the number of compromises
[int]($filteredLines -split ':')[-1]
}

使用起来非常简单:只需将密码传给 Test-Password 函数即可。它返回已知泄露的数量,并且返回大于 0 泄露的任何密码都被认为是不安全的,必须进行更改。

1
2
3
4
PS> $password = Read-Host -AsSecureString

PS> Test-Password -Password $password
4880

The password must be submitted as a SecureString. You can either run Test-Password without a password in which case you get safely prompted. Or you need to read the password as a SecureString.
密码必须作为 SecureString 提交。您可以不带密码运行 Test-Password,在这种情况下,系统会提示您。或者您需要以 SecureString 形式读取密码。

在该示例中,复杂密码 “P@$$w0rd” 在 4880 次攻击中被泄露,使用起来非常不安全。

评论

PowerShell 技能连载 - 创建软件库

Windows 注册表存储已安装的所有软件的名称和详细信息。PowerShell 可以读取该信息,并为您提供完整的软件清单:

1
2
3
4
5
6
7
8
9
10
11
12
# read all child keys (*) from all four locations and do not emit
# errors if one of these keys does not exist
Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
'HKCU:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' -ErrorAction Ignore |
# list only items with the DisplayName
Where-Object DisplayName |
# show these registry values per item
Select-Object -Property DisplayName, DisplayVersion, UninstallString, InstallDate |
# sort by DisplayName
Sort-Object -Property DisplayName

如果您想添加更多信息(例如,软件是 32 位还是 64 位),或者要将代码转换为可重用的新 PowerShell 命令,请在此处阅读更多内容:https://powershell.one/code/5.html

评论

PowerShell 技能连载 - 使 PowerShell 模块保持最新

务必经常检查您的 PowerShell 模块是否为最新。如果您使用的是旧的和过时的模块,则可能会遇到问题,就像平时使用旧的和过时的软件一样。

例如,PowerShellGet 模块提供了诸如 Install-Module 之类的 cmdlet,可让您轻松下载和安装其他 PowerShell 模块,并通过新的命令和功能扩展 PowerShell。

为了了解这一点,下面是一个示例,该示例下载并安装 QRCodeGenerator 模块,该模块会生成各种 QR 代码,例如用于 Twitter 个人资料:

1
2
3
4
5
# install new PowerShell module from PowerShell Gallery
PS> Install-Module -Name QRCodeGenerator -Scope CurrentUser

# use one of the newly added commands to create a QR code for Twitter profiles
PS> New-QRCodeTwitter -ProfileName tobiaspsp -Show

使用智能手机相机扫描创建的 QR 码时,您可以访问 QR 码中编码的 Twitter 个人资料。同样,其他 QR 码类型也可以提供前往某个地点的路线或向您的地址簿添加联系人:

1
2
3
4
5
6
7
8
PS> Get-Command -Module QRCodeGenerator -CommandType function

CommandType Name Version Source
----------- ---- ------- ------
Function New-PSOneQRCodeGeolocation 2.2 QRCodeGenerator
Function New-PSOneQRCodeTwitter 2.2 QRCodeGenerator
Function New-PSOneQRCodeVCard 2.2 QRCodeGenerator
Function New-PSOneQRCodeWifiAccess 2.2 QRCodeGenerator

如果您在新添加的模块上遇到问题,则可能是因为 PowerShellGet 模块已过时。如果您仍在使用古老的 PowerShellGet 版本 1.0.0.1,则可能会遇到讨厌的错误。

当模块仅使用 manifest 文件中的 major 和 minor 版本号时,Install-Module 会将它们安装到具有 3 位数字版本号的子文件夹中。这使已安装的模块不可用。

因此,保持模块最新很重要。PowerShellGet 的最新版本已修复此错误。让我们看一下如何检查和更新模块。

首先,找出您当前使用的模块版本,例如 PowerShellGet:

1
2
3
4
5
6
7
8
9
10
PS> Get-Module -Name PowerShellGet -ListAvailable


Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.2.1 PowerShellGet {Find-Command, Find-DSCResource, Find-Module...}
Script 1.0.0.1 PowerShellGet {Install-Module, Find-Module, Save-Module...}

在此示例中,安装了两个不同版本的 PowerShellGet模块:初始发行版本1.0.0.1和更新版本2.2.1。要找出您使用的版本,请尝试以下操作:

1
2
3
4
5
6
7
PS> Import-Module -Name PowerShellGet

PS> Get-Module -Name PowerShellGet

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.2.1 PowerShellGet {Find-Command, Find-DscResource, Find-Module...}

接下来,检查是否有可用的较新版本(这要求该模块通过官方 PowerShell 库提供,但并非对所有模块都适用。如果此处未提供您的模块,则需要检查最初提供该模块的实体):

1
2
3
4
5
PS> Find-Module -Name PowerShellGet

Version Name Repository Description
------- ---- ---------- -----------
2.2.3 PowerShellGet PSGallery PowerShell module with commands for discovering, installing, upd...

如果有较新的版本,请先尝试更新模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
PS> Update-Module -Name PowerShellGet

PS> Get-Module -Name PowerShellGet -ListAvailable

Directory: C:\Users\tobia\OneDrive\Dokumente\WindowsPowerShell\Modules


ModuleType Version Name ExportedCommands
---------- ------- ---- -----------
Script 2.2.3 PowerShellGet {Find-Command, Find-DSCResource, Find-M...}


Directory: C:\Program Files\WindowsPowerShell\Modules


ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.2.1 PowerShellGet {Find-Command, Find-DSCResource, Find-M...}
Script 1.0.0.1 PowerShellGet {Install-Module, Find-Module, Save-M...}

Update-Module 要求该模块最初是通过 Install-Module 安装的。如果是这样,PowerShell 会知道原始源码库并自动更新该模块。

If Update-Module fails, try and re-install the module using the -Force parameter. If that still fails, add the -SkipPublisherCheck parameter:
如果 Update-Module 失败,请尝试使用 -Force 参数重新安装该模块。如果仍然失败,请添加 -SkipPublisherCheck 参数:

1
PS> Install-Module -Name PowerShellGet -Scope CurrentUser -Force -SkipPublisherCheck

要验证成功,请确保已加载最新版本:

1
2
3
4
5
PS> Import-Module -Name PowerShellGet -Force -PassThru

ModuleType Version Name ExportedCommands
---------- ------- ---- ----------------
Script 2.2.3 PowerShellGet {Find-Command, Find-DscResource, Find-Mo...
评论

PowerShell 技能连载 - 增加新的 PowerShell 命令

PowerShell 只是一个脚本平台,可以增加新命令来扩展。新命令的一个很好的来源是公开的 PowerShell Gallery。您可以访问 [https://powershellgallery.com](https://powershellgallery.com)上的图形前端,并搜索模块。

PowerShell 带有一个称为 PowerShellGet 的模块,该模块又提供了从 PowerShell 库下载和安装扩展的命令。我们现在就下载并安装免费的命令扩展程序。

当前最受欢迎的通用 PowerShell 命令扩展之一是免费的 Carbon 模块,在过去六周中下载了将近 400 万次。要从 PowerShell 库中安装它,请使用 Install-Module。使用 CurrentUser 范围时,不需要管理员权限:

1
PS> Install-Module -Name Carbon -Scope CurrentUser

首次使用时,Install-Module 会请求下载许可并使用 “nuget“ DLL,该 DLL 负责下载和安装过程。接下来,下载并解压缩请求的模块。由于 PowerShell 库是一个公共存储库,因此要求您同意将材料下载到计算机上。使用 -Force 参数可以跳过此部分。

重要提示:PowerShell Gallery 提供的大多数 PowerShell 模块都是基于脚本的。您需要允许执行脚本;否则,您将无法使用基于脚本的模块。如果尚未允许脚本执行,则可以使用以下命令:

1
PS> Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force

要查看新的 PowerShell 命令,请列出添加的模块中包含的命令:

1
PS> Get-Command -Module Carbon | Out-GridView

这是一个例子:

1
2
3
4
5
6
7
PS> Get-FileShare

Name Path Description
---- ---- -----------
ADMIN$ C:\Windows Remote Admin
C$ C:\ Default share
print$ C:\Windows\system32\spool\drivers PrintDrivers
评论

PowerShell 技能连载 - 获取 WMI 对象的帮助

WMI 非常强大,但文档不太够。要改变这个情况,已经成立了一个小组并正在编写用于 PowerShell 的 WMI 参考文档:https://powershell.one/wmi

为了轻松查找帮助,可以将 Help() 方法添加到所有WMI和CIM实例对象。只需运行以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$codeCim = {
$url = 'https://powershell.one/wmi/{0}/{1}' -f $this.CimSystemProperties.Namespace.Replace("/","\"),
# add class
$this.CimSystemProperties.ClassName

Start-Process -FilePath $url.ToLower()
}
$codeWmi = {
$url = 'https://powershell.one/wmi/{0}/{1}' -f $this.__Namespace, $this.__Class

Start-Process -FilePath $url.ToLower()
}

Update-TypeData -TypeName Microsoft.Management.Infrastructure.CimInstance -MemberType ScriptMethod -MemberName Help -Value $codeCim -Force
Update-TypeData -TypeName System.Management.ManagementObject -MemberType ScriptMethod -MemberName Help -Value $codeWmi -Force

现在,当您从 Get-WmiObjectGet-CimInstance 检索信息时,每个对象都具有新的 Help() 方法,该方法会自动在浏览器中打开相应的参考页:

1
2
3
4
5
6
7
8
9
10
11
PS> $result = Get-WmiObject -Class Win32_Share

PS> $result[0].Help()

PS> $result.Help()



PS> $result = Get-CimInstance -ClassName Win32_StartupCommand

PS> $result.Help()

如果您想参加并获得有用的 WMI 示例代码,请转到相应的参考页面,并通过底部的注释功能添加您的代码。

评论

PowerShell 技能连载 - 读取机箱的 SKU

在 Windows 10 和 Server 2016中,WMI 添加了一个新属性,该属性简化了机箱或机壳 SKU 的收集。以下这行代码能够读取 SKU:

1
2
3
4
5
PS> Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property Name, ChassisSKUNumber

Name ChassisSKUNumber
---- ----------------
DESKTOP-8DVNI43 Convertible

SKU 编号仅仅是通用的“可替换编号”(对于笔记本电脑)还是一个独立的编号,取决于制造商和 BIOS 设置。

一个更有希望的类是 Win32_SystemEnclosure,它存在于所有 Windows 版本中:

1
2
3
4
5
PS> Get-CimInstance -ClassName Win32_SystemEnclosure | Select-Object -Property Manufacturer, SerialNumber, LockPresent

Manufacturer SerialNumber LockPresent
------------ ------------ -----------
Dell Inc. 4ZKM0Z2 False
评论

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

当 Windows 系统崩溃时,通常会立即重新启动。这称为“自动重置功能”,使用此此行代码即可检查您的计算机是否支持此功能:

1
Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property Name, AutomaticResetCapability

系统是否实际执行自动重启由“AutomaticResetBootOption”控制:

1
Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property Name, AutomaticResetBootOption

If you own Administrator privileges, you can even change this setting. To turn off automatic reset booting, run this:
如果您拥有管理员特权,甚至可以更改此设置。要关闭自动重置启动,请运行以下命令:

1
Set-CimInstance -Query 'Select * From Win32_ComputerSystem' -Property @{AutomaticResetBootOption=$false}

有关 WMI 类 Win32_ComputerSystem 的更多信息,请访问[http://powershell.one/wmi/root/cimv2/win32_computersystem](http://powershell.one/wmi/root/cimv2/win32_computersystem)。

评论

PowerShell 技能连载 - 使用自定义的验证器属性

从 PowerShell 5开始,您可以创建自己的属性,即自定义验证程序。它们可以应用于变量(和参数),并且一旦分配的值与验证程序不匹配,就会引发异常。

这是一个路径验证器的示例。将其应用于变量时,只能将有效文件路径应用于该变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class ValidatePathExistsAttribute : System.Management.Automation.ValidateArgumentsAttribute
{
# the value to be checked surfaces in $path and must be of type [object]
[void]Validate([object]$path, [System.Management.Automation.EngineIntrinsics]$engineIntrinsics)
{
# if anything is wrong with the value, throw an exception
if([string]::IsNullOrWhiteSpace($path))
{
Throw [System.ArgumentNullException]::new()
}
if(-not (Test-Path -Path $path))
{
Throw [System.IO.FileNotFoundException]::new()
}

# if NO exception was thrown, the value is accepted
}
}
#endregion


[ValidatePathExists()][string]$Path = "c:\windows"
$Path = "c:\test123"

当您分配不存在的路径时,PowerShell都将分配它,而是保留现有值。

评论

PowerShell 技能连载 - 检测是否连接到计费的 WLAN

是否曾经需要知道您当前是否已连接到计费的网络?这是一种快速的检查方法:

1
2
3
4
5
6
function Test-WlanMetered
{
[void][Windows.Networking.Connectivity.NetworkInformation, Windows, ContentType = WindowsRuntime]
$cost = [Windows.Networking.Connectivity.NetworkInformation]::GetInternetConnectionProfile().GetConnectionCost()
$cost.ApproachingDataLimit -or $cost.OverDataLimit -or $cost.Roaming -or $cost.BackgroundDataUsageRestricted -or ($cost.NetworkCostType -ne "Unrestricted")
}

它使用一个 UWP API 返回有关网络状态的大量信息,包括有关网络是否计费的信息。

如果您使用的是较旧的 Windows 平台,则以下是替代的代码,该代码使用好用的旧版 “netsh“ 命令行工具并提取所需的信息。请注意,字符串操作(下面的代码广泛使用)容易出错,可能需要进行调整。

同时,以下代码很好地说明了如果手头没有适当的面向对象的 API 可调用,那么 PowerShell 中的通用字符串操作工具如何可以用作最后的保障:

1
2
3
4
5
6
7
8
9
10
11
function Test-WlanMetered
{
$wlan = (netsh wlan show interfaces | select-string "SSID" | select-string -NotMatch "BSSID")
if ($wlan) {
$ssid = (($wlan) -split ":")[1].Trim() -replace '"'
$cost = ((netsh wlan show profiles $ssid | select-string "Cost|Kosten") -split ":")[2].Trim() -replace '"'

return ($cost -ne "unrestricted" -and $cost -ne "Uneingeschränkt" -and $cost -ne 'Uneingeschr"nkt')
}
else { $false }
}
评论

PowerShell 技能连载 - 使用 WMI 实例路径(第 2 部分)

在上一个技能中,我们演示了了新的 Get-CimInstance 命令缺少 Get-WmiObject 能够返回的重要的 “__Path“ 属性。现在让我们将此属性添加回 Get-CimInstance 中。

Get-CimInstance 返回的每个实例的类型均为 [Microsoft.Management.Infrastructure.CimInstance] 类型,因此可以用 Update-TypeData 向该类型添加新属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$code = {
# get key properties
$keys = $this.psbase.CimClass.CimClassProperties.Where{$_.Qualifiers.Name -eq 'Key'}.Name
$pairs = foreach($key in $keys)
{
'{0}="{1}"' -f $key, $this.$key
}
# add server name
$path = '\\{0}\{1}:{2}.{3}' -f $this.CimSystemProperties.ServerName.ToUpper(),
# add namespace
$this.CimSystemProperties.Namespace.Replace("/","\"),
# add class
$this.CimSystemProperties.ClassName,
# add key properties
($pairs -join ',')

return $path
}

Update-TypeData -TypeName Microsoft.Management.Infrastructure.CimInstance -MemberType ScriptProperty -MemberName __Path -Value $code -Force

运行此代码后,所有 CIM 实例都将再次具有 __Path 属性。它略有不同,因为“新的” __Path 属性引用了所有键值。对于我们测试的所有用例,这都没有什么不同:

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
PS> $old = Get-WmiObject -Class Win32_BIOS

PS> $new = Get-CimInstance -ClassName Win32_BIOS


PS> $old.__PATH
\\DESKTOP-8DVNI43\root\cimv2:Win32_BIOS.Name="1.0.13",SoftwareElementID="1.0.13",SoftwareElementState=3,TargetOperatingSystem=0,Version="DELL - 20170001"

PS> $new.__Path
\\DESKTOP-8DVNI43\root\cimv2:Win32_BIOS.Name="1.0.13",SoftwareElementID="1.0.13",SoftwareElementState="3",TargetOperatingSystem="0",Version="DELL - 20170001"


PS> [wmi]($old.__Path)

SMBIOSBIOSVersion : 1.0.13
Manufacturer : Dell Inc.
Name : 1.0.13
SerialNumber : 4ZKM0Z2
Version : DELL - 20170001

PS> [wmi]($new.__Path)

SMBIOSBIOSVersion : 1.0.13
Manufacturer : Dell Inc.
Name : 1.0.13
SerialNumber : 4ZKM0Z2
Version : DELL - 20170001
评论