Every PowerShell script eventually needs user input. And for years the answer has been the same: Read-Host. It works, but it’s a blunt instrument — no validation, no choices, no multi-select, no conditional logic. PSInquirer changes that by bringing Inquirer.js-style interactive prompts to PowerShell.
The Problem with Read-Host
The classic pattern looks like this:
$env = Read-Host "Deploy to which environment? (dev/staging/production)"
This is fragile. The user might type “Dev”, “DEV”, “devv”, or just press Enter and leave $env empty. You end up writing a lot of defensive code before you even start the actual work.
PSInquirer replaces that with structured, validated, user-friendly prompts.
Installation
Install-Module -Name PSInquirer -Scope CurrentUser
Import-Module PSInquirer
Your First Interactive Prompt
Import-Module PSInquirer
$answers = Invoke-PSInquirer @(
New-PSIQuestion -Type Input -Name "name" -Message "What is your name?"
New-PSIQuestion -Type List -Name "env" -Message "Target environment?" `
-Choices @("dev", "staging", "production")
New-PSIQuestion -Type Confirm -Name "proceed" -Message "Ready to deploy?" -Default $true
)
Write-Host "Hello $($answers.name)! Deploying to $($answers.env)..."
The user navigates the list with arrow keys, presses Enter to confirm, and the answers come back as a clean hashtable. No parsing, no trimming, no case normalisation.
Question Types
PSInquirer ships five question types that cover virtually every interactive scenario.
Text Input
New-PSIQuestion -Type Input -Name "appName" -Message "Application name:"
Yes/No Confirmation
New-PSIQuestion -Type Confirm -Name "overwrite" -Message "Overwrite existing config?" -Default $false
Single-Choice List
The user selects exactly one option with arrow keys:
New-PSIQuestion -Type List -Name "region" -Message "Deploy to which region?" `
-Choices @("us-east-1", "eu-west-1", "ap-southeast-1")
Multi-Select Checkbox
The user toggles any number of options with Space, then confirms with Enter:
New-PSIQuestion -Type Checkbox -Name "features" -Message "Enable optional features:" `
-Choices @("Logging", "Metrics", "Tracing", "Alerting")
Password (Masked Input)
Input is hidden as the user types:
New-PSIQuestion -Type Password -Name "apiKey" -Message "Enter your API key:"
Built-In Validation
Attach a -Validate scriptblock to any question. Return $true to accept the value, or return an error string to reject it and prompt again:
New-PSIQuestion -Type Input -Name "port" -Message "Port number:" -Validate {
param($value)
$n = [int]$value
if ($n -ge 1 -and $n -le 65535) { return $true }
return "Please enter a value between 1 and 65535."
}
The prompt loops until the user provides a valid value — no extra loop code required.
Conditional Questions
Use -When to show a question only when a previous answer satisfies some condition. This lets you build branching wizards without messy if/else blocks:
$answers = Invoke-PSInquirer @(
New-PSIQuestion -Type Confirm -Name "useTLS" -Message "Enable TLS?"
New-PSIQuestion -Type Input -Name "certPath" -Message "Path to certificate:" -When {
param($a) $a.useTLS -eq $true
}
New-PSIQuestion -Type Input -Name "certPass" -Message "Certificate password:" -When {
param($a) $a.useTLS -eq $true
}
)
If the user answers No to “Enable TLS?”, the certificate questions are skipped entirely.
Real-World Example: Deployment Wizard
Here is a complete interactive deployment wizard that collects everything it needs before touching any infrastructure:
Import-Module PSInquirer
$answers = Invoke-PSInquirer @(
New-PSIQuestion -Type Input -Name "appName" -Message "Application name:" -Validate {
param($v) if ($v.Trim()) { $true } else { "Application name cannot be empty." }
}
New-PSIQuestion -Type List -Name "env" -Message "Target environment?" `
-Choices @("dev", "staging", "production") -Default "dev"
New-PSIQuestion -Type Checkbox -Name "steps" -Message "Steps to include:" `
-Choices @("Build", "Unit Tests", "Migrate DB", "Deploy", "Smoke Tests")
New-PSIQuestion -Type Confirm -Name "dryRun" -Message "Run as dry-run (no changes)?" `
-Default $true
New-PSIQuestion -Type Confirm -Name "confirm" -Message "Everything looks good — proceed?" `
-Default $false
)
if (-not $answers.confirm) {
Write-Host "Deployment cancelled."
exit 0
}
$mode = if ($answers.dryRun) { "[DRY RUN] " } else { "" }
Write-Host "`n${mode}Deploying $($answers.appName) to $($answers.env)`n"
foreach ($step in $answers.steps) {
Write-Host " → Running: $step"
# ... actual step logic here ...
}
Write-Host "`n✅ Deployment complete!"
Combining PSInquirer with Other PSTools Modules
PSInquirer pairs naturally with other modules in the PSTools ecosystem. For example, pair it with PSSpinner to collect input up front and then show progress during execution:
Import-Module PSInquirer
Import-Module PSSpinner
# Gather all user choices first
$answers = Invoke-PSInquirer @(
New-PSIQuestion -Type Input -Name "server" -Message "Server hostname:"
New-PSIQuestion -Type Confirm -Name "restart" -Message "Restart after deploy?" -Default $true
)
# Execute with visual feedback
Invoke-WithSpinner -Message "Deploying to $($answers.server)..." -ScriptBlock {
Start-Sleep -Seconds 3 # your actual deploy logic
}
Tips for Great Interactive Scripts
- Order questions logically — ask for the most important decisions first so the user can bail early with Ctrl+C if needed.
- Use sensible defaults — set
-Defaulton every question so power users can hit Enter quickly through a wizard they run often. - Validate eagerly — use
-Validateto catch bad input immediately rather than failing later in the script. - Group with
-When— use conditional questions instead of building branching logic around the answers after the fact. - Confirm before irreversible actions — always finish with a summary and a
Confirmquestion before any destructive operation.
Conclusion
PSInquirer gives PowerShell scripts the same polished, interactive feel that Node.js CLI tools have enjoyed for years. It’s a small module with a focused job: replace every Read-Host with something your users will actually enjoy.
Install-Module -Name PSInquirer -Scope CurrentUser
Explore the full command reference on the PSInquirer module page and browse the source on GitHub.