PowerShell : Problem with ConvertTo-SecureString and ConvertFrom-SecureString INSIDE a PSSession - powershell

I try to use ConvertTo- and ConvertFrom-SecureString in 2 Powershell scripts, but I've got a problem generating encrypted passwords with a dynamic profile, and then reading/deciphering them with the SAME profile on the SAME machine.
My script ask an Interactive User (IU) to type credential for a Task User (TU).
The logic is to create a PSSession fot the TU inside the powershell session of the IU, to generate a secure string from a plain text (or read-host), and to convert it to regular string to export it to a file.
$scriptUser = Read-Host "Entrez le nom de l'utilisateur qui va chiffrer/utiliser le fichier de mot de passe (domain\user)"
$scriptCredential = Get-Credential -Message "Veuillez entrer le mot de passe de l'utilisateur $scriptUser" -User $scriptUser
$Crypt = New-PSSession -Credential $scriptCredential -ComputerName localhost
if ($Crypt)
{
Enter-PSSession $Crypt
$Texte = "JULIEN"
ConvertTo-SecureString $Texte -AsPlainText -Force | ConvertFrom-SecureString | Set-Content -Path C:\PathToFile\testcrypt_adm_task.txt
Exit-PSSession
}
But when I try to read the content of the file using ConvertFrom-SecureString with the TU (interactive or task scheduler): no way!
> PS C:\PathToFile> Get-Content .\testcrypt_adm_task.txt |
> convertto-securestring convertto-securestring : Key not valid for use
> in specified state. At line:1 char:40
> + Get-Content .\testcrypt_adm_task.txt | convertto-securestring
> + ~~~~~~~~~~~~~~~~~~~~~~
> + CategoryInfo : InvalidArgument: (:) [ConvertTo-SecureString], CryptographicException
> + FullyQualifiedErrorId : ImportSecureString_InvalidArgument_CryptographicError,Microsoft.PowerShell.Commands.Conv ertToSecureStringCommand
If I do the exact same command with my IU, no problem, as if the key used to encrypt my Securestring was bound to my IU and not my TU.
The point is I've got a problem really understanding what is really loaded with PSSession, as the secure-string is readable by my IU and not my TU, even if the encryption operation has been done in a PSSession with the TU creds...
Doesn't Enter-PSSession mean to really enter a session, with all the environment with it ?
Is there something I am missing concerning the environment loaded with Enter-PSSession ?
Thanks for your help

Import-clixml is the only way to save a PowerShell object to disk. Export-clixml will let you import the file into a PowerShell object.
Try changing "| Set-Content -Path C:\PathToFile\testcrypt_adm_task.txt" to "| Export-Clixml -Path C:\PathToFile\testcrypt_adm_task.txt"
When you ready to read it use $mysavedpassword = import-clixml c:\PathToFile\testcrypt_adm_task.txt

Probably you created the secure-string using some different user and trying to covert back to plain text using different user. Please use the same user for making it secure and convert it back to plain text.

Related

Issues with running script without credentials dialog box

