@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
I am trying to run a very simple batch file but I don't want the password stored in plain text if someone were to edit it.
Right now the DFC.exe password line is where the password is stored.
Is there a way to hide this password in another file and call it from there?
Try using the net use command in your script to map the share first, because you can provide it credentials. Then, your copy command should use those credentials.
GUI Method. Right click on the file, you want to make it Read-only. Click on the Properties tab from the context menu. Click the Read-only check box belong to Attributes from on the General tab from the popped up Properties window.
To open the BAT file in Notepad, right-click it and choose Show more options > Edit from the menu (or just Edit in some Windows versions). You might find it helpful to use more advanced text editors that support syntax highlighting when editing a BAT file.
A few days ago I stumbled upon a more secure way to store a Password using a batch file. When it encodes the letters even the same letters aren't the same 40 digit string making it more secure. set /p filename=Enter the File name you wish to save the Text under (Eg. Text): Echo Encrypting... echo Encrypting complete!
The main rule is: never store the password inside the script. If the script will run only manually (someone executing the script), do not store the password on the script, instead, make the script ask the password every time it's executed. Create a specific user for the purpose you need. ensure the user has the minimum permissions as possible.
If the script will run only manually (someone executing the script), do not store the password on the script, instead, make the script ask the password every time it's executed. Create a specific user for the purpose you need. ensure the user has the minimum permissions as possible.
Not to worry – as always powershell has a module to save our skins. Here’s how you store your passwords securely and retrieve them when needed: Powershell thankfully has the ConvertFrom-SecureString module to convert any text to a secure string.
You can use PowerShell to store the password on disk in a way that (by default) is only retrievable by the currently executing user on the computer it was created on. If you can't write your entire script in PowerShell, you can at least do this by calling powershell.exe
during your script.
To create the credential file (this will prompt you for the credential, the username doesn't matter in this case but must be provided):
powershell.exe -c "Get-Credential | Export-CliXml cred.xml"
Export-CliXml
is a special cmdlet that serializes a PowerShell object to disk, and with some edge caveats (like don't try doing this with a COM object and expect it to work), can usually be used to read the object back into another session as we do below. And to read it in from your script to a variable and use it in your command:
for /f %i in ('powershell.exe -c "( Import-CliXml cred.xml ).GetNetworkCredential().Password"') do set PASSWORD=%i
DFC.EXE %PASSWORD% /BOOTTHAWED
We need to obtain the network credential so we can get a usable password as part of that command. If you do find yourself needing the username as well in other commands, you can also get that in a similar fashion:
for /f %i in ('powershell.exe -c "( Import-CliXml cred.xml ).UserName"') do set USERNAME=%i
In the case of the username, it is not encrypted so you don't need to return the network credential to obtain a useable username.
Above, we leverage Get-Credential
to create the initial credential for its simplicity, but it's not strictly necessary to build a credential object with it.
If you need to decrypt the credential from multiple machines or users, it's a little more complicated. You won't be able to leverage Get-Credential
and will have to build the credential yourself, and store only the password in a file (you could store the username as well but for this case).
To prepare the credential, first we'll need to create a key file. This is more complex than being able to use Get-Credential
but you only have to do these steps when you generate the keyfile or password file the first time. It's best to do this step from 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
Now that we have the key file, we can store your password to disk using it (remember, this time we are just storing the password in the file, not a PSCredential
object). Once again, this is best done from powershell.exe
like with the previous step:
# 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
Now you will have your encrypted password file saved to $securePassFile
. At this point you can copy your password file and key to a location on the network.
Now we're going back to batch world. To read the password in, you'll need to know the location of the password file and key file, and have permissions to access both of these. I apologize, but this is going to be a long PowerShell command to fit on one line:
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
That was a mouthful, so let's break it down:
for
loop is the "magic" required to set a variable to a command's output. Eventually sets the PASSWORD
variable to the output of the PowerShell command. IMO the people who wrote the command prompt are masochists XD.$key
from the key file. Without this we can't decrypt our password from the password file.System.Net.NetworkCredential
object. The first parameter is the username (which we don't need here, an empty string works) and the second is the SecureString
password:SecureString
using the key from our key file.NetworkCredential
object we are able to read the Password
property which is a usable password we can return.for
loop, PASSWORD
is set to the output of the previous PowerShell command, which in this case is the Password
property of the NetworkCredential
we built.If you provided your own key, make sure to store your key somewhere secure. Only the users and machines that should have access to it should be able to read it. Ideally, credentials and secrets should be stored and retrieved from a secrets vault (e.g. Hashicorp Vault, Keepass, etc.) but file ACLs can be used to control who can access this information as well.
Do note that when the account password changes, you will have to regenerate cred.xml
if you are relying on the default encryption behavior.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With