How do you decrypt securestring in powershell [duplicate] - powershell

This question already has answers here:
Convert a secure string to plain text
(4 answers)
Closed 2 years ago.
$Variable = Read-Host "Enter thing" -AsSecureString
Will prompt you for input and save it as a secure string to variable. How do I decrypt a secure string variable?
PS C:\Users\Todd> $Variable
System.Security.SecureString

A security warning first:
Converting a secure string to a regular [string] instance defeats the very purpose of using [securestring] (System.Security.SecureString) to begin with: you'll end up with a plain-text representation of your sensitive data in your process' memory whose lifetime you cannot control.
Also, note that secure strings are generally not recommended for use in new code anymore: they offer only limited protection on Windows, and virtually none on Unix-like platforms, where they aren't even encrypted.
PowerShell v7+ now offers ConvertFrom-SecureString -AsPlainText to convert a secure string to its - unsecured - plain-text representation:
# PowerShell 7.0 or higher.
$password = Read-Host "Enter password" -AsSecureString
$plainTextPassword = ConvertFrom-SecureString -AsPlainText $password
In PowerShell v6- (including Windows PowerShell), you can use the following:
$password = Read-Host "Enter password" -AsSecureString
$plainTextPassword = [Net.NetworkCredential]::new('', $password).Password

$password = Read-Host "Enter password" -AsSecureString
$password = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$password = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($password)
echo $password
pause
To convert Read-Host SecureStrings to normal strings, you use
$NewVaraible = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($ReadVariable)
$NewNewVariable = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($NewVariable)
Or you could just update the existing variable:
$ReadVaraible = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($ReadVariable)
$ReadVariable = [Runtime.InteropServices.Marshal]::PtrToStringBSTR($ReadVariable)
Thank you #mklement0 for your insightful comments; updated answer accordingly to mklement0's comment

Related

Pass Stored Creds to bat file

I am trying to figure out if there is a way to take a stored credential in Windows Cred vault and pass it to a bat file that needs the credentials. I found a very old bat file that has a username and password in clear text. These are used to authenticate against a portal and have to be read by the bat in clear text. I have stored credentials on my server that I want to use so I can close this security gap but I am not 100% sure how to pass the password because it has to be in clear text. Here is what I have:
$creds = Get-StoredCredential -Target "Username"
$password = $creds.Password
$username = $creds.UserName
Start-Process cmd.exe "/c C:\trigger.bat `"argument1`" $username $password `"Argument2`" Argument3" -NoNewWindow -Verbose
When I enter the password in clear text in my line it works. If I use $password it throws an auth error. I assume that this is because the $password is a stored PSObject and isn't getting passed to cmd "correctly". Is there a way around this?
PS: Get-StoredCredential is from the CredentialManager module.
If $creds contains a PSCredential object, then you should be able to replace this:
$password = $creds.Password
with this:
$password = $creds.GetNetworkCredential().Password
Get-StoredCredential, when called without -AsCredentialObject, yields PSCredential instances.
The PSCredential.Password property you are accessing is not a String but a SecureString, so you cannot retrieve the plain text password like you are attempting.
Based on Convert a secure string to plain text you can use the PSCredential to get a NetworkCredential and then use its Password property...
$password = $creds.GetNetworkCredential().Password
In any case, when you get an authentication error using $username and $password you should ensure those variables contain the values you expect them to.

Box input for Administrator password with secure string

Need little help ,
i need to create a Input Box that user your enter new Local Administrator Password .
very simple , so i wrote this script but it does not work ,
can you help me ?
$pass = Read-Host "Enter Password" -AsSecureString
net user administrator $pass
What Read-Host -AsSecureString returns is an instance of System.Security.SecureString, which by design cannot be used as plain text.
You can force its re-conversion to plain text as follows, but note that the very point of using a secure string is to avoid plain-text representations.
Given that calling external programs such as net user requires a plain-text representation, it's more secure to use .NET alternatives that can work directly with SecureString instances, if available.
If you must use net.exe, use the following:
# Read the password masked, into a SecureString instance.
$passSecure = Read-Host "Enter Password" -AsSecureString
# INSECURE: Force reconversion to plain text.
$passPlainText = [pscredential]::new('dummy', $pass).GetNetworkCredential().Password
# INSECURE: Pass the plain-text representation to `net user`
net user administrator $passPlainText

