Prompt Answers in PowerShell

When you are building a PowerShell script, there might be situations where you want to prompt for a piece of data. Some cmdlets like Get-Credential do that sort of task implicitly. You can also get prompting if you define a mandatory parameter in a function or script. Otherwise, we tend to rely on PowerShell’s Read-Host cmdlet. With this cmdlet, you provide a prompt message and PowerShell writes the object back to the pipeline.

$r = Read-Host "Enter computername"

Using Read-Host (Image Credit: Jeff Hicks)
Using Read-Host (Image Credit: Jeff Hicks)

The variable $r now contains whatever was entered at the prompt.
By default, the cmdlet writes a string to the pipeline. Although I haven’t seen the source code for Read-Host, it’s most likely implementing the ReadLine() method of the built-in $host.ui object. I can simulate the Read-Host cmdlet:
Simulating Read-Host (Image Credit: Jeff Hicks)
Simulating Read-Host (Image Credit: Jeff Hicks)

I show this to you to not only demonstrate how using a cmdlet is better than re-inventing the wheel, but I’m also showing this to you I found another method that doesn’t appear to have any native cmdlet equivalent, and it’s something you might find useful.
The $host.ui object includes a method called Prompt(). The method requires three parameters: a prompt title, the message to display, and a key name. The last piece may puzzle you. The Prompt() method will create a Collections object, which is like a hashtable. The key name you specify will be used in the output. Here’s a simple example.

$r = $host.ui.Prompt("SERVER REPORTING","Enter a computername","Name")

A simple UI prompt (Image Credit: Jeff Hicks)
A simple UI prompt (Image Credit: Jeff Hicks)

I saved the results to a variable, which looks like a hashtable.
Viewing prompt result (Image Credit: Jeff Hicks)
Viewing prompt result (Image Credit: Jeff Hicks)

I could then use this object in my script or PowerShell session by referencing $r.Name. You have to be careful because unlike a normal hashtable, the key name is case-sensitive.
Using the collections object (Image Credit: Jeff Hicks)
Using the collections object (Image Credit: Jeff Hicks)


Now let’s make it interesting. It turns out you can use one prompt for multiple entries. All you need to do is specify an array of key names.

$r = $host.ui.Prompt("SERVER REPORTING","Enter values for these settings:",@("Computername","Domain","Operating System","Version"))

Prompting for multiple values (Image Credit: Jeff Hicks)
Prompting for multiple values (Image Credit: Jeff Hicks)

But wait it gets better. Even though $r is this fancy Collections object, I can still turn it into a PowerShell object using New-Object.

$s = New-Object -TypeName PSObject -Property $r

Creating an object from the collection (Image Credit: Jeff Hicks)
Creating an object from the collection (Image Credit: Jeff Hicks)

When referencing property names via the object, you also no longer have to worry about case.
Testing properties (Image Credit: Jeff Hicks)
Testing properties (Image Credit: Jeff Hicks)

Of course, what would make this all much easier to use is function, so here you go:

Function Read-MyHost {
[cmdletbinding()]
Param(
[Parameter(Position=0,Mandatory,HelpMessage="Enter the message prompt.")]
[ValidateNotNullorEmpty()]
[string]$Message,
[Parameter(Position=1,Mandatory,HelpMessage="Enter key property name or names separated by commas.")]
[System.Management.Automation.Host.FieldDescription []]$Key,
[Parameter(HelpMessage = "Text to display as a title for the prompt.")]
[string]$PromptTitle = "",
[Parameter(HelpMessage = "Convert the result to an object.")]
[switch]$AsObject
)
$response = $host.ui.Prompt($PromptTitle,$Message,$Key)
if ($AsObject) {
    #create a custom object
    New-Object -TypeName PSObject -Property $response
}
else {
    #write the result to the pipeline
    $response
}
} #end function

The title, while required for Prompt method, can be an empty string, so I didn’t make it a mandatory parameter. You probably also noticed the type name for the Key parameter. The Prompt() method is looking for parameters of this type so I’ll have PowerShell force them to be so. I also added a switch to write the result as an object to the pipeline to save a step.
Here’s a simple test:

A simple test of the new function (Image Credit: Jeff Hicks)
A simple test of the new function (Image Credit: Jeff Hicks)

Notice that I didn’t have to specify a prompt title. But you can.
Prompting for multiple entries (Image Credit: Jeff Hicks)
Prompting for multiple entries (Image Credit: Jeff Hicks)

I should also point out that with both the collection output or the object, you can always change the values after the fact.
Modifying the object (Image Credit: Jeff Hicks)
Modifying the object (Image Credit: Jeff Hicks)


I hope you find this function useful and if so, I certainly hope you will let me know how you are using it. In the meantime, continue to poke around in PowerShell and especially with Get-Member. You never know what you might discover.