@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密码行是存储密码的位置。
有没有办法将此密码隐藏在另一个文件中并从那里调用?
答案 0 :(得分:4)
您可以使用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命令的输出,在此情况下,该命令是{{1}的Password
属性}。如果您提供了自己的密钥,请确保将密钥存储在安全的地方。只有应该有权访问它的用户和机器才能读取它。理想情况下,凭据和秘密应该从秘密文件库(例如Hashicorp Vault,Keepass等)中存储和检索,但是文件ACL可以用来控制谁也可以访问此信息。
请注意,当帐户密码更改时,如果您依赖默认的加密行为,则必须重新生成NetworkCredential
。