Skip to content

Instantly share code, notes, and snippets.

@JohnL4
Last active November 20, 2020 21:11
Show Gist options
  • Save JohnL4/e765145f1b7a6711d4d8d093a7f8eb62 to your computer and use it in GitHub Desktop.
Save JohnL4/e765145f1b7a6711d4d8d093a7f8eb62 to your computer and use it in GitHub Desktop.
Store and retrieve a password using Microsoft's magical amazing SecureString functions
$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