Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Secure String Powershell

Tags:

powershell

I am getting an issue when trying to pass a securestring in to a powershell script, but it's coming back with this error?

Cannot process argument transformation on parameter 'Password'.
Cannot convert the "ConvertTo-SecureString" value
of type "System.String" to type "System.Security.SecureString".

$SecureServiceAccountPassword = ConvertTo-SecureString  "somethingstong!" `
    -AsPlainText -Force   
$AgentAccount = "myAccount"
$ServiceAccountOU = "MYOU"
POWERSHELL -COMMAND $ADAccountScript `
    -ServiceAccountOU $ServiceAccountOU `
    -Account $AgentAccount `
    -Password $SecureAgentAccountPassword

The script that it's calling is this.

param(
 ##MasterKey for KeePass currently stored in a DB.  
  [Parameter(Position=0,mandatory=$true)] [string] $ServiceAccountOU,
 ##Account to be created in AD
  [Parameter(Position=1,mandatory=$true)] [string] $Account,

  [Parameter(Position=2,mandatory=$true)] [SecureString] $Password
 )

NEW-ADUSER -Name $Account `
    -AccountPassword $Password `
    -Path $SrviceAccountOU `
    -Enabled $True `
    -PasswordNeverExpires $True `
    -CannotChangePassword $True
like image 803
Dave Carpenter Avatar asked Sep 10 '26 10:09

Dave Carpenter


1 Answers

To pass a [securestring] (System.Security.SecureString) instance as such via PowerShell's CLI (powershell.exe in Windows PowerShell, pwsh in PowerShell (Core) 7+), you must pass the command to execute (-Command / -c) as a script block.[1]

  • Note: While use of [securestring] - assuming the input string wasn't obtained via a plain-text representation (as shown in the question) - is undoubtedly better than using plain-text passwords, use of [securestring] in new projects is discouraged, because it offers no protection on Unix-like platforms and only limited protection on Windows. See this .NET platform-compatibility recommendation and this answer.

Note that this passing a script block as the command to execute only works when you call from an existing PowerShell session - where the need to invoke a script via another PowerShell instance (the child process created by the CLI call) rather than by direct invocation (in-process in the same session) is unusual, however.

In your case, the simplest solution is:

powershell -c { 
  $scriptFile, $passThruArgs = $args
  & $scriptFile @passThruArgs
} -args $ADAccountScript, $ServiceAccountOU, $AgentAccount, $SecureServiceAccountPassword

Note that this relies on positional argument-passing.

If you wanted to use named arguments, as in your own attempt, you'd have to resort to hashtable-based splatting

# Create the hashtable whose entries map onto the target
# script's parameters.
$htArgs = @{
    ServiceAccountOU = 'foo'
    Account          = 'bar'
    Password         = ConvertTo-SecureString  "somethingstrong!" -AsPlainText -Force
}

powershell -c { 
  $scriptFile, $passThruArgs = $args
  & $scriptFile @passThruArgs
} -args $ADAccountScript, $htArgs

[1] If you pass the -Command / -c argument as a string - which is the only option when calling PowerShell's CLI from outside PowerShell - a [securestring] is passed as its string representation, which is its full type name, verbatim: 'System.Security.SecureString'; that is, the actual, "secure" content is lost.
By contrast, passing a script block triggers CLIXML-based serialization behind the scenes, where passing and receiving objects rather than only text is supported - see this answer for more information.

like image 122
mklement0 Avatar answered Sep 13 '26 05:09

mklement0