Powershell: Working with Passwords

When creating a new Active Directory user from the command line in PowerShell, you will likely find yourself using Read-Hosts’s asSecureString switch when entering the password.

$password = Read-Host "Enter password" -AsSecureString

Next, you’ll probably look around the Internets for a few hours or so trying to figure out how to change the password of the newly created user. You will soon discover that the user creation process in PowerShell 1.0 isn’t very straightfoward and it even requires a specific order for proper account creation. First, you create the account, then you set some basic properties, next you call SetInfo(), and finally you invoke setPassword using the follwing syntax:

$newUser.psbase.Invoke("SetPassword",$password)

Now you may find yourself with the following exception: Exception calling “Invoke” with “2″ argument(s): “Exception has been thrown by the target of an invocation.” Originally, this post mentioned using toString() to address the problem but PowerShell team member Lee Holmes wrote to let me know that the password was changed literally to System.Security.SecureString. He also said that “there is no really easy way to convert a secure string to plain text – on purpose. Since a SecureString is supposed to prevent plain text from littering your computer’s memory, converting it to plain text defeats the purpose.”

My primary reason for using asSecureString is to encode the string into asterisks when typing it at the prompt. So Lee gave me two ways to convert the password to be used while invoking SetPassword. Note that unless you are using a secure LDAP channel, the password will be sent over the network in clear text.

$temporaryCredential = New-Object System.Management.Automation.PsCredential "None",$password
$newUser.psbase.Invoke("SetPassword",$temporaryCredential.GetNetworkCredential().Password)

Or, alternatively:

$temporaryCredential = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($password))$newUser.psbase.Invoke("SetPassword",$temporaryCredential)

If you continue to see this exception, check to make sure that the password you entered meets your domain’s password complexity requirements.

Posted in Active Directory, PowerShell, Security
7 comments on “Powershell: Working with Passwords
  1. povlhp says:

    I have no luck converting a string into a securestring:

    0
    PS C:\scripts> $x = New-Object System.Management.Automation.PsCredential “None”, “abekat”
    New-Object : Cannot convert argument “1″, with value: “abekat”, for “.ctor” to type “System.Security.SecureString”: “Cannot convert value “abekat” to type “System.Security.SecureString”. Error: “Invalid cast from ‘System.String’ to ‘System.Security.SecureString’.”"
    At line:1 char:16
    + $x = New-Object <<<< System.Management.Automation.PsCredential “None”, “abekat”

  2. bene says:

    Hi,

    make the $password with ” around and it works create.
    $newUser.psbase.Invoke(“SetPassword”,”$password”)

    You could also make $password.tostring():
    $newUser.psbase.Invoke(“SetPassword”,$password.ToString())

  3. Robert says:

    Using this ‘$newUser.psbase.Invoke(“SetPassword”,”$password”)’

    I get an error
    Method invocation failed because [System.Management.Automation.PSMemberset doesn’t contain a method names ‘Invoke’

    Any ideas?

  4. Troy says:

    I’ve seen and tried several methods now for changing passwords using Powershell. I am successfull when changing passwords in the same domain, but I manage a multidomain forest and the methods don’t work from one to the next. In other words, from my management server in domainA I can’t change a password of a user account in domainB. I have the permissions to do so, I am binding successfully and I can retrieve the user attributes. I can even change attributes, but I can’t change the password. All my servers are Windows 2003 R2 SP2, the domains and forest level is native 2003.

  5. Patriot says:

    I needed to be able to accept an obfuscated password on the Powershell command line, to be passed to the “schtasks” tool, and this solution worked perfectly. Thanks to you and to Lee Holmes.

    $password = Read-Host ‘Enter password’ -asSecureString
    $tempCredential = New-Object System.Management.Automation.PsCredential “None”,$password
    $password = $tempCredential.GetNetworkCredential().Password

    The $password can now be passed to another program, as an argument on the command line.

    As to the security of this method, I cannot comment. I don’t know how risky this approach is, as compared to supplying schtasks (or any other program) with a password, as an inline parameter, when calling the command.

    I will say, however, that entering one’s password, as part of the schtasks command, would allow anyone standing over his/her shoulder to read the password, in cleartext, as it is typed. So, even though this method may not be water-tight, it solves the over-the-shoulder observation problem.

    Based on what I’ve read here and on Lee Holmes’ blog, using this method is not, in itself, unsecure. The problems are introduced when the password is then passed over an unsecure network connection. I have to assume that schtasks, and other utilities that are included with Windows, do not send passwords over the nextwork in cleartext.

  6. Joe Ranallo says:

    I’m trying to change passwords for ADAM accounts, yet it seems the same code working in AD, does not work with ADAM. Does anyone have any thoughts on getting this working?
    When using the following:
    $newUser.psbase.Invoke(“SetPassword”,$password)

    I get the following error:
    Exception calling “Invoke” with “2″ argument(s): “The directory property cannot be found in the cache.”

    I read in the following article that setPassword is not available through ADSI in ADAM. Can anyone confirm or deny? Am I misinterpreting this?
    http://forums.techarena.in/active-directory/1125854.htm

    code:
    $password = Read-Host “Enter password” -AsSecureString
    $ADANOu = New-Object DirectoryServices.DirectoryEntry(“LDAP://contmgmt01:11389/cn=xxxx,cn=xxxx,cn=xxx,ou=users,DC=xx,DC=com”)
    $ADANOU_child = $ADANOu.get_Children()
    foreach($user in $ADANOU_child)
    {
    If ($user.name -like “*testprof”)
    $user.psbase.Invoke(“SetPassword”)
    }

  7. Peter says:

    You can also use the ConvertTo-SecureString cmdlet.

    For example:

    $password = Read-Host -Prompt "password"
    $password = ConvertTo-SecureString $password -AsPlainText -Force

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">