Getting AD User Attributes

By default, Get-ADUser (provided by ActiveDirectory module which is part of the free Microsoft RSAT tools) retrieves only a few default properties. To get more information, use the –Properties parameter, and specify the properties you are after.

To get a list of all AD users with their notes and description fields, try this:

#requires -Modules ActiveDirectory 
Get-ADUser -Filter * -Properties Description, Info

If you don’t know the names of available properties, use “*” instead to retrieve all available properties.

Twitter This Tip! ReTweet this Tip!

Careful with Get-Credential and SecureStrings

Sometimes, scripts interactively ask for credentials, or passwords. Always be aware that the script author can get to the plain text of all entered information. Only enter sensitive information if you trust the script and author.

Please note: this is not a PowerShell issue. It is a general issue with all software.

Let’s see how a script could exploit an entered password. If a script asks for a complete credential, it could then examine the credential object and extract the plain text password:

$credential = Get-Credential
$password = $credential.GetNetworkCredential().Password

"The password entered was: $password"

Likewise, when you are prompted to enter a password as secure string, the script author could again find out the entered plain text:

$password = Read-Host -AsSecureString -Prompt 'Enter Password'

# this is how the owner of a secure string can get back the plain text:
$BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password)
$plaintext = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)

"The password entered was $plaintext"

Twitter This Tip! ReTweet this Tip!

Managing Credentials (Part 5)

When PowerShell auto-encrypts a secure string, it uses your identity as secret. Only you can decrypt the secure string. What if you want to encrypt a secret with a shared passphrase?

Here is one classic approach, using a passphrase for encryption:

# $secretKey MUST be of length 8 or 16
# anyone who knows the secret can decrypt the password 
$secretKey = 'mysecretmysecret'
$password = 'myPassword'

$SecureString = ConvertTo-SecureString -String $password -AsPlainText -Force
$RandomSecureString = ConvertTo-SecureString -String $secretKey -AsPlainText -Force
$encryptedPassword = ConvertFrom-SecureString -SecureString $SecureString -SecureKey $RandomSecureString
$encryptedPassword

The secret decryption key ($secretKey) needs to be a text with 8 or 16 characters length. Anyone who knows this key can decrypt the secret (which is why the secretKey should not be part of a script and is added to the below script only to illustrate the decryption process. You better ask for it interactively):

# this is the key to your secret
$secretKey = 'mysecretmysecret'
# this is the encrypted secret as produced by the former code
$encryptedPassword = '76492d1116743f0423413b16050a5345MgB8AEMARQAxAFgAdwBmAHcARQBvAGUAKwBOAGoAYgBzAE4AUgBnAHoARABSAHcAPQA9AHwANQA3ADYAMABjAGYAYQAwAGMANgBkADQAYQBiADYAOAAyAGYAZAA5AGYAMwA5AGYAYQBjADcANQA5ADIAYwAzADkAMAA2ADQANwA1ADcAMQA3ADMAMwBmAGMAMwBlADIAZQBjADcANgAzAGQAYQA1AGIAZABjADYAMgA2AGQANAA='

$RandomSecureString = ConvertTo-SecureString -String $secretKey -AsPlainText -Force
$securestring = $encryptedPassword | ConvertTo-SecureString -SecureKey $RandomSecureString
# Result is a secure string
$SecureString

The result is a secure string that you could use to compose a full credential:

$credential = New-Object -TypeName PSCredential('yourcompanyyouruser', $SecureString)
$credential

You can also double-check the clear text secret:

 
PS C:Userstobwe> $credential.GetNetworkCredential().Password
myPassword
 

Note that the owner of a secure string (the one who created it) can always get back to the plain text password. This is not a security issue. The one that created the secure string already knew the secret at a given point in the past. A secure string protects sensitive data from third party, and stores it in memory in a way that no other user can touch it.

The issue with secret keys and symmetric encryption is that you need to distribute the secret key, that it needs to be protected, and can be used both for encryption and decryption.

A much safer way was introduced in PowerShell 5: Protect-CMSMessage and Unprotect-CMSMessage use digital certificates and asymmetric encryption. This way, the party encrypting a secret does not need to know the decryption key, and vice versa. The encrypting party only needs to specify who (which certificate) should be able to decrypt the secret.

Twitter This Tip! ReTweet this Tip!

Managing Credentials (Part 4)

In the previous script we showed how you can save a credential object in encrypted form to disk. A similar approach just saves the secret password as encrypted text. This creates the encrypted password file:

# read in the password, and save it encrypted
$text = Read-Host -AsSecureString -Prompt 'Enter Password'
$text | Export-Clixml -Path "$homedesktopmypassword.xml"

It can only be read back from the person that saved it, and only on the same machine. A second script could take the password and use it to log in to another system without user interaction:

# read in the secret and encrypted password from file
$password = Import-Clixml -Path "$homedesktopmypassword.xml"

# add the username and create a credential object
$username = 'yourCompanyyourUserName'
$credential = New-Object -TypeName PSCredential($username, $password)

The credential object can then be used with any cmdlet that takes the -Credential parameter.

# use the credential with any cmdlet that exposes the –Credential parameter
# to log in to remote systems
Get-WmiObject -Class Win32_LogicalDisk -ComputerName SomeServer -Credential $credential

Twitter This Tip! ReTweet this Tip!

Managing Credentials (Part 3)

For unattended scripts, it is generally unsafe and not recommended to hard-code secret passwords into a script.

As an alternative, you could ask for the password once, then create a credential object and use it wherever needed in your script. This part asks for a password, then constructs a credential object:

$password = Read-Host -AsSecureString -Prompt 'Enter Password'
$username = 'myCompanymyUserName'
$credential = New-Object -TypeName PSCredential($username, $password)

The credential object can then be used with any cmdlet that takes the -Credential parameter.

# use the credential with any cmdlet that exposes the –Credential parameter
# to log in to remote systems
Get-WmiObject -Class Win32_LogicalDisk -ComputerName SomeServer -Credential $credential

Twitter This Tip! ReTweet this Tip!

Managing Credentials (Part 2)

For scripts running unattended, you can create login credentials from code. This requires the secret password to be saved as clear text in a script (which obviously is unsafe unless you encrypt your script with the encrypting file system (EFS) or take other measures to protect the content):

$password = 'topsecret!' | ConvertTo-SecureString -AsPlainText -Force
$username = 'myCompanymyUserName'
$credential = New-Object -TypeName PSCredential($username, $password) 

# use the credential with any cmdlet that exposes the –Credential parameter
# to log in to remote systems
Get-WmiObject -Class Win32_LogicalDisk -ComputerName SomeServer -Credential $credential

Twitter This Tip! ReTweet this Tip!