Summary: With Windows PowerShell cmdlets, it is easy to mask passwords used when scripting remote applications.

 

Hey, Scripting Guy! Question Hey, Scripting Guy! I need to be able to mask a password when running a Windows PowerShell script. I am attempting to convert my VBScript scripts to Windows PowerShell, but I have a problem. In VBScript I would use a COM object called scriptpw.password. I first learned about it from the How Can I Mask Passwords Using an InputBox? Hey, Scripting Guy! post. Unfortunately, I get an error when attempting to use this object in Windows PowerShell. I don’t get it because I thought that Windows PowerShell could create COM objects. What do I need to do to make this work?

-- AJ

 

Hey, Scripting Guy! Answer Hello AJ,

Microsoft Scripting Guy Ed Wilson here. I was in Ft. Lauderdale, Florida, teaching a VBScript class a few years ago when this happened. There was a knock on the hotel room door. I opened it, and there stood my significant other. Teresa had decided to fly down and join me for the weekend. Because she went to all the trouble to fly down and visit me, I felt compelled to see what she wanted to do for the weekend. For her, the choice was easy—go to a butterfly farm. Luckily, I had my camera with me. Butterfly farms offer myriad opportunities for taking great pictures, such as this one I snapped.

Photo Ed took of a butterfly

Even though it might seem difficult to take great pictures of butterflies, it can be surprisingly easy. AJ, the same is true for masking passwords in Windows PowerShell: It is very easy when you know the trick. For example, if I need to mask the administrator password while checking on the BIOS version of a remote computer, I use the –credential parameter:

Get-WmiObject -Class win32_bios -ComputerName hyperv -Credential nwtraders\administrator

When the Get-WmiObject command runs, the dialog box appears that is shown in the following image. Note that the username is automatically filled out from the domain and username supplied when typing the command. When the Windows PowerShell Credential Request dialog box appears, the password characters are masked as you type them.

Image of dialog box that appears when Get-WmiObject command is run

If you do not supply a username for the –credential parameter for the Get-WmiObject cmdlet, the error shown in the following image appears.

Image of error produced when a  user name is not supplied for -credential parameter

The error actually makes sense because when working interactively, you would normally supply the username to use for the command.

There are 56 cmdlets that use the –credential parameter. They are shown here. GCM is an alias for the Get-Command cmdlet. The ? is an alias for the Where-Object cmdlet:

PS C:\> gcm -type cmdlet | ? { $_.parameters.keys -match 'credential'} | Format-Wide
name -AutoSize
Add-Computer Add-Content Clear-Content
Clear-Item Clear-ItemProperty Connect-WSMan
Copy-Item Copy-ItemProperty Enter-PSSession
Get-Content Get-Credential Get-HotFix
Get-Item Get-ItemProperty Get-WinEvent
Get-WmiObject Get-WSManInstance Invoke-Command
Invoke-Item Invoke-WmiMethod Invoke-WSManAction
Join-Path Move-Item Move-ItemProperty
New-Item New-ItemProperty New-PSDrive
New-PSSession New-PSSessionOption New-Service
New-WebServiceProxy New-WSManInstance New-WSManSessionOption
Register-WmiEvent Remove-Computer Remove-Item
Remove-ItemProperty Remove-WmiObject Remove-WSManInstance
Rename-Item Rename-ItemProperty Resolve-Path
Restart-Computer Send-MailMessage Set-Content
Set-Item Set-ItemProperty Set-WmiInstance
Set-WSManInstance Split-Path Start-Job
Start-Process Stop-Computer Test-Connection
Test-Path Test-WSMan
PS C:\> gcm -type cmdlet | ? { $_.parameters.keys -match 'credential'} | measure
Count : 56
Average :
Sum :
Maximum :
Minimum :
Property :
PS C:\>

Unfortunately, most of the 56 cmdlets that accept the credential parameter may not work the way you envision. For example, the Get-Item cmdlet accepts credential, but it is not implemented for any of the default providers except for the wsMan drive. This is shown here:

PS C:\> Get-PSProvider
Name Capabilities Drives
---- ------------ ------
WSMan Credentials {WSMan}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess {C, E, D}
Function ShouldProcess {Function}
Registry ShouldProcess, Transactions {HKLM, HKCU}
Variable ShouldProcess {Variable}
Certificate ShouldProcess {cert}
PS C:\>

This means that you cannot supply credentials for the Get-Item cmdlet when connecting to registry or to a file system drive—two of the more common scenarios.

If you would like the user to type full credentials for your script (both a user name and a password), you can use the Get-Credential cmdlet. This is shown in the ShutdownComputer.ps1 script.

ShutdownComputer.ps1

$credential = Get-Credential

Stop-Computer -ComputerName win7-c1 -Credential $credential

 

When the script runs, the dialog box appears that is shown in the following image.

Image of dialog box that appears when script is run

If you only want to obtain the password, you can use the Read-Host cmdlet with the –asSecureString parameter. By default, when using the Read-Host cmdlet, it does not mask data supplied via the command line. But when the –asSecureString parameter is used, it masks the password. This is shown in the following image.

Image of -asSecureString masking password

Because both of these methods, Get-Credential and Read-Host, return an instance of the System.Security.SecureString .NET Framework object, it is important to test your script to ensure that the target application will accept a SecureString for the password. This is especially true for old COM interfaces. Most .NET Framework interfaces will accept the SecureString. This is important from a security concern because a SecureString is encrypted.

AJ, that is all there is to using Windows PowerShell to mask passwords when running scripts. Running Windows PowerShell Scripts Week will continue tomorrow when we will talk about pausing a script to wait for user interaction.

We invite you to follow us on Twitter and Facebook. If you have any questions, send email to us at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

 

Ed Wilson and Craig Liebendorfer, Scripting Guys