I appreciate that most people won’t want to ever convert a secure string into a normal string however there’s a couple of reasons why you would even though there are security concerns. In my case I’m providing PowerShell scripts that are nothing more than a wrapper around a command that must be executed from the command line to for the purpose of simplifying deployment instructions I’m writing for a deployment guide. I like to do this as it provides a predictable, repeatable and consistent experience, e.g. when Microsoft first shipped the server core version of Windows Server 2008 I found myself doing this quite a lot using CMD scripts, e.g. wrappers around things like NETDOM and NETSH, etc.
Anyway, I want to take a password and make use of the star notation via the Read-Host cmdlet, e.g. when you enter something that will be read into a variable by Read-Host I don’t want what’s being typed visible at the console. To do this I need to use the -AsSecureString parameter of Read-Host and assign the value to a [System.Security.SecureString] variable. However I then need to get the actual string value in a plain, unencrypted form so that I can provide it to, for example, MSIEXEC or NETDOM. The PowerShell product group have obviously not made this easy, however it is possible. Here’s how:
[System.Security.SecureString]$secureStringValue = Read-Host "Enter the service account password: " -AsSecureString;
[String]$stringValue = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureStringValue));
In the above snippet I read the value entered by the user as a secure string into $secureStringValue and then store the plain string in the string attribute $stringValue.
Put into context I want someone to execute my script in a way not dissimilar to a multitude of command line applications, i.e. you either enter your password within the confines of your command; you supply a wildcard; or you supply no password at all and the application prompts for a password, e.g. here’s an example of the RUNAS application:
PS C:\dev\lang\ps1\fim\unattended-installation> runas /noprofile /user:dev\paulw-admin cmd
Enter the password for dev\paulw-admin:
Here’s a slightly larger snippet taken directly from a script that I use to perform an unattended installation of FIM. The script is intended to be used interactively. It’s not part of a larger deployment, e.g. a System Center Configuration Manager (SCCM) deployment, but a simplistic “run this script, provide two arguments and FIM is installed” type thing.
if($ServiceAccountPassword -eq "*")
[System.Security.SecureString]$ServiceAccountPassword = Read-Host "Enter the service account password: " -AsSecureString;
[String]$syncSvcAccountPassword = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($ServiceAccountPassword));
[String]$syncSvcAccountPassword = $ServiceAccountPassword;
I then execute the script in either of the following ways:
- Showing the password:
PS C:\dev\lang\ps1\fim\unattended-installation> .\UnattendedInstallation.ps1 -XmlConfigFile .\InstallationProperties.xml -ServiceAccountPassword @C0mp3xP@55w0rd!
- Telling the script to prompt for the password:
PS C:\dev\lang\ps1\fim\unattended-installation> .\UnattendedInstallation.ps1 -XmlConfigFile .\InstallationProperties.xml -ServiceAccountPassword *
- Blissfully unaware of what options are available re. the needed password value:
PS C:\dev\lang\ps1\fim\unattended-installation> .\UnattendedInstallation.ps1 -XmlConfigFile .\InstallationProperties.xml