Is there a way to use ConvertFrom-SecureString and ConvertTo-SecureString with any user?

I'm using the following to create the password file:
$path = "C:\Users\USER\Desktop"
$passwd = Read-Host "enter desired password" -AsSecureString
$encpwd = ConvertFrom-SecureString $passwd
$encpwd > $path\filename.bin
Then calling the file with:
# define path to store password and input password
$path = "C:\Users\USER\Desktop"
# get the encrypted password from the path
$encpwd = Get-Content $path\filename.bin
# convert file to secure string
$passwd = ConvertTo-SecureString $encpwd
# define needed credential
$cred = new-object System.Management.Automation.PSCredential 'WIN-SERVER\AdminForQB',$passwd
# go to DVD drive launch setup.exe as user with privileges to launch the program with no user input required
Set-Location "C:\Program Files (x86)\Intuit\QuickBooks 2017\"
Start-Process PowerShell -windowstyle hidden -Cred $cred -ArgumentList .\QBW32PremierAccountant.exe
My goal is be able to run QB2017 with admin privs without giving the user admin privs. The issue I am having is that I have to generate the password file on each user or I get the following error if a user trys to use one generated from another user:
Key not valid for use in specified state.
Is there a way to use this method without generating a key per user?
When you use ConvertTo-SecureString and ConvertFrom-SecureString without a Key or SecureKey, Powershell will use Windows Data Protection API (DPAPI) to encrypt/decrypt your strings. This means that it will only work for the same user on the same computer.
When you use a Key/SecureKey, the Advanced Encryption Standard (AES) encryption algorithm is used. You are able to use the stored credential from any machine with any user so long as you know the AES Key that was used.
More info on this topic (with example code)
Note: This is only Security through obscurity, which isn't good practice. If you store the Key on the same computer as the encrypted password, it's not much more secure than plain text passwords!
PowerShell is the wrong solution for this.
To fix this you should give them read/write access to the folders and registry key QB2017 needs access to. If you still have issues, create a Shim using Microsoft's Application Compatibly Toolkit.
https://deployhappiness.com/fixing-applications-that-require-administrator-rights/

IIS app pool identity is entered incorrectly from powershell script

