Dave Carpenter
Dave Carpenter

Reputation: 41

Secure String 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

Upvotes: 3

Views: 15552

Answers (2)

mklement0
mklement0

Reputation: 440556

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.

Upvotes: 3

Ranadip Dutta
Ranadip Dutta

Reputation: 9341

Your password is not passing to PS as secure string. So, you have to convert the same and pass it.

Replace this:

NEW-ADUSER -Name $Account -AccountPassword $Password -Path $SrviceAccountOU -Enabled $True -PasswordNeverExpires $True -CannotChangePassword $True

TO:

NEW-ADUSER -Name $Account -AccountPassword (ConvertTo-SecureString "$password" -AsPlainText -Force) -Path $SrviceAccountOU -Enabled $True -PasswordNeverExpires $True -CannotChangePassword $True

Best way is to directly pass the credentials:

$User = "MyUserName"
$File = "C:\Temp 2\Password.txt"
$password = Get-Content "C:\Passwords\password.txt" | ConvertTo-SecureString 
$credential = New-Object System.Management.Automation.PsCredential("Luke",$password)
$MyCredential=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)

New-ADUser -credential $MyCredential # Followed by whatever you need except the username and password.

Upvotes: 0

Related Questions