11

I have a Param block in my script

Param (
    [Parameter(Mandatory=$True)]
    [string]$FileLocation,

    [Parameter(Mandatory=$True)]
    [string]$password = Read-Host "Type the password you would like to set all the users to" -assecurestring
)

Can I use the Read-Host CmdLet in a required Parameter field? if not what can I do to make sure I take in the correct type of variable type so I can pass it to a user creation process?

3 Answers 3

19

Specifying correct type for password should be enough, try:

Param (
    [Parameter(Mandatory=$True)]
    [string]$FileLocation,

    [Parameter(Mandatory=$True)]
    [Security.SecureString]$password
)

PowerShell will "mask" password (same as for read-host -asSecureString) and result type will be the one that other cmdlets may require.

EDIT: After recent comments: solution, that gives both option to provide plain text password, or force user to type password (but mask it same way Read-Host -AsSecureString would) and in both cases get [Security.SecureString] in the end. And, as a bonus, you get some fancy prompt for your secret password. ;)

[CmdletBinding(
    DefaultParameterSetName = 'Secret'
)]
Param (
    [Parameter(Mandatory=$True)]
    [string]$FileLocation,

    [Parameter(
        Mandatory = $True,
        ParameterSetName = 'Secret'
    )]
    [Security.SecureString]${Type your secret password},
    [Parameter(
        Mandatory = $True,
        ParameterSetName = 'Plain'
    )]
    [string]$Password
)

if ($Password) {
    $SecretPassword = $Password | ConvertTo-SecureString -AsPlainText -Force
} else {
    $SecretPassword = ${Type your secret password}
}

Do-Stuff -With $SecretPassword

I've used Jaykul's trick here to cheat with prompting for secure password. ;) It will make this parameter very hard to use in CLI mode (-Type your secret password won't work as expect), so it should force users of the script to either omit password (and get masked prompt) or specify it with -password parameter that accepts regular string and converts it to secure string inside script logic.

5
  • This results in an error for me.
    – Ryan Ries
    Jul 11, 2012 at 21:34
  • 1
    Can't really help with so vague info. ;) What error do you get? I've tested this both on v2 and v3 and it worked fine for me. Not sure where the source of your issue may be if you don't specify error message...
    – BartekB
    Jul 11, 2012 at 21:49
  • No no, you're right - sorry. Your code is correct, but I'm still thinking the OP is going to want a way to pass a SecureString to the script on the command line, and not just a string.
    – Ryan Ries
    Jul 11, 2012 at 21:53
  • I am getting the following error when I use this Param block [PS] C:\Windows\system32>C:\Util\Create-MailboxUsers.ps1 -FileLocation C:\Util\Users.csv -password P@ssword C:\Util\Create-MailboxUsers.ps1 : Cannot process argument transformation on parameter 'password'. Cannot convert the "P @ssword" value of type "System.String" to type "System.Security.SecureString". At line:1 char:74 + C:\Util\Create-MailboxUsers.ps1 -FileLocation C:\Util\Users.csv -password <<<< P@ssword
    – TechGuyTJ
    Jul 12, 2012 at 13:58
  • 1
    That's because you can not convert regular string to secure string like that. I've updated my answer with something that will probably allow you to get little of both: masked prompt and optionally possibility to specify password inline with -password P@ssword param.
    – BartekB
    Jul 12, 2012 at 19:33
4

It's a little hard to decipher what you're trying to do...

Edit; like mentioned by Ryan, you currently already are specifying it as a string...

But in some code, I've used the following function when using Read-Host and SecureStrings

function AskSecureQ ([String]$Question, [String]$Foreground="Yellow", [String]$Background="Blue") {
    Write-Host $Question -ForegroundColor $Foreground -BackgroundColor $Background -NoNewLine
    Return (Read-Host -AsSecureString)
}

In your case you'd call it by doing the following;

Param (
    [Parameter(Mandatory=$True)]
    [string]$FileLocation,

    [Parameter(Mandatory=$True)]
    [string]$password = AskSecureQ "Type the password you would like to set all the users to"
)

EDIT: Given comments, and just for the hell of it... here's an alternative method used to convert the above secure string into plain text within Powershell;

# Taking a secure password and converting to plain text
Function ConvertTo-PlainText( [security.securestring]$secure ) {
    $marshal = [Runtime.InteropServices.Marshal]
    $marshal::PtrToStringAuto( $marshal::SecureStringToBSTR($secure) )
}

You'd use it like this;

$PWPlain = ConvertTo-PlainText $password

Too summarise, you take the password in masked, it's a secure string, you can then break this down into plain text for use elsewhere, a real word example would be if certain CLI programs only accept passwords being passed into them as plain text, this helps with automation where you don't want to hard code a password into your script..

1

I'm not sure I understand... it appears that you already are doing that. By setting the parameter to mandatory, Powershell will prompt you for it if you don't provide it on the command line, and with [string] you are ensuring that the only data type that can go into that variable is System.string.

EDIT: Building on Bartek's answer, do this in your script:

Param ([Parameter(Mandatory=$true,ValueFromPipeline=$true)][Security.SecureString]$Password)       

Then you have to pass your script a SecureString object like so:

PS:> Read-Host -AsSecureString | .\YourScript.ps1

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .