How do I encrypt a password using command line arguments? - powershell

I need a way to encrypt a password using a command line argument while in the console without prompting via Get-Credential. Example:
.\Script.ps1 -User Blah -Password ********
I have tried several different methods, using the type securestring and trying to pass Read-Host into the parameter but everything so far continue to display clear text in the console.
Here is what I have tried.
param (
[string]$user,
[securestring]$password)
param (
[string]$user,
[string]$password = $(Read-Host -AsSecureString))
Any help is greatly appreciated!

Suppose your password is thePassword.
You cannot just do .\Script.ps1 -user "Blah" -password "thePassword" and expect the thePassword to become ***********.
Here are some of the things you can do.
First, make sure your parameter types are correct. The reason your second parameter set does work is that you made the type of $password a [String]. Instead, your parameter list should look like the following.
param(
[String]$user,
[SecureString]$password = $(Read-Host -AsSecureString)
)
Now, with this code, if you do the following, it will fail.
.\Script.ps1 -user "Blah" -password "thePassword"
This is because "thePassword" is [String] and not [SecureString].
If you want to actually be able to pass the password into the script, you can create the [SecureString] outside calling the script, or have a wrapper script that calls Script.ps1, or a few other ways. For example...
# Doing it Manually in two lines
$password = Read-Host -AsSecureString
.\Script.ps1 -user "Blah" -password $password
OR
# Doing it Manually in one line
.\Script.ps1 -user "Blah" -password $(Read-Host -AsSecureString)
OR
# Taking advantage of the Default Value for $password
.\Script.ps1 -user "Blah"
# Will automatically prompt for $password upon executing
OR
# Doing it in a Wrapper Script
# You can save the following in a separate script
# OR you can add it to Script.ps1 itself
$user = Read-Host "Enter Username"
$password = Read-Host -AsSecureString "Enter Password"
.\Script.ps1 -user $user -password $password

Thanks, from your comments I think I understand your issue better now.
You want to invoke a script from the command line and provide a masked password parameter, without waiting for it to prompt you.
Unfortunately, there is no way to do this.
Your second parameter block that uses Read-Host -AsSecureString will work as long as you don't supply -password at all. The script will then prompt you for the password and it will be masked.
But this is basically the same as using Get-Credential.

Related

Invoke New-LocalUser command with a variable as the password

I'd like to have a script that creates a local user based on choices from the user.
I currently do it by putting the command in a variable then I invoke it.
$pw = Read-Host "Enter password" -AsSecureString
$command = "New-LocalUser -Name $name -Password $pw $accountparam $accexpiredate $passwordparam $pwexpiredate $canchangepwparam"
iex $command
Everything is working fine except the password, the command fails with the following error :
Unable to convert the "System.Security.SecureString" value from the "System.String" type to the "System.Security.SecureString" type
If I remove the password parameter and let PowerShell automatically ask it then it works, but I'd like to manually ask it.
Can someone help me ?
Well I fixed it, here is the solution in case someone is asking himself the same question and finds this
$command = "New-LocalUser -Name $name -Password (ConvertTo-SecureString '$pw' -AsPlainText -Force) $accountparam $accexpiredate $passwordparam $pwexpiredate $canchangepwparam"

PowerShell - Cannot validate argument on parameter 'Identity'. The argument is null

Hi I am new developing scripts in powershell and Active Directory, I am trying to run the following .ps1
#! /usr/bin/pwsh
param ([String]$dns, [String]$adminUser, [String]$adminPassword, [String]$user, [String]$newPassword)
$password = ConvertTo-SecureString -String $adminPassword -AsPlainText -Force
$pass = ConvertTo-SecureString -String $newPassword -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential ($adminUser, $password)
$session = New-PSSession -cn $dns -Credential $credential -Authentication Negotiate
Invoke-Command -Session $session -ScriptBlock {Set-ADAccountPassword -Identity $user -Reset -NewPassword ($pass)}
passing the arguments like this
./changePasswordAD.ps1 mydns myuser mypassword userToEdit NewPassword
the result obtained is the following
Set-ADAccountPassword: Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again.
Why does this happen and how can I solve it?
I am grateful in advance for your contributions
It's a scope problem. A ScriptBlock can't directly reference variables defined in another PowerShell session. New sessions are used when remoting or relying on jobs. This is hinted at by the presence and use of New-PSSession, Enter-PSSession, etc. when PSRemoting, but isn't as obvious when using jobs.
You can prefix the variable reference in the ScriptBlock with $using: like so in order to "use" the variable defined within the calling session:
{
Set-ADAccountPassword -Identity $using:user -Reset -NewPassword $using:pass
}
However, the using scope can't be used when running a ScriptBlock on the local system. Referencing a local variable would work fine if you executed the ScriptBlock locally within the same session (using the call operator &, Invoke-Command is not usually recommended for local use since it unnecessarily relies on PSRemoting). So what if we want it to run anywhere?
If the ScriptBlock needs to be able to function regardless of execution context, you can use the-ArgumentList parameter of Invoke-Command (this also applies to cmdlets like Start-Job when execution would be local but within a new session) instead to pass the variables into the ScriptBlock:
Invoke-Command -ArgumentList $user, $pass {
Param( $user, $pass )
Set-ADAccountPassword -Identity $user -Reset -NewPassword $pass
}
I added line breaks for readability but both ScriptBlocks above should function as a one-liner as well.
Note: Technically, parameters passed via -ArgumentList would be referenced as $args[0], $args[1], etc. in the order provided such as when processing raw script arguments, but as executing a ScriptBlock functions similarly to a script or... well, function, adding the Param( .... ) bit will cause the arguments provided to be assigned to positional parameters defined in the ScriptBlock; in this case, the friendlier names $user and $pass. The param names do not need to be the same as the original variable names in the parent scope.

Encrypting password or workaround

I am bit of a lazy guy, so I have created a script that opens many applications for me. Works fine as ISE opened with Administrator credentials, also opens apps with admin creds, however some of them need a different credentials.
Is it possible, to make powershell remember typed in password each time I log in and open it? (I know that variables are stored only till ps is opened)
Thing is - I cannot store a visible password in profile/text file or in a script, as this is a jump server used by many people. Is it somehow possible to type a password once, make PS encrypt it and each time I will open PS, it will decrypt it and use? or any workaround possible around this?
edit with code:
It's the only part I would like to change
$currentPW = "some password"
$credentials = New-Object System.Management.Automation.PSCredential ("domain\username",$CurrentPW)
start "c:\application.exe" -credential $credentials
It kinda works but it would require me, to input the password everytime I log in to device, so I could go for option like:
$currentPW = read-host "Provide your password"
$credentials = New-Object System.Management.Automation.PSCredential ("domain\username",$CurrentPW)
start "c:\application.exe" -credential $credentials
but this would require me to input the password each time I log in to system and open PS as it does not remember variables after restart.
So...is it even possible to make this work?^^
You can use ConvertTo-SecureString to encrypt the password using the users account key, then save this secure string to a file to load at a later time.
This assumes you are the only one with access to the logon account (not an account with shared credentials), as anyone who can logon as the account can decrypt the file.
$username = "domain\username"
$passwordFile = "C:\folder\EncryptedPassword.txt"
#if password file exists: populate $securePwd from file contents
If (Test-Path $passwordFile) {
$pwdTxt = Get-Content $passwordFile
$securePwd = $pwdTxt | ConvertTo-SecureString
}
#if no file: prompt for password, create file and populate $securePwd
Else {
$password = Read-Host "Provide your password"
$securePwd = $password | ConvertTo-SecureString -AsPlainText -Force
$securePwd | ConvertFrom-SecureString | Set-Content $passwordFile
}
$credentials = New-Object System.Management.Automation.PSCredential -ArgumentList $username, $securePwd
Start-Process "c:\application.exe" -Credential $credentials
If you have PowerShell 3.0 or newer, you can also combine Get-Credential with Export-CliXml to export a PSCredential object as an XML file. Example:
Get-Credential | Export-CliXml "C:\XML Files\credential.xml"
You can then import the credentials using Import-CliXml. Example:
$credential = Import-CliXml "C:\Xml Files\credential.xml"
Note that the password is encrypted using DPAPI, so you can only import the credentials using Import-CliXml on the same computer using the same user account that was used to export the credentials using Export-CliXml.

Run ScriptBlock with different credentials

I have a script, that determines a userid; once I have that userid, I want to run a script block against that userid using different credentials. Is this possible? Can anyone show me examples of this?
I got it, thanks to Trevor Sullivan for pointing me in the right direction. I ended up just putting my second ps1 file into a scriptblock, and running it as a job, and passing it the arguments from the main script, like this
$job = Start-Job -scriptblock {
param ($username)
some code to run against the variable that was passed in
} -Args $target -credential $Cred
$target being the variable I want to pass to my scriptblock.
$username being the parameter that the scriptblock accepts Thanks.
I know this was answered a long time ago, but I thought I'd add another option for those looking that returns data without having to retrieve it.
We can create a helper script that creates a pscredential and then uses it to start a local PSSession to run a script or scriptblock in a different user's context. You need to get the user password from somewhere, preferably entered as a secure string or retrieved from a Key Vault, but for the example our helper script will take it as a string parameter.
Script contents:
param ([string]$username,[string]$password)
$Username = 'username#domain.com'
$Password = ConvertTo-SecureString -String $password -AsPlainText -Force
$Credential = New-Object -Type PSCredential($Username,$Password)
$Session = New-PSSession -Credential $Credential
Invoke-Command -Session $Session -FilePath C:\Path\to\some\script.ps1
You can also use -ScriptBlock instead of -FilePath if you have a simple chunk of code to run or you have converted a script to a script block.
Hope this helps somebody out!
Security context for a session is established when the session is initialized. You can't arbitrarily run commands under a different context within the session. To run under a different security context (set of credentials) you'll need to initialize a new session under those credentials and run it there.
If you look at the help for Invoke-Command, you'll note that the -Credential parameter is only valid in parameter sets that specify a remote session by computername, uri, or session. You can also use -credential with Start-Job, which will run the command in a new session on the local machine.
This code will launch PowerShell in Administrator mode using the credentials provided and then run the code in the script block. There might be others ways but this works for me.
$account= # AD account
$password = # AD user password
$passwordSecure = ConvertTo-SecureString ($password) -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential ($account, $passwordSecure)
$ScriptBlock = {
whoami
start-sleep 3
}
 
# Run PowerShell as Administrator with Custom Crednetails
start-Process powershell.exe -Credential $Cred -ArgumentList "-Command Start-Process powershell.exe -Verb Runas -ArgumentList '-Command $ScriptBlock'" -Wait

Expect and Spawn with PowerShell

Is there any way to do expect and spawn with powershell.
I have to parse a CLI program with powershell which is asking for password is there any way to input this password via powershell.
In perl or python even in bash you can use expect/spawn
Is there any solution in powershell ?
One way to do this would be to create a text file with the encrypted password one time, then call this file as the password in as many scripts as necessary.
Create the password file once:
$pwd = Read-Host 'Enter password for encrypting:' -AsSecureString | ConvertFrom-SecureString | Out-File -Path 'C:\SpecialFiles\CLIPassword.txt'
Then you can use it whenever it's needed:
$pass = (Get-Content -Path 'C:\SpecialFiles\CLIPassword.txt' | ConvertTo-SecureString)
$creds = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList (<insert CLI UserName>, $pass)
Then when you need to supply the username and password to your script, you simply pipe
$creds | <command>
or if the command supports the -Credential parameter
<command> -Credential $creds
If your command needs the user name and password entered separately, you can do that by specifying the property name:
<command> -UserName $creds.UserName -Password $creds.Password
You can use Read-Host to prompt the user for input. See here for more information.
$pass = Read-Host 'What is your password?' -AsSecureString
$decodedpass = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($pass))
I'm sure what you want to do with spawn, but you can execute other scripts or executables by just calling them
.\MyOtherScript.ps1