Double quotes expand variables: "Server is $serverName" outputs the server name. Single quotes are literal: 'Server is $serverName' outputs the text $serverName. A common script bug is using single quotes when you intended variable interpolation—double-check quote style whenever a variable does not expand as expected.
Variables, Data Types, and Operators
Declare and use variables correctly, understand how PowerShell handles data types implicitly and explicitly, work with strings, arrays, and hashtables, and apply comparison and logical operators in conditions and filters.
🧒 Simple Explanation (ELI5)
A variable is a named box that holds a value. PowerShell variables start with $: $name = "Alice". The box can hold text, numbers, lists, or complex objects. Operators are the comparison words: equal, greater than, less than. They let you ask questions like "is this server's disk usage above 80%?" inside conditions and filters.
🔧 Why Do We Need It?
- Reusability: store a server list in
$serversand reference it throughout the script instead of repeating the list. - Type safety: declaring a variable as
[int]prevents silent errors when strings sneak in during automation runs. - Data structures: arrays and hashtables let you build lookup tables, server inventories, and configuration maps that drive automation logic.
- Dynamic string building: string interpolation and here-strings let you build email bodies, log entries, and commands dynamically.
⚙️ Technical Explanation
PowerShell variables are declared with the $ sigil. Types are inferred by default but can be enforced with a cast: [int]$port = 8080. Common types: [string], [int], [bool], [datetime], [array], [hashtable], [PSCustomObject].
PowerShell strings support two quote styles: double quotes allow variable expansion ("Hello $name") and escape sequences (`n = newline, `t = tab). Single quotes treat everything literally ('Hello $name' outputs the literal text $name).
Comparison operators use letter-based syntax (not symbols, except for some assignments): -eq, -ne, -gt, -lt, -ge, -le. For case-sensitive versions, prefix with c: -ceq, -cne. String matching: -like (wildcards *), -match (regex). Logical operators: -and, -or, -not, !.
Hashtables are the PowerShell equivalent of a dictionary. They are ideal for mapping server names to IPs, environment names to resource groups, or config keys to values. Define once: $envMap = @{ dev = 'rg-dev'; staging = 'rg-staging'; prod = 'rg-prod' }. Access anywhere: $envMap[$env]. This pattern eliminates long if/elseif chains in deployment scripts.
📊 Visual Representation
[string]
[int]
[array]
[hashtable]
[bool]
⌨️ Commands / Syntax
# Declare variables
$serverName = "web01"
[int]$port = 8080
[bool]$isProduction = $true
# String interpolation (double quotes expand variables)
Write-Host "Connecting to $serverName on port $port"
# String methods
$serverName.ToUpper()
$serverName.StartsWith("web")
$serverName.Replace("web", "db")
# Here-string for multi-line text
$body = @"
Server: $serverName
Port: $port
Environment: Production
"@
# Arrays
$servers = @("web01", "web02", "web03")
$servers.Count # 3
$servers[0] # "web01"
$servers += "web04" # append
# Hashtables
$config = @{
Environment = "prod"
Region = "uksouth"
MinReplicas = 2
}
$config["Region"] # "uksouth"
$config.Environment # "prod"
# Comparison operators
$port -eq 8080 # True
$serverName -like "web*" # True
$serverName -match "^\w+\d+$" # True (regex)
5 -gt 3 # True
# Logical operators
($port -eq 8080) -and $isProduction # True
($port -eq 9090) -or ($port -eq 8080) # True
-not $isProduction # False
# Get variable type
$port.GetType().Name # Int32
💼 Example (Real-world Use Case)
A deployment script uses a hashtable to map environment names to Azure resource groups, avoiding repeated if/elseif blocks: the caller passes -Environment prod and the script resolves $resourceGroup = $envMap[$Environment] in one line. This pattern scales to dozens of environments and prevents typos in hardcoded resource group names.
🧪 Hands-on
- Create a string variable for a server name and interpolate it:
$srv = "web01"; Write-Host "Server: $srv". - Build an array of three server names and get the count:
$list = @("a","b","c"); $list.Count. - Create a hashtable mapping two environment names to resource groups and retrieve one entry.
- Test the -like operator:
"web01" -like "web*"should return True. - Use Get-Date and store it in a variable:
$now = Get-Date; $now.ToString("yyyy-MM-dd").
Build a configuration hashtable for a deployment script that has keys: Environment, ResourceGroup, Location, and MinInstances. Then write a string using those values: "Deploying to $($config.Environment) in $($config.Location)". Note the $() sub-expression syntax needed when accessing hashtable properties inside a double-quoted string.
🐛 Debugging Scenario
Problem: your script does a comparison $count -gt 10 but it is always $false even when $count should be 15.
- Cause:
$countis a string, not an integer. String comparison of "15" -gt "10" compares alphabetically—but mixing types in comparisons can give unexpected results. - Diagnose: run
$count.GetType().Nameto check: if it returns String, that is the cause. - Fix: either declare the variable as
[int]$countat assignment, or cast it at comparison:[int]$count -gt 10. - Root cause: values read from CSV files, environment variables, or API responses are strings by default. Always cast to the expected type before arithmetic or magnitude comparisons.
🎯 Interview Questions
Beginner
Use the $ sigil: $name = "value". PowerShell infers the type automatically. To enforce a type, cast it: [int]$count = 5.
Double quotes expand variables and escape sequences. Single quotes treat content as a literal string. "Hello $name" outputs the value of $name; 'Hello $name' outputs the text "$name".
Use @(): $servers = @("web01", "web02"). Access elements with zero-based index: $servers[0]. Get the count with $servers.Count.
-eq (equal), -ne (not equal), -gt (greater than), -lt (less than), -ge (greater or equal), -le (less or equal), -like (wildcard match), -match (regex match). These use alphabetic names, not symbols, to avoid ambiguity.
A hashtable is a key-value dictionary: $h = @{ key = "value" }. Use it for configuration maps, lookup tables, and named parameters when passing multiple values to functions or commands.
Intermediate
Values from CSV files, REST APIs, environment variables, and string splits are strings by default. If you compare them with -gt, -lt, or perform arithmetic, the comparison may work incorrectly or throw a type error. Always check GetType() or cast explicitly when the source is external data.
A here-string is a multi-line string literal delimited by @" ... "@. It preserves formatting and supports variable expansion. It is useful for embedding JSON payloads, HTML bodies, SQL queries, or configuration file content directly in scripts without string concatenation.
Use the sub-expression operator $(): "Region: $($config.Region)". Without $(), PowerShell would try to expand $config followed by a literal .Region and produce wrong output.
Scenario-based
Run $row.Port.GetType().Name after importing the CSV. Import-Csv returns all columns as strings. Cast to the intended type: [int]$port = $row.Port, then compare. Alternatively, use ConvertFrom-Csv with explicit type conversion logic.
Use a hashtable lookup: $rgMap = @{dev='rg-dev'; staging='rg-staging'; prod='rg-prod'}; $rg = $rgMap[$Environment]. Add a validation check: if (-not $rg) { throw "Unknown environment: $Environment" }. This is clean, extensible, and self-documenting.
🌐 Real-world Usage
Azure deployment scripts use hashtables to map environment names to subscription IDs, resource groups, and locations. CI/CD pipeline scripts use typed variables to ensure port numbers, replica counts, and timeout values are integers before they are passed to commands. Array variables hold server lists that drive parallel Invoke-Command loops across fleets.
📝 Summary
Variables in PowerShell use the $ sigil and are dynamically typed by default. Enforce types with casts. Double quotes expand variables; single quotes are literal. Arrays hold ordered lists; hashtables hold key-value pairs. Comparison operators use alphabetic names (-eq, -gt, -like, -match). Type bugs from external data sources are the most common variable-related failure—always validate types when data comes from CSV, API, or environment variables.