5

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?

1
  • My Plan B here is to just Base64 encode the password value itself as opposed to the whole parameter string then decode that in the script. Simple enough, but was wondering if I was missing an easier way to do it automatically Commented Jun 9, 2011 at 16:24

1 Answer 1

6

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.
Sign up to request clarification or add additional context in comments.

1 Comment

Ah, including the script in the encoded string. Simple solution but I hadn't seen any examples of that anywhere. Thank you very much!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.