Last active
November 20, 2020 21:11
-
-
Save JohnL4/e765145f1b7a6711d4d8d093a7f8eb62 to your computer and use it in GitHub Desktop.
Store and retrieve a password using Microsoft's magical amazing SecureString functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
$passwd = ConvertTo-SecureString 'hunter2' -AsPlainText -Force | |
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)) | |
# Another way to get the password in w/out putting it in a command line as above. | |
$passwd = Read-Host -AsSecureString | |
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)) | |
$bytes = (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16) | |
$bytes.length # Should be 16 | |
ConvertFrom-SecureString $passwd -key $bytes > c:/tmp/my-password-is-hunter2.txt | |
<# | |
RDP to some other machine, possibly as some other user, and you should be able to decrypt the text file using the same | |
byte array to recover the password, which you can then pass to some other piece of software such as | |
A JAVASCRIPT ENGINE WRITTEN IN GO. | |
#> | |
# --------------------------------------------------- Random bytes --------------------------------------------------- | |
$bytes = [System.Byte[]]::CreateInstance( [System.Byte], 16) | |
$rand.NextBytes( $bytes) | |
# Now bytes has 16 random byte values. Et voila, a 128-bit AES key. | |
$bytes > "some-shared-directory/random-bytes.txt" | |
# (On another machine:) | |
$byte_vals = cat .\random-bytes.txt | |
$bytes = [System.Byte[]]::CreateInstance( [System.Byte], 16) | |
for ($i = 0; $i -lt 16; $i++) { | |
$bytes[$i] = $byte_vals[$i] # Magical type conversion here | |
} | |
# There's also the following possibility (untested because I got tired of messing around with it). | |
# I got tired of messing around with it because sometimes WriteAllBytes() does nothing (w/out any errors), | |
# depending on where you're trying to write to, so it might not be so reliable. ReadAllBytes() seems to work, though. | |
# From https://stackoverflow.com/questions/31855705/write-bytes-to-a-file-natively-in-powershell/31856307 | |
[IO.File]::WriteAllBytes( "some-shared-directory\bytes.bin", $bytes) | |
# ...and then, on another machine... | |
$bytes_read = [IO.File]::ReadAllBytes( "some-shared-directory\bytes.bin") | |
# Who cares, though? We're not saving that much space to write in binary, nor do we lose much efficiency | |
# to be converting to text and back. | |
# Of course, this requires storing both the encrypted password AND the key to decrypt it, which seems dumb. | |
# -------------------------------------------------- Scheduled Task -------------------------------------------------- | |
# YET ANOTHER ALTERNATIVE, via | |
# https://community.spiceworks.com/scripts/show/3517-use-powershell-securestring-with-windows-system-account | |
<# | |
AUTHOR: Keith Francis | |
Description: This script creates a scheduled task under the system account and runs a command to create a text file with an encrypted password. | |
Since this password is encrypted using the system account, only tasks run under the System account that use this text file for the | |
password will be able to decrypt this password. No other account can decrypt it. This way, the password is stored securely and not | |
in plain text in a powershell script. The encrypted password can be used to, for example, authenticate an email account that may be | |
used in a PS script that sends emails. I could not find another way to run a command under the system account in PowerShell so creating | |
a scheduled task and running it there under the system account will have to do | |
#> | |
#Task name. Call it whatever you want | |
$taskName = "Create Secure Email Password" | |
#This is the path and name where the encrypted password will be stored in a text file | |
$filePath = "C:\SecureFolder\" | |
$fileName = "EncryptedPass.txt" | |
#Create the filePath if it does not exist | |
New-Item -ItemType Directory -Force -Path $filePath | |
$fullPath = $filePath + $fileName | |
#This is the password you are trying to encrypt. Doing -AsSecureString so that it doesn't show the password when you type it | |
$password = Read-Host -Prompt "Enter password" -AsSecureString | |
#Convert the password back to plain text | |
$password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)) | |
#Remove task with the name "Create Secure Email Password" if it already exists | |
$task = Get-ScheduledTask | Where-Object {$_.TaskName -like $taskName} | |
if (![string]::IsNullOrWhiteSpace($task)) | |
{ | |
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false | |
} | |
#Create the action for the scheduled task. It will run powershell and execute the command specified below | |
$action = New-ScheduledTaskAction -Execute 'Powershell.exe' ` | |
-Argument "-command &{'$password' | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File $fullPath}" | |
#Register Scheduled task and then run it once to create the text file with the encrypted password | |
Register-ScheduledTask -Action $action -TaskName $taskName -Description "Creates a text file with the encrypted email password" -User "System" -RunLevel Highest | |
Start-ScheduledTask -TaskName $taskName | |
#Remove the task after it is run | |
Unregister-ScheduledTask -TaskName $taskName -Confirm:$false | |
<# | |
To get the password and use it somewhere like emailing, for example, use the Get-Content command to get the string from the text file | |
and convert it to SecureString. See the sample code below to see how to do this: | |
********************************************************************************** | |
$email = "[email protected]" | |
$pass = Get-Content "C:\SecureFolder\EncryptedPass.txt" | ConvertTo-SecureString | |
$emailCredential = New-Object System.Net.NetworkCredential($email, $pass) | |
********************************************************************************** | |
#> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment