如何在批处理脚本中存储和检索密码到文件中?

7
@ECHO OFF
DFC.EXE get /isfrozen

IF Errorlevel 1 GOTO Frozen
IF Errorlevel 0 GOTO Thawed

:Frozen
Echo Errorlevel 1 Computer is Frozen, Thawing Now
DFC.EXE fakepassword123 /BOOTTHAWED
Echo
Goto END

:Thawed
Echo Errorlevel 0 Computer is Not Frozen
Echo
Goto END

:END
Exit

我试图运行一个非常简单的批处理文件,但如果有人想编辑它,我不希望密码以纯文本形式存储。

目前,DFC.exe密码行是存储密码的位置。

有没有一种方法将这个密码隐藏在另一个文件中,并从那里调用它?

1个回答

9

您可以使用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

那是一个难以理解的内容,让我们来逐步分解一下:
1. 批处理循环(batch for loop)是必须要使用的“魔法”,用于将变量设置为命令输出的结果。最终会将 PASSWORD 变量设置为 PowerShell 命令的输出结果。我认为编写命令提示符的人都是受虐狂 XD。
2. 这里开始实际的解密过程。首先,我们需要从密钥文件读取 $key。如果没有这个密钥,我们就无法从密码文件中解密出密码。
3. 我们创建了一个新的网络凭据,可以通过创建新的 System.Net.NetworkCredential 对象从中提取密码。第一个参数是用户名(我们这里不需要,填空字符串即可),第二个参数是 SecureString 类型的密码。
4. 对于密码参数,我们从文件中读取密码,并使用密钥文件中的密钥将其解密为正确的 SecureString。
5. 从生成的 NetworkCredential 对象中,我们可以读取 Password 属性,这是一个可用的密码。
6. 作为原始批处理循环的一部分,PASSWORD 被设置为前一个 PowerShell 命令的输出结果。在本例中,它是我们构建的 NetworkCredential 的 Password 属性。
请像任何敏感密码一样对待你的密钥
如果你提供了自己的密钥,请确保将其存储在安全的地方。只有应该访问它的用户和计算机才能读取它。理想情况下,凭据和密钥应该存储在秘密保管库中(例如 Hashicorp Vault、Keepass 等),但文件 ACL 也可以用于控制谁可以访问这些信息。
请注意,当账户密码更改时,如果你依赖默认加密行为,你将需要重新生成 cred.xml。

非常感谢你,Bender!你是绝对最棒的! - Riley
没问题。不过我必须承认,编写批处理代码将命令输出设置为变量让我想起了我有多么讨厌命令提示符语法哈哈。 - codewario
2
我建议学习它。是一个更干净的语法,比cmd.exe更强大。 - codewario
那么,是否可以使用\server\path从远程计算机调用cred.xml?我需要从服务器运行此脚本到100台计算机,并且我没有时间去每个计算机上保存此cred文件。我打算在星期一尝试它,但我还是想问一下。我只需将其输入到for /f %i in ('powershell.exe -c "(Import-CliXml \server\fakenetworkpath\fakefolder\cred.xml ? - Riley
1
我认为有一种方法可以使用证书作为密钥,但我不知道具体细节。 - js2010
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接