Powershell securestring containing comma, or ? or : not working - powershell

I've a script to convert a string to a securestring, to use it in a powershell script.
The script works fine, but I'm not able to use password when there is a comma , or ? or : (I don't know which of the special char don't work ....) inside.
Here is the script :
# Creating SecureString object
$PasswordFile = "X:\pwd\password.txt" # where the securestring will be stored
$KeyFile = "X:\pwd\password.key" # where the AES.Key is located
$Key = Get-Content $KeyFile
$Password = "azerty,12?34:5" | ConvertTo-SecureString -AsPlainText -Force # put your password
$Password | ConvertFrom-SecureString -key $Key | Out-File $PasswordFile
Thanks
I already tried a lot of escape sequences,
'''password''',
backslash, ....

Related

Handling special characters in password string

I have a string. Sometimes it looks like this:
9xABp'}H9$G(#
While, sometimes it looks like this:
9xABp"}H9$G(#
I do not have any control over the character set used to generate the string, but I need to have Powershell stop complaining that the string cannot be parsed and to give me all of the characters.
$string = '9xABp'}H9$G(#'
$secure = ConvertTo-SecureString -String $string -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
That doesn't work, so I tried wrapping my string in double quotes, instead of single quotes.
$string = "9xABp'}H9$G(#"
$secure = ConvertTo-SecureString -String $string -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
That's fine, but $G is not included (replaced by a backslash) and what about when my string has a double quote inside?
I tried using [Regex]::Escape().
$string = "9xABp'}H9$G(#"
$secure = ConvertTo-SecureString -String ([Regex]::Escape($string)) -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
But $G is still missing. Another try, this time with double and single quotes on the outside.
$string = "'9xABp'}H9$G(#'"
$secure = ConvertTo-SecureString -String ([Regex]::Escape($string)) -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secure)
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
What can I do here?
The PowerShell herestring exists for just such an occasion.
$string = #"
'9xABp'}H9$G(#'
"#
The #" and "# characters have to be on their own line, but allow for any characters inside of them.
Edit
Thanks to Mike Klement for reminding me of the single quote variant, which should be used if your password might contain a $ or another character which has significance in PowerShell.
$string = #'
'9xABp'}H9$G(#'
'#
This works the same as the previous here-string but this one will not expand a variable, and is a better fit.

Password from SecureString makes the script hanging

$password = Get-Content 'c:\temp\tmp1\pw.dat' | ConvertTo-SecureString
& "C:\Program Files\PuTTY\pscp.exe" -P 2222 -pw $password 'c:\temp\tmp1\test.txt' 'root#localhost:/home/root/temp'
The above code just got hanging; However, the code below worked.
$password='mypw'
& "C:\Program Files\PuTTY\pscp.exe" -P 2222 -pw $password 'c:\temp\tmp1\test.txt' 'root#localhost:/home/root/temp'
Any suggestion? I do not think I typed the password wrong since I did it several times. Furthermore, I expect an error message if the password was typed wrong.
By the way, the objective of the script is to transfer the file to a linux box.
As stated in a comment the .dat file is created using
read-host -AsSecureString | ConvertFrom-SecureString | out-file
So there are 2 ways I know of doing this.
$EncryptedString = read-host -AsSecureString | ConvertFrom-SecureString
$SecureString = $EncryptedString | ConvertTo-SecureString
$Pointer = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString)
$PlainTextPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Pointer)
$PlainTextPassword
The secret here is the [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecureString) which turns the string into a bytes and returns a pointer to where it is located
The next part [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($Pointer) goes to the pointer and turns the bytes into a string.
The other way would be turning the secure string into a PSCredential.
$EncryptedString = read-host -AsSecureString | ConvertFrom-SecureString
$SecureString = $EncryptedString | ConvertTo-SecureString
$PlainTextPassword = ([PsCredential]::new("DoesntMatter",$SecureString)).GetNetworkCredential().Password
$PlainTextPassword
This turns the Secure String into a PSCredential where you can get the NetworkCredential's password which is in plain text.

Decrypting AES encrypted password to plain text in PowerShell Script

I have been following along on numerous how-to articles that explain how to decrypt an AES encrypted password. No matter how I try, the password ends up with $password displaying as System.Security.SecureString. I need the password to echo in plain text because I am calling a command line utility that does not use windows permissions (ADSI/LDAP). Here's my script:
$PasswordFile = "$PSScriptRoot\PowerShell\AESpassword.txt"
$KeyFile = "$PSScriptRoot\PowerShell\AES.key"
$key = Get-Content $KeyFile
$MyPassword = ConvertTo-SecureString (Get-Content $PasswordFile | ConvertTo-SecureString -Key $key) -AsPlainText -Force
$Marshal = [System.Runtime.InteropServices.Marshal]
$BSTR = $Marshal::SecureStringToBSTR($MyPassword)
$password = $Marshal::PtrToStringAuto($BSTR)
According to #MathiasRJessen the suggestion to use $MyPassword = Get-Content $PasswordFile | ConvertTo-SecureString -Key $key worked like a charm! Thank you so much! Make sure to post that comment as the answer so I can give you credit for it. :)

using secure password with multiple users without prompt

I am trying to have my password secured and stored in a file so that I don't need to enter each time when I run the script.
First step, I ran the following, entered the password which got stored into E:\cred.txt file. The txt file now contains an encrypted password.
(Get-Credential).Password | ConvertFrom-SecureString | Out-File "E:\cred.txt"
Secondly, I ran the below Script:
$File = "E:\cred.txt"
$User = "jason#domain.com"
#### I have two different user accounts, one for admin and other for operator,
#### however both user accounts use same password.
$adminuser = $User
$operator = $User -replace "#domain.com"
#### I would need to read $File to get only the password
$pass = New-Object -TypeName System.Management.Automation.PSCredential `
-ArgumentList (Get-Content $File | ConvertTo-SecureString)
$adminuser
$operator
$pass
Output:
jason#domain.com
jason
UserName Password
-------- --------
From the output, it seems New-Object refers to both UserName and Password. And when I try to connect to systems, it fails with Authentication error. Since I already have two different usernames hard coded within the script, how should I get only the password stored in $pass? or is it possible to include all usernames ($User, $adminuser, $operator) into the cred.txt file?
Try this:
#saving credentials
Get-Credential | Export-CliXml -Path c:\credential.xml
#importing credentials to a variable
$Credential = Import-CliXml -Path c:\credential.xml
Or this:
#you could then write it to a file or, i say its a better approach to a registry key
$SecurePassword = ConvertTo-SecureString -String 'P#ssw0rd' -AsPlainText -Force | ConvertFrom-SecureString
#now you are taking it back as a secure string
$RegistrySecureString = $SecurePassword | ConvertTo-SecureString
#you can aslo see the password
$UserName = "NULL"
$Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName, $RegistrySecureString
$Password = $Credentials.GetNetworkCredential().Password
#P#ssw0rd

Using Powershell -encodedcommand to pass parameters

I'm trying to find an elegant way of passing parameters to a powershell script where the string can contain any number of special characters that would need to be escaped. For example, a complex password with special characters.
I was looking at the -encodedcommand option but it seems like this is only intended to pass an encoded script block, not an encoded version of parameters.
For example, consider the following script:
param(
[Parameter()][Alias("un")][string]$Username,
[Parameter()][Alias("pw")][string]$Password
)
Write-Host "Username: $Username"
Write-Host "Password: $Password"
The string '-un testuser -pw testpw' is base64 encoded as the following:
LQB1AG4AIAB0AGUAcwB0AHUAcwBlAHIAIAAtAHAAdwAgAHQAZQBzAHQAcAB3AA==
I tried calling the script as a .ps1 file and passing -encodedcommand with the above string but got the error 'A parameter cannot be found that matches parameter name 'encodedcommand'
So, fine, this has to be a call to powershell.exe directly.
Also tried the following:
powershell.exe -encodedcommand LQB1AG4AIAB0AGUAcwB0AHUAcwBlAHIAIAAtAHAAdwAgAHQAZQBzAHQAcAB3AA== -file Base64ParamTest.ps1
This ran the script, but the parameters had no value.
This is behaving as I would expect, but not as I would hope. Is there a way to actually pass my parameters themselves as safely encoded strings?
You have to include the script invocation as part of the command e.g.:
PS> $command = "& '$pwd\login.ps1' -un testuser -pw testpw"
PS> $bytes = [Text.Encoding]::Unicode.GetBytes($command)
PS> $encodedCommand = [Convert]::ToBase64String($bytes)
PS> powershell.exe -noprofile -encodedCommand $encodedCommand
Username: testuser
Password: testpw
Here are some notes I've taken in the past on how to deal with passwords in scripts:
###########################################################
#
# Stashing passwords to avoid interactive password prompting
#
# NOT RECOMMENDED BUT IF PASSWORD IS DYNAMIC OR WIDELY KNOWN
$passwd = ConvertTo-SecureString "Not Very Secret Password" -AsPlainText -Force
# Need a way to prompt for password and use clear text password for use with net use
$cred = Get-Credential
$cred.GetNetworkCredential().UserName
$cred.GetNetworkCredential().Password
#
# SAFE BUT NOT NECESSARILY PORTABLE APPROACH
# Depends on how DPAPI works with roaming profiles
#
# Capture once and store to file
$passwd = Read-Host "Enter password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd
$encpwd
$encpwd > $path\password.bin
# Later pull this in and restore to a secure string
$encpwd = Get-Content $path\password.bin
$passwd = ConvertTo-SecureString $encpwd
# Let's see if the rehydrate worked?
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)
$str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
$str
$cred = new-object System.Management.Automation.PSCredential 'john',$passwd
$cred
# NOTE: The "secret" required to rehyrdate correctly is stored in DPAPI - consequence:
# You can only rehydrate on the same machine that did the ConvertFrom-SecureString
#
# PORTABLE BUT NOT NECESSARILY SAFE APPROACH
#
# Let's do this so that it will work on multiple machines:
$key = 1..32 | ForEach-Object { Get-Random -Maximum 256 }
$passwd = Read-Host "Enter password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd -Key $key
$encpwd
# Could easily modify this to store username also
$record = new-object psobject -Property #{Key = $key; EncryptedPassword = $encpwd}
$record
$record | Export-Clixml $path\portablePassword.bin
# Later pull this in and restore to a secure string
$record = Import-Clixml $path\portablePassword.bin
$passwd = ConvertTo-SecureString $record.EncryptedPassword -Key $record.Key
# Let's see if the rehydrate worked?
$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($passwd)
$str = [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr)
[System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr)
$str
$cred = new-object System.Management.Automation.PSCredential 'john',$passwd
$cred
Start-Process powershell.exe -Credential $cred -NoNewWindow
# Portable is better BUT the secret (Key) is shared (stored with the password file)
# Can be reversed to original password - still much better than clear-text password
# stored in your script.