I'm writing a powershell script to install my application and configure the web application identity for a specific user.
The code i'm using is:
$pool.processModel.identityType = 3
$AppPoolUsername = Read-Host "User name(domain\username)"
$AppPoolPassword = Read-Host "Password" -AsSecureString
$pool.processModel.userName = [string]$AppPoolUsername`enter code here`
$pool.processModel.password = [string]$AppPoolPassword
After I ran the script I ran the application and the App Pool is stopped.
If i will manually enter the app pool identity it will not stopped and the web application will work.
I tried to convert the password from a securestring to a regular string with no success with this code:
$AppPoolPassword = Read-Host -Prompt "Password" -AsSecureString
$pool.processModel.userName = [string]$AppPoolUsername
$pool.processModel.password = ConvertFrom-SecureString -SecureString $AppPoolPassword
I get "01000000d08c9ddf0115d1118c7a00c04fc297eb010000006876492ae8edf3429d809bb3ca213d910000000002000000000003660000c000000010000000ebd2f4fc7a59a92ad8cb2c4
9b99498fc0000000004800000a0000000100000007ffdc206c4eeb7c67237d24e575f86ff08000000fe8c91a31879d93014000000fee1ff6c8aa4fe66e9debe245e7ea3fd26fc823a" when checking the app pool password.
Is that right or should i get the regular string i input?
Am I at the right direction?
Here is one way to do it, using NetworkCredential to unwrap the hidden SecureString that's not supported by the application pool configuration API.
$AppPoolUsername = Read-Host "User name(domain\username)"
$AppPoolPassword = Read-Host "Password" -AsSecureString
# We cannot pass the password as a SecureString directly to
# the app pool configuration. NetworkCredential is at least
# one possible way to access the hidden clear text password.
$netcred = New-Object System.Net.NetworkCredential "unused",$AppPoolPassword
$pool.processModel.identityType = 3
$pool.processModel.userName = $AppPoolUsername
$pool.processModel.password = $netcred.Password
$pool | Set-Item
Not sure I completely understand what you're saying but are you calling
$pool | set-item
Are you saying that after running the script the AppPool works but is just stopped? If so, you can easily start the AppPool using Start-WebAppPool -Name AppPoolName
Or you can try
Set-ItemProperty iis:\AppPools\AppPoolName -name processModel -value #{userName="Domain\UserName";password="Password";identitytype=3}
The processmodel's password MUST be a plain text unfortunately.
For the secureString, it cannot directly be assigned to the password property.
#Oskar Berggren has a nice way around it but if you get the string directly from a 'Read-Host', the best would be to keep it as a plain text (Remove -AsSecureString) and assign it directly to the password property. In the contrary, if you plan on persisting the secureString, then use #Oskar Berggren's way to get your plain password back.
Chen,
When you send your password into the process model password field, it needs to be plain text. You are reading the password from a user as a secure string (which is correct) but you need to convert it back to plain text. The conversion command that I use is: $textpassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($securestringpassword))
So, updating your code sample, the code below should work for you:
#input from user
$AppPoolUsername = Read-Host "User name(domain\username)"
$AppPoolPassword = Read-Host "Password" -AsSecureString
$AppPoolName = Read-Host "App pool name"
#instantiate new app pool
$newAppPool = New-Item IIS:\AppPools\$AppPoolName;
$newAppPool.processModel.identityType = 3;
$newAppPool.processModel.userName = $AppPoolUsername
$newAppPool.processModel.password = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($AppPoolPassword))
$newAppPool | Set-Item;
Hopefully this helps.

How can I use powershell's read-host function to accept a password for an external service?

I have a script I'm writing that makes a connection to a SOAP service. After the connection is made, I need to pass in a the username/pass with every command I send. The problem I have is that when I use read-host to do this, my password is shown in cleartext and remains in the shell:
PS C:\Users\Egr> Read-Host "Enter Pass"
Enter Pass: MyPassword
MyPassword
If I hide it with -AsSecureString, the value can no longer be passed to the service because it is now a System.Security.SecureString object:
PS C:\Users\gross> Read-Host "Enter Pass" -AsSecureString
Enter Pass: **********
System.Security.SecureString
When I pass this, it does not work. I don't care about the passwords being passed to the service in cleartext, I just don't want them sticking around on a user's shell after they enter their password. Is it possible to hide the Read-Host input, but still have the password stored as cleartext? If not, is there a way I can pass the System.Security.SecureString object as cleartext?
Thanks
$Password is a Securestring, and this will return the plain text password.
[Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($Password))
You can save the password(input) as a variable and pass it to your service. If the code is run in a script or as a function, the variable containing the password will be deleted after it's done(they are stored in a temp. local scope). If you run the commands in the console(or dot-source the script like . .\myscript.ps1), the password variable will stay in the session scope, and they will be stored until you delete it or close the session. If you want to be sure the variable is removed after your script is run, you can delete it yourself. Like this:
#Get password in cleartext and store in $password variable
$password = Read-Host "Enter Pass"
#run code that needs password stored in $password
#Delete password
Remove-Variable password
To read more about how variables are stored in scopes, check out about_Scopes
There is a way to do this in PowerShell versions 6.x+:
$password = read-host -maskinput "Enter password"
, thanks to jborean93 for pointing this out to me.