I'm trying to run through a powershell script that creates a computername and places that computer in the right OU in AD. The only issue is I need to enter credentials for this to happen, but I want to do it without having to enter the credentials into the powershell credential dialog box.
I used the System.Management.Automation.PSCredential, but that is was apparently was giving me the dialog box.
$secpasswd = ConvertTo-SecureString 'xxxxxx' -AsPlainText -Force
$mycreds = New-Object System.Managemnet.Automation.PSCredential("xxxx", $secpasswd)
Trying to the use the code above without a dialog box popping up
New-Object : Cannot find type [System.Managemnet.Automation.PSCredential]: verify that the assembly containing this type is loaded.
At line:2 char:12
+ $mycreds = New-Object System.Managemnet.Automation.PSCredential("xxxx ...
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidType: (:) [New-Object], PSArgumentException
+ FullyQualifiedErrorId : TypeNotFound,Microsoft.PowerShell.Commands.NewObjectCommand
You made a typo on "Managemnet". It should be -
$mycreds = New-Object System.Management.Automation.PSCredential("xxxx", $secpasswd)
It appears you made a typo in your code: Managemnet should be Management, as in System.Management.Automation. That is why your error is being thrown.
However, there is no need to use the full definition for PSCredential. Use the following instead:
$secpasswd = ConvertTo-SecureString 'xxxxxx' -AsPlainText -Force
$mycreds = New-Object PSCredential("xxxx", $secpasswd)
This does not show a dialog box.

How to replace a string in file on remote computer in Powershell?

I have a VM running Windows Server 2012.And some intended services on it. I want to change a configuration file on this VM machine remotely from my desktop pc.
Currently I change this configuration file by mapping the C: drive of the remote server and then changing the file. Now this blocks me from changing multiple servers as I can't map multiple server c: simultaneously to same drive. Also, mapping hundreds of drives wouldn't be ideal.
The way I am changing the file by mapping drive is:
$password = <password text> | ConvertTo-SecureString -asPlainText -Force
$username = "admin"
$credential = New-Object System.Management.Automation.PSCredential($username,$password)
net use Z: \\$ipAddress\C$ <password> /user:admin type 'z:\Program Files\lalaland\Data\Settings.xml'
(Get-Content 'z:\Program Files\lalaland\Data\Settings.xml') | ForEach-Object { $_ -replace $oldString, $newString } | Set-Content 'z:\Program Files\lalaland\Data\Settings.xml'
type 'z:\Program Files\lalaland\Data\Settings.xml'
net use z: /delete
Therefore I searched for a better option and found this script at https://gallery.technet.microsoft.com/scriptcenter/PowerShell-Replace-String-58fbfa85 but it doesn't work for me.
I am using this script as :
.\Replace-StringInFile.ps1 -ComputerName <RemoteComputerHostName> -TargetPath 'C:\Program Files\lalaland\Data' -Fil
eName Settings.xml -Replace $oldString -ReplaceWith $newString -Credential (Get-Credential)
when I run the command credential window pops up asking for username and password. I enter the username and password that I used for mapping the drive, but it throws the following error:
New-PSSession : [<RemoteHostName>] Connecting to remote server <RemoteHostName> failed with the following error message : The user name or password is incorrect. For more information, see the
about_Remote_Troubleshooting Help topic.
At D:\workspace\Replace-StringInFile.ps1:84 char:14
+ ... $Session = New-PSSession -ComputerName $Computer -Credential $Creden ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OpenError: (System.Manageme....RemoteRunspace:RemoteRunspace) [New-PSSession], PSRemotingTransportException
+ FullyQualifiedErrorId : LogonFailure,PSSessionOpenFailed
what I don't understand is when I map the drive with the same credentials it works fine but using the other script, which internally uses New-PSSession doesn't work.
Any idea ?
I was able to do this using the following cmdlet:
function Edit-RemoteFileStringReplace
{
[cmdletbinding()]
param([Parameter(Mandatory=$true)][ValidateScript({$_ -match [IPAddress]$_ })][string]$Address,
[Parameter(Mandatory=$true)][string]$FilePath,
[Parameter(Mandatory=$true)][string]$Replace,
[Parameter(Mandatory=$true)][string]$ReplaceWith,
[Parameter(Mandatory=$true)][System.Management.Automation.PSCredential]$Credential
)
$DriveLetter=""
$FilePathWithoutDriveLetter=""
$DriveName = $Address.replace('.','x')
$DriveName = "PSDrive_$DriveName"
$DriveLetter = (Get-DriveLetterFromPath -Path $FilePath).Substring(0,1)
$FilePathWithoutDriveLetter = Remove-DriveLetterFromPath -Path $FilePath
$MappedFilePath="$DriveName" + ":$FilePathWithoutDriveLetter"
New-PSDrive -Name $DriveName -PSProvider FileSystem -Root \\$Address\$DriveLetter$ -Credential $Credential -ErrorAction Stop
(Get-Content $MappedFilePath) | ForEach-Object { $_ -replace $Replace, $ReplaceWith } | Set-Content $MappedFilePath
Remove-PSDrive -Name $DriveName
}

Invoke-Command with -credentials

I want to invoke a command on a remote server, I do not want to have to put in the password to run the script. I've tried encrypting the password and storing it in a txt file.
$username = "Mydomain\service.account"
$password = cat C:\username-password-encrypted.txt | convertto-securestring
$cred = new-object -typename System.Management.Automation.PSCredential - argumentlist $username, $password
Invoke-command $cred -Computer myserver -scriptblock {param([string]$LocalUser); Add-PSSnapin Citrix* ; Get-BrokerSession -max 10000 | Where-Object brokeringusername -eq "mydomain\$($LocalUser)" | Stop-BrokerSession} -ArgumentList $user
Here is the error I get
Invoke-Command : A positional parameter cannot be found that accepts argument 'System.Management.Automation.PSCredential'.
At \\uncpath\citrix\Installation Media\Citrix\Ticketing_script\Ticketing_Script - Copy (3).ps1:70 char:1
+ Invoke-command $cred -Computer MyServer -scriptblock {param([s ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : PositionalParameterNotFound,Microsoft.PowerShell.Commands.InvokeCommandCommand
There has to be an easier way to run this command on myserver without having to put in the password every time.
You just have to specify the -Credential parameter:
Invoke-command -Credential $cred -Computer myserver -scriptblock {param([string]$LocalUser); Add-PSSnapin Citrix* ; Get-BrokerSession -max 10000 | Where-Object brokeringusername -eq "mydomain\$($LocalUser)" | Stop-BrokerSession} -ArgumentList $user
4 years later but here goes:
Frode F. had the right idea in the comments. Your third line has - argumentlist but it must be -ArgumentList, otherwise it will throw New-Object : A positional parameter cannot be found that accepts argument 'ArgumentList'.
Also, when I copy and run your exact code it does not throw the same error which leads me to believe that the code you're running is not the same as the one you've written here. Here are the different errors you've received and the reasons for them:
Incorrect syntax
A positional parameter cannot be found that accepts argument 'System.Management.Automation.PSCredential'.
This means that you've not specified the flag correctly, Powershell thinks you're using a flag or parameter called System.Management.Automation.PSCredential. You can simulate this by adding a hyphen like New-Object -TypeName - System.Management.Automation.PSCredential and see for yourself, so your syntax is wrong somewhere.
Incorrect password format
Cannot find an overload for "PSCredential" and the argument count: "2".
This means that the $Password is not in the correct format. You're importing a file called password-encrypted.txt but after this you pass it to ConvertTo-SecureString. Are you sure that the information in the password-encrypted.txt file is passed to both ConvertTo-SecureString and then to ConvertFrom-SecureString before you saved it, like so?
"MyPassword" | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString | Out-File "C:\username-password-encrypted.txt"
For more information on how to deal with passwords in Powershell, see this post that goes into detail on how to do credentials in Powershell:
https://www.pdq.com/blog/secure-password-with-powershell-encrypting-credentials-part-1/
In conclusion
If you run the code you've provided here using both -ArgumentList (instead of - argumentlist) and -Credentials $creds like others have suggested it should run fine. You're most likely not running the code that you've provided here because with these two adjustments the code runs.

Powershell SecureString Encrypt/Decrypt To Plain Text Not Working

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

Powershell - Secure String for Passwords and SFTP

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()