Variables, Data Types & Operators
PowerShell Fundamentals
Chapter 5 · Variables, Data Types & Operators
Every object pipelined through Get-Member in Chapter 3, and every property tested with -eq/-gt/-like in Chapter 4, was a real, typed .NET object the entire time — that's exactly what made those chapters work. Variables are no different, even though declaring one looks deceptively casual. This chapter is about that duality: PowerShell lets you create a variable with zero type declaration, the same relaxed feel as Bash or Python, while every value it ever holds stays a genuine, strongly-typed object underneath — not the loose, everything-is-basically-text world Bash actually lives in.
Declaring a Variable
Every variable name starts with $ — on both assignment and read, which is one real, easy-to-trip-on difference from Bash, where $ only appears when reading a variable (name="Philip" to assign, $name to read):
No type was declared anywhere in that example — and yet neither variable is untyped. Ask any variable what it actually is with .GetType():
$age could hold a string tomorrow if you reassign it. It does not mean the value is typeless the way Bash treats everything as fundamentally text until proven otherwise. Every value in PowerShell is a real .NET object with a real, discoverable type, the whole time — which is exactly why Get-Member (Chapter 3) always has something concrete to report, and why -gt/-lt (Chapter 4) can compare numbers as numbers instead of comparing digit characters as text.
Casting & Type Accelerators
A short bracketed name before a value — a type accelerator — converts it explicitly:
| Accelerator | .NET type | Holds |
|---|---|---|
| [string] | System.String | Text |
| [int] | System.Int32 | Whole numbers |
| [double] | System.Double | Decimal numbers |
| [bool] | System.Boolean | $true / $false |
| [datetime] | System.DateTime | Dates and times |
| [array] | System.Array | An ordered collection |
| [hashtable] | System.Collections.Hashtable | Key-value pairs |
Arithmetic — and a Genuinely Surprising Rounding Gotcha
double back to [int] uses banker's rounding (round-half-to-even), not the "always round .5 up" rule most people assume by default: [int]2.5 is 2, but [int]3.5 is 4 — both rounded to the nearest even number, not simply upward. If you specifically want traditional round-half-up behavior, reach for [math]::Round($value, 0, [MidpointRounding]::AwayFromZero) instead of a bare cast.
Strings: Quoting, Interpolation & Joining
That single-vs-double distinction is a real, common trip-up: reach for single quotes when you actually want $ printed literally, and double quotes any time a variable or expression should be substituted in.
Arrays: @()
Hashtables: @{}
Looping over every key or value in a hashtable properly belongs to Chapter 6's own control-flow material — for now, know that @{} and [ordered]@{} are genuinely different types with a real behavioral difference, not just a stylistic choice.
Automatic Variables Worth Knowing Now
| Variable | Holds |
|---|---|
| $null | PowerShell's explicit "no value" — comparing something to $null uses -eq/-ne like any other value |
| $true / $false | The two [bool] literals |
| $_ / $PSItem | The current pipeline object inside a script block (Chapter 4) |
| $PSVersionTable | The running PowerShell version details (Chapter 1) |
| $Error | A list of recent errors — covered properly in Chapter 9 |
| $args | Positional arguments passed to a script or function — covered properly in Chapter 7 |
.GetType() before assuming PowerShell is wrong. Nine times out of ten, the type wasn't what you assumed it was, and .GetType() tells you immediately rather than leaving you to guess.
Hands-On Exercises
Predict what .GetType().Name reports for $x = "42" versus $x = 42, and predict what $x + 8 does in each case. Explain the reasoning behind both predictions using this chapter's own casting example.
Explain why [int]2.5 evaluates to 2 while [int]3.5 evaluates to 4. What should you use instead if you specifically want traditional round-half-up behavior?
Given $person = @{ Name = "Alice"; Age = 30 }, show two different ways to read the Age value. Then explain why a plain @{} hashtable's key order isn't guaranteed the way an array's order is, and what fixes that.
Chapter 5 Quick Reference
$name = value—$is used on both assignment and read, unlike Bash.GetType()— reveals a variable's real underlying .NET type- Type accelerators —
[string][int][double][bool][datetime][array][hashtable], for explicit casting or constraining a variable - Division auto-widens —
7 / 2is3.5, a double, not a truncated integer - Casting to
[int]rounds half-to-even —[int]2.5is2;[int]3.5is4 - Single vs. double quotes — single is literal; double interpolates variables and
$(...)expressions @()arrays — zero-indexed, negative indexing,..range operator, freely mixed types@{}vs.[ordered]@{}— a plain hashtable doesn't guarantee key order;[ordered]@{}does- Next chapter: Control Flow: Conditionals, Loops & Switch