您可以使用 PowerShell 将密码存储在磁盘上,这种方式(默认情况下)只能由创建密码的计算机上的当前执行用户检索。如果您不能在 PowerShell 中编写整个脚本,您至少可以通过在脚本期间调用 powershell.exe 来做到这一点。
如果您想使用来自单个机器和用户的凭据
创建凭证文件(这将提示您输入凭证,在这种情况下用户名无关紧要,但必须提供):
powershell.exe -c "Get-Credential | Export-CliXml cred.xml"
Export-CliXml 是一个特殊的 cmdlet,它可以将 PowerShell 对象序列化到磁盘,并且有一些边缘警告(比如不要尝试对 COM 对象执行此操作并期望它工作),通常可用于读取对象回到我们下面做的另一个会话。并将其从您的脚本读入一个变量并在您的命令中使用它:
for /f %i in ('powershell.exe -c "( Import-CliXml cred.xml ).GetNetworkCredential().Password"') do set PASSWORD=%i
DFC.EXE %PASSWORD% /BOOTTHAWED
我们需要获取网络凭据,以便我们可以在该命令中获取可用密码。如果您确实发现自己在其他命令中也需要用户名,您也可以通过类似方式获得:
for /f %i in ('powershell.exe -c "( Import-CliXml cred.xml ).UserName"') do set USERNAME=%i
在用户名的情况下,它没有加密,因此您无需返回网络凭据即可获得可用的用户名。
如果您想使用来自多台机器和用户的凭据
以上,为了简单起见,我们利用Get-Credential 创建初始凭据,但并非绝对必须使用它来构建凭据对象。
如果您需要解密来自多台机器或用户的凭据,则稍微复杂一些。您将无法利用Get-Credential,并且必须自己构建凭据,并且仅将密码存储在文件中(您也可以存储用户名,但在这种情况下)。
准备秘密
要准备凭证,首先我们需要创建一个密钥文件。这比能够使用Get-Credential 更复杂,但您只需在第一次生成密钥文件或密码文件时执行这些步骤。最好从powershell.exe做这一步:
$keyFile = "C:\path\to\keyfile.key"
# you can adjust this number for different levels of AES encryption
# 32 = 256 bits
# 24 = 192 bits
# 16 = 128 bits
$key = New-Object Byte[] 32
[Security.Cryptography.RNGCryptoServiceProvider]::Create().GetBytes($key)
# Save the key file to disk
$key | Out-File $keyFile
现在我们有了密钥文件,我们可以使用它将您的密码存储到磁盘(请记住,这次我们只是将密码存储在文件中,而不是 PSCredential 对象)。再一次,最好从powershell.exe 完成,就像上一步一样:
# Save your password in a file so you don't have it plaintext in your history
$insecurePassFile = "C:\path\to\insecurePassFile.txt"
# This will be the encrypted password outfile
$securePassFile = "C:\path\to\securePassFile.txt"
# This can also be a UNC path if on a share
$keyFile = "C:\path\to\keyfile.key"
# Read the key in
$key = Get-Content $keyFile
# Read the plaintext password in and convert it to a secure string using our key
$password = Get-Content $insecurePassFile | Select-Object -First 1 | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString -key $key
# Write the encrypted password out to a file to be read in later using our key
$password | Out-File $securePassFile
现在您将加密的密码文件保存到$securePassFile。 此时您可以将密码文件和密钥复制到网络上的某个位置。
在批处理脚本中使用凭据
现在我们要回到批处理世界。要读入密码,您需要知道密码文件和密钥文件的位置,并有权访问这两者。我很抱歉,但这将是一个很长的 PowerShell 命令,只能放在一行中:
for /f %i in ('powershell.exe -c "$key = Get-Content \\server.domain.tld\share\path\to\keyfile.key; [System.Net.NetworkCredential]::new("", ( Get-Content \\server.domain.tld\share\path\to\password.txt | ConvertTo-SecureString -Key $key ) ).Password"') do set PASSWORD=%i
这是一口,所以让我们分解一下:
- 批处理
for 循环是将变量设置为命令输出所需的“魔法”。最终将PASSWORD 变量设置为PowerShell 命令的输出。 IMO 编写命令提示符的人是受虐狂 XD。
- 这将开始实际的解密过程。首先我们需要从密钥文件中读取
$key。没有这个,我们就无法从密码文件中解密我们的密码。
- 我们创建一个新的网络凭据,我们可以通过创建一个新的
System.Net.NetworkCredential 对象从中提取密码。第一个参数是用户名(我们这里不需要,空字符串可以),第二个是SecureString密码:
- 对于密码参数,我们从文件中读取密码并使用我们的密钥文件中的密钥将其解密为正确的
SecureString。
- 从生成的
NetworkCredential 对象中,我们可以读取Password 属性,这是我们可以返回的可用密码。
- 作为原始批处理
for 循环的一部分,PASSWORD 设置为上一个 PowerShell 命令的输出,在本例中是我们构建的 NetworkCredential 的 Password 属性。
像对待任何其他敏感密码一样对待您的密钥
如果您提供了自己的密钥,请确保将您的密钥存储在安全的地方。只有应该有权访问它的用户和机器才能读取它。理想情况下,凭据和机密应存储在机密保险库(例如 Hashicorp Vault、Keepass 等)中并从中检索,但文件 ACL 也可用于控制谁可以访问此信息。
请注意,当帐户密码更改时,如果您依赖默认加密行为,则必须重新生成 cred.xml。