We are trying to store a user password in the registry as a secure string but we can not seem to find a way to convert it back to plain text. Is this possible with SecureString?
Here is the simple test script we are trying to use...
Write-Host "Test Start..."
$PlainPassword = "#SomethingStupid" | ConvertTo-SecureString -AsPlainText -Force
$BSTR = ` [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassword)
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
Write-Host "Password is: " $PlainPassword
Read-Host
This is the error we are getting...
The term ' [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR'
is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
At C:\test.ps1:4 char:71
+ $BSTR = ` [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR
<<<< ($PlainPassword)
+ CategoryInfo : ObjectNotFound: (
[System.Runtim...ureStringToBSTR:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Cannot find an overload for "PtrToStringAuto" and the argument count: "1".
At C:\test.ps1:5 char:75
+ $PlainPassword =
[System.Runtime.InteropServices.Marshal]::PtrToStringAuto <<<< ($BSTR)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
What is with the backtick in the $BSTR = ... line? I agree with Graham above. If I remove the backtick it work just fine:
$PlainPassword = "#SomethingStupid" | ConvertTo-SecureString -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassword)
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
Write-Host "Password is: " $PlainPassword
Outputs:
Password is: #SomethingStupid
You're not trying to run this on something like Windows RT or some other PowerShell configuration where the language is restricted - are you?
Here's a kludgy but much simpler way to decrypt a secure string, taking advantage of the fact that the PSCredential class has a constructor that accepts the password as a secure string and a method (GetNetworkCredential) that returns that password in plain text:
(New-Object System.Management.Automation.PSCredential 'N/A', $secure_string).GetNetworkCredential().Password
Although it's intended for use with credentials, there's nothing that prevents you from using this to decrypt any secure string* regardless of purpose, supplying a dummy argument for the username (the username argument can't be null or an empty string, but any meaningless string will do).
* Under the context of the account that encrypted the secure string to begin with, of course
Related
I am working on a script that will run New-RemoteMailbox with a generated string as the password argument. I have specific requirements for generating the password. It should begin with "Welcome" and then include some numbers and a few acceptable symbols. These are OTPs that will be used shortly after creation so I don't need them to be very strong.
Below is the code where I generate the password and convert it to a secure string:
[string]$Prefix = 'Welcome'
$Numbers = -join ((48..57) | Get-Random -Count 3 | % {[char]$_})
$Symbols = -join ((35..38)+(42)+(63..64)+(33) | Get-Random -Count 2 | % {[char]$_})
$Password = $Prefix + $Numbers + $Symbols
Write-Output "Temporary Password: $Password"
$Password = ConvertTo-SecureString -string $Password -AsPlainText -Force
Then here's where I use the variable later:
New-RemoteMailbox -Name "$FullN" -Password $Password -UserPrincipalName $Address -FirstName $FirstN -LastName $LastN -ResetPasswordOnNextLogon $true -SamAccountName $SamName
When I do that, I get the following error:
Cannot process argument transformation on parameter 'Password'. Cannot convert the "System.Security.SecureString" value of type "System.String" to type "System.Security.SecureString".
+ CategoryInfo : InvalidData: (:) [New-RemoteMailbox], ParameterBindin...mationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,New-RemoteMailbox
The rest of this script seems to work without issue. This particular problem only showed up once I introduced the custom password generation (the prebuilt password method often recommended online did not suit our needs, as it generates (){}[]-./\|=+;:, potentially needlessly complicating the process for a new user, but the method was not causing this error). I see there have been questions about this particular error before, but the solution to the ones I've seen was using ConvertTo-SecureString, which I have in the code. I also can add Write-Output $Password any time before the conversion and it seems to output what I would expect (example: Welcome267#&).
Any ideas?
As #MathiasR.Jessen said in the replies, the issue was that I declared [String]$Password (not shown in the question), which prevented it from converting to a secure string. Changing the declaration or just using a new variable both seem to work.
If i run this code it will run the file
{Write-host "Please Enter the email address of the user you want to check the permissions"
$user = Read-Host
Powershell.exe C:\Temp\Report\Reports.ps1}
But if i run it like this which is what i need to do
{ Write-host "Please Enter the email address of the user you want to check the permissions"
$user = Read-Host
Powershell.exe C:\Temp\Report\Reports.ps1 -processOneDrive $true -OneDriveEmail $user}
I get this error
Powershell.exe : C:\Temp\ReportSharedFiles\ReportSharedFiles.ps1 : Missing an argument for parameter 'OneDriveEmail'. Specify a
At C:\Temp\ReportSharedFiles\Full Exchange Script Menu.ps1:88 char:2
+ Powershell.exe "c:\Temp\ReportSharedFiles\ReportSharedFiles.ps1" -pr ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (C:\Temp\ReportS...il'. Specify a :String) [], RemoteException
+ FullyQualifiedErrorId : NativeCommandError
parameter of type 'System.String' and try again.
At line:1 char:71
+ ... haredFiles\ReportSharedFiles.ps1 -processOneDrive True -OneDriveEmail
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [ReportSharedFiles.ps1], ParameterBindingException
+ FullyQualifiedErrorId : MissingArgument,ReportSharedFiles.ps1
What am i doing wrong and how can i get this to work? any help will be appreciated
I believe its asking you for a sting parameter in the error
parameter of type 'System.String' and try again.
Hope this works out>
{ [string]$user = Read-Host "Please Enter the email address of the user you want to check the permissions"
Powershell.exe C:\Temp\Report\Reports.ps1 -processOneDrive $true -OneDriveEmail $user}
Type String >
I have figured it out. It seems when running the powershell script within another script and to have the arguments in. when it comes to the -processOneDrive $true It tried to convert that to boolem which caused errors. i changed this to 1 which im sure means true so code looks like this
Powershell.exe "c:\Temp\Report\Reports.ps1" -processOneDrive 1 -OneDriveEmail $user
Now it runs smoothly. Thanks for everyone that tried to help me with this :)
We have one script which has been used to store password to a text file and then the mail script recalls/reuses this password from the password text file to run the master script.
I am getting below error,after changing the password.
Script used to generate secure password:
"Password" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "D:\Scripts\Password.txt"
Error we are getting now:
At C:\Scripts\Lync_HealthCheck_Prod.ps1:1199 char:82
+ $PasswrdS = Get-Content C:\Windows\System32\SecStrng.sec | convertto-securest
ring <<<<
+ CategoryInfo : InvalidArgument: (:) [ConvertTo-SecureString], C
ryptographicException
+ FullyQualifiedErrorId : ImportSecureString_InvalidArgument_Cryptographic
Error,Microsoft.PowerShell.Commands.ConvertToSecureStringCommand
New-Object : Exception calling ".ctor" with "2" argument(s): "Cannot process ar
gument because the value of argument "password" is null. Change the value of ar
gument "password" to a non-null value."
At C:\Scripts\Lync_HealthCheck_Prod.ps1:1218 char:27
+ $Creds1 = New-Object <<<< System.Management.Automation.PSCredential -A
rgumentList $CheckUser1, $PasswrdS
+ CategoryInfo : InvalidOperation: (:) [New-Object], MethodInvoca
tionException
+ FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.Power
Shell.Commands.NewObjectCommand
Would be great if you can help.
The error message claims that you are handling null values:
"Cannot process argument because the value of argument "password" is null.
So, double-check that you actually are reading good content from the password file. The location in C:\Windows\System32 very hints that the process is looking for it from wrong location.
$PasswrdS = Get-Content C:\Windows\System32\SecStrng.sec
Exactly same problem, due to NTFS rights mismatch on the sec file. Get-content is OK, but not call of Convertto-SecureString.
User who created the password file was not the user who executed the program.
I put total control on this file for both users. It is OK now.
To be more accurate : I connected with account needed to run, drop and recreated the secure file containing credentials. This file is useful only for this account
I'm working in PowerShell and I have code that successfully converts a user entered password into plain text:
$SecurePassword = Read-Host -AsSecureString "Enter password" | convertfrom-securestring | out-file C:\Users\tmarsh\Documents\securePassword.txt
I've been tried several ways to convert it back, but none of them seem to work properly. Most recently, I've tried with the following:
$PlainPassword = Get-Content C:\Users\tmarsh\Documents\securePassword.txt
#convert the SecureString object to plain text using PtrToString and SecureStringToBSTR
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassword)
$PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important step to keep things secure
This gives me an error as well.
Cannot convert argument "s", with value: "01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e43000000000200000000000366000
0c0000000100000008118fdea02bfb57d0dda41f9748a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8
bc271400000038c731cb8c47219399e4265515e9569438d8e8ed", for "SecureStringToBSTR" to type "System.Security.SecureString": "Cannot convert the "01000000
d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f9748a05f10
000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569438d8e8
ed" value of type "System.String" to type "System.Security.SecureString"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:14 char:1
+ $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($PlainPassw ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Cannot find an overload for "PtrToStringAuto" and the argument count: "1".
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:15 char:1
+ $PlainPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
Cannot convert argument "s", with value: "", for "ZeroFreeBSTR" to type "System.IntPtr": "Cannot convert null to type "System.IntPtr"."
At C:\Users\tmarsh\Documents\Scripts\Local Admin Script\PlainTextConverter1.ps1:16 char:1
+ [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR) #this is an important ste ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Password is: 01000000d08c9ddf0115d1118c7a00c04fc297eb0100000026a5b6067d53fd43801a9ef3f8ef9e430000000002000000000003660000c0000000100000008118fdea02bfb57d0dda41f97
48a05f10000000004800000a000000010000000c50f5093f3b87fbf9ee57cbd17267e0a10000000833d1d712cef01497872a3457bc8bc271400000038c731cb8c47219399e4265515e9569
438d8e8ed
Does anyone know of a way that will work for this?
You are close, but the parameter you pass to SecureStringToBSTR must be a SecureString. You appear to be passing the result of ConvertFrom-SecureString, which is an encrypted standard string. So call ConvertTo-SecureString on this before passing to SecureStringToBSTR.
$SecurePassword = ConvertTo-SecureString $PlainPassword -AsPlainText -Force
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecurePassword)
$UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)
[Runtime.InteropServices.Marshal]::ZeroFreeBSTR($BSTR)
You can use PSCredential.GetNetworkCredential() :
$UnsecurePassword = (New-Object PSCredential 0, $SecurePassword).GetNetworkCredential().Password
The easiest way to convert back it in PowerShell
[System.Net.NetworkCredential]::new("", $SecurePassword).Password
In PS 7, you can use ConvertFrom-SecureString and -AsPlainText:
#Requires -Version 7.0
$UnsecurePassword = ConvertFrom-SecureString -SecureString $SecurePassword -AsPlainText
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.security/ConvertFrom-SecureString?view=powershell-7#parameters
ConvertFrom-SecureString
[-SecureString] <SecureString>
[-AsPlainText]
[<CommonParameters>]
I am trying to implement a way to use a stored secure string so that my SFTP password is not visiable in the script. For example, I'd like to generate a variable $password that could be used instead. I found the following examples online but I can't get them to work unfortunately. I've done something similar in the past but can find my notes or links to the website that explained how to complete the task.
read-host -assecurestring | convertfrom-securestring | out-file C:\securestring.txt
$pass = cat C:\securestring.txt | convertto-securestring
$mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist "test",$pass
Here is my script. Here is a link to the snapin if anyone is interested. http://www.k-tools.nl/index.php/sftp-in-powershell/
#Add the SFTP snap-in
Add-PSSnapin KTools.PowerShell.SFTP
#Define some variables
$sftpHost = "ftp.domain.com"
$userName = "user"
$userPassword = "password"
$localFile = "C:\bin\emp1.xlsx"
#Open the SFTP connection
$sftp = Open-SFTPServer -serverAddress $sftpHost -userName $userName -userPassword $userPassword
#Upload the local file to the root folder on the SFTP server
$sftp.Put($localFile)
#Close the SFTP connection
$sftp.Close()
Again, thanks for everyones help!
UPDATE
I tried this:
$pass = cat c:\bin\ftpcreds.txt | convertto-securestring
$mycred = new-object -typename System.Management.Automation.PSCredential -argumentlist "usertest1",$pass
$sftpHost = "ftp.domain.com"
$userName = $mycred.username
$userPassword = $mycred.password
$sftp = Open-SFTPServer -serverAddress $sftpHost -userName $userName -userPassword $userPassword
$sftp.Put($localFile)
$sftp.Close()
And get this error:
Method invocation failed because [Tamir.SharpSsh.jsch.JSchException] doesn't contain a method named 'Put'.
At C:\bin\SFTP Upload Samples.ps1:21 char:1
+ $sftp.Put($localFile)
+ ~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Method invocation failed because [Tamir.SharpSsh.jsch.JSchException] doesn't contain a method named 'Close'.
At C:\bin\SFTP Upload Samples.ps1:36 char:1
+ $sftp.Close()
+ ~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
Any suggestions?
Thanks!
If your SFTP is wanting to use a decrypted version of your secured password then you'll want to extract it from your $mycred by:
$userpassword = $mycred.getnetworkcredential().password.tostring()