Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk8 min

Working With PowerShell’s Data Types: Objects, Casting, Arrays, and Custom Records

PowerShell variables are dynamic, but their .NET runtime types control behavior. Learn to inspect, convert, constrain, and choose objects, arrays, hashtables, custom records, classes, and enums safely.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

PowerShell carries .NET objects through its pipeline rather than plain text. Variables are dynamically typed unless you add a type constraint, and PowerShell may convert, unwrap, enumerate, or format those objects automatically. That flexibility is convenient, but it also explains surprises such as '10' + '2' producing 102, a command result changing shape when it returns one item instead of many, or a remoted object losing its methods.

The reliable approach is to inspect runtime types, convert external input explicitly, normalize collection output, and choose a representation—scalar, array, hashtable, custom object, class, or enum—that matches the job.

The PowerShell type model

A data type describes what a value is and what operations are available. Its runtime type affects properties, methods, operators, parameter binding, formatting, and serialization. PowerShell variables themselves are not constrained by default:

$value = 42
$value.GetType().Name       # Int32
$value = 'hello'
$value.GetType().Name        # String

You can constrain a variable and request conversion by placing a type literal before its name:

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
[int]$count = 42
$count = '43'               # Converts to Int32
$count = 'not a number'      # Conversion error

Thus, the most accurate description is a dynamic, object-based type system with optional constraints and extensive conversion rules—not simply “strongly typed” or “untyped.”

For example, a file-system item is an object with data and behavior:

$file = Get-Item .
$file.Name
$file.Length
$file.GetType().FullName

PowerShell’s object model is documented at about_Objects.

Inspect a value before making assumptions

Get the runtime type

$value.GetType().FullName
$value.GetType().BaseType
$value.GetType().IsArray

.GetType() cannot be called on $null, so inspect null safely:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
if ($null -eq $value) {
    'Value is null'
} else {
    $value.GetType().FullName
}

Inspect members and PowerShell adaptation

$value | Get-Member
$value.PSTypeNames
$value.psobject

Get-Member shows the properties and methods exposed to PowerShell. PSTypeNames reveals the type-name list used by formatting and adaptation. The psobject intrinsic member exposes PowerShell’s adapted view of an object. Be aware that a pipeline can enumerate a collection; wrap output in @(...) when you need to inspect the collection itself:

$items = @(Get-Process)
$items.GetType().FullName
$items | Get-Member

Test or attempt a conversion

$value -is [string]
$value -isnot [int]
$date = $value -as [datetime]

-is and -isnot test types. -as attempts conversion and returns $null instead of throwing when conversion fails:

[int]'42'       # 42; a failed cast raises an error
'abc' -as [int] # $null

See about_Type_Conversion for the conversion rules and the about-topics index for related operator topics.

Type literals and accelerators

Square brackets name .NET types. Common accelerators include:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Accelerator Underlying type or purpose
[int] System.Int32
[long] System.Int64
[decimal] Exact decimal arithmetic for values such as prices
[double] Floating-point measurements
[string] System.String
[datetime] System.DateTime
[guid] System.Guid
[hashtable] System.Collections.Hashtable
[xml] System.Xml.XmlDocument
[int]42
[string]42
[datetime]'2026-08-18'
[guid]'9f7d4d4e-0b1d-4c6b-b9ac-123456789abc'
[datetime]::Now
[System.IO.Path]::GetFileName('C:Tempfile.txt')

Accelerators are aliases for .NET types, with special PowerShell handling for [pscustomobject] and [ref]. Details are in about_Type_Accelerators.

Strings, numbers, dates, and Boolean values

Strings

Single quotes preserve literal text; double quotes expand variables and subexpressions. Here-strings support multiline text.

$name = 'Ada'
"Hello, $name"
"Today is $((Get-Date).DayOfWeek)"

$count = 42
$text = '42'
$count.GetType().Name  # Int32
$text.GetType().Name   # String

The left operand commonly influences the + operator:

'10' + '2'           # 102
[int]'10' + [int]'2' # 12

Convert external text before arithmetic instead of relying on the input’s current type.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Numeric types

PowerShell supports integral, decimal, floating-point, and arbitrarily large integer values:

1.GetType().FullName
1.0.GetType().FullName
1.0d.GetType().FullName
1.0f.GetType().FullName

[decimal]$price = 19.99
[long]$largeCount = 5000000000
[bigint]$huge = 123456789012345678901234567890

Literal syntax and suffixes influence inferred types. Choose [decimal] for exact decimal calculations, [double] when floating-point behavior is acceptable, and [long] or [bigint] when 32-bit limits are insufficient. Overflow and precision loss remain possible when the chosen type is too small or approximate.

Culture-sensitive conversion

Date and numeric text can depend on culture and .NET parsing rules. An external value such as 08/18/2026 should be parsed with an explicit format and culture when ambiguity matters, rather than assumed to mean the same thing on every machine.

Booleans and truthiness

Conditional contexts convert values to Boolean. Common false-like values are $false, $null, numeric zero, an empty string, and an empty array. An empty hashtable is a notable exception and should not be casually grouped with every empty value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
if ($null -eq $value) { ... }
if ($value -eq 0) { ... }
if ([string]::IsNullOrWhiteSpace($text)) { ... }

Use explicit tests when null, zero, and empty text have different meanings.

$null, empty values, and missing data

These expressions have different shapes:

$a = $null
$b = ''
$c = @()
$d = @($null)

$a -eq $null       # True
$b -eq $null       # False
$c.Count           # 0
$d.Count           # 1

A command that emits no objects, a missing property, and an existing property whose value is $null can all require different handling. Normalize command output when zero, one, or many results are valid:

$items = @(Get-ChildItem -Path . -Filter '*.log')
$items.Count

Putting $null on the left side of a comparison—$null -eq $result—makes the intended null test unambiguous.

Arrays and collection shape

Create and type arrays

$numbers = 1, 2, 3
$numbers = @(1, 2, 3)
$single = ,7
$range = 1..5

[int[]]$typedNumbers = 1, 2, 3
[string[]]$names = 'Ada', 'Grace'

In ordinary untyped-array cases, PowerShell creates a System.Object[]. A typed array converts each element to the declared element type or reports an error.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Index, range, and count

$numbers[0]
$numbers[1..3]
$numbers[-1]
$numbers.Count
$numbers.Length

The unary comma makes one value into a single array element. The array subexpression operator @() forces a consistently array-shaped result. PowerShell 3.0 introduced several ordered and array conveniences, and Windows PowerShell 3.0 added array-like properties for zero- and one-item collections; do not assume every collection returned by a command is literally an object array.

Pipeline enumeration

PowerShell normally writes collection members to the pipeline individually. A function that appears to output an array can therefore produce separate pipeline objects:

function Get-Numbers {
    $numbers = 1, 2, 3
    $numbers
}

$items = @(Get-Numbers)

Preserve an array as one pipeline object with:

Write-Output -NoEnumerate $numbers
# or, where appropriate:
, $numbers

Assignments suppress their own output, so this does not emit the date:

$value = Get-Date
$value

Conversely, every uncaptured expression in a function can become output. return exits the current scope but does not create an exclusive C#-style return channel. See about_Arrays and about_Return.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Hashtables and ordered dictionaries

Use a hashtable for key-based lookup, nested configuration, or parameter splatting:

$config = @{
    ComputerName = 'SERVER01'
    RetryCount   = 3
    Enabled      = $true
}

$config['ComputerName']
$config.ComputerName
$config.ContainsKey('RetryCount')
$config['RetryCount'] = 5

$params = @{
    ComputerName = 'SERVER01'
    ErrorAction   = 'Stop'
}
Get-CimInstance @params

Keys and values can be arbitrary .NET objects, and nested hashtables are valid. PowerShell hashtable keys are normally case-insensitive. An ordinary hashtable does not guarantee insertion order; use [ordered] when order matters:

$ordered = [ordered]@{
    First  = 1
    Second = 2
}

Hashtables are System.Collections.Hashtable; ordered literals create an ordered dictionary. Documentation: about_Hash_Tables.

Rank #4
Sale
PowerShell for Sysadmins: Workflow Automation Made Easy
  • Book - powershell for sysadmins: workflow automation made easy
  • Language: english
  • Binding: paperback

[pscustomobject] for pipeline records

A custom object represents a record with named properties:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
$user = [pscustomobject]@{
    Name = 'Ada'
    Role = 'Administrator'
}

[pscustomobject]@{
    Computer = $env:COMPUTERNAME
    Status   = 'Online'
    Checked  = Get-Date
}

This shape displays naturally, travels well through pipelines, and is convenient for CSV or JSON export. A literal hashtable cast to [pscustomobject] has special behavior, including property-order behavior for that literal. It is not a general-purpose coercion target like [int], and $value -is [pscustomobject] is not a reliable proof that an object was created by that expression because many objects are exposed through PowerShell’s PSObject adaptation.

Behavior of Count and Length for objects produced from a hashtable cast differs between Windows PowerShell and PowerShell 6+. Consult about_PSCustomObject when writing version-sensitive code.

Choosing a representation

Need Starting choice Reason
One logical value Scalar A typed string, number, Boolean, date, or GUID is clear and compact
Ordered sequence Array Supports indexing, ranges, and iteration
Key lookup or splatting Hashtable Direct key access and flexible values
Ordered key/value data [ordered]@{} Preserves insertion order
Pipeline records [pscustomobject] Named properties and readable export
Reusable behavior and invariants Class Properties, constructors, methods, and inheritance
Fixed named choices Enum Discoverable, strongly typed symbolic values

Casting, conversion, and parameter binding

PowerShell converts values in explicit casts, constrained assignments, function parameters, operators, and cmdlet binding. The target type, source type, culture, and context all matter.

function Test-Count {
    param([int]$Count)
    $Count.GetType().FullName
}

Test-Count -Count '42'

Typed parameters improve a command’s contract, but conversion alone does not enforce semantic rules. Add validation attributes where appropriate:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
function Get-Report {
    param(
        [Parameter(Mandatory)]
        [string]$Path,

        [ValidateRange(1, 100)]
        [int]$Limit = 10,

        [ValidateSet('Summary', 'Full')]
        [string]$Mode = 'Summary'
    )

    # ...
}

Use runtime checks for conditions that attributes cannot express, and decide explicitly how $null should be handled.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Comparison operators and automatic member enumeration

Comparison conversion can be asymmetric: the left operand often influences how the right operand is converted. Do not rely on casual string/number comparisons without testing the intended types.

1 -eq '1'
'1' -eq 1

'PowerShell' -ceq 'powershell'  # False
'PowerShell' -ieq 'powershell'  # True

1, 2, 3 -contains 2
2 -in 1, 2, 3

Use -is for a type test and -as when a non-throwing conversion attempt is preferable. Details are covered by about_Operators and about_Type_Conversion.

PowerShell can retrieve a member from each collection element:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
(Get-Process).Name

There is an important exception: if the collection itself has that member, PowerShell uses the collection member instead. In this example, Length is the array’s size, not each record’s property:

$collection = @(
    [pscustomobject]@{ Length = 'foo' }
    [pscustomobject]@{ Length = 'bar' }
)
$collection.Length

Force item-level access when the distinction matters:

$collection | ForEach-Object Length
$collection.ForEach({ $_.Length })
$collection.GetEnumerator() | ForEach-Object Length

Member-access enumeration is available beginning in PowerShell 3.0 and is a convenience, not a universal replacement for explicit iteration. See about_Member-Access_Enumeration and about_Properties.

Enums for fixed choices

An enum is a named set of integral values:

enum DeploymentStatus {
    Pending
    Running
    Complete
    Failed
}

$status = [DeploymentStatus]::Running
$status
$status.GetType().FullName

The first member defaults to zero, subsequent members increment, and the underlying type is [int] unless specified otherwise. Flags use powers of two:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
[Flags()]
enum AccessLevel {
    None  = 0
    Read  = 1
    Write = 2
    Admin = 4
}

$access = [AccessLevel]('Read, Write')

Enums prevent spelling mistakes and make finite states discoverable, but arbitrary integer conversion can still create unnamed values. Enums defined in another module may require using module before functions reference them. See about_Enum.

Classes for reusable models

PowerShell classes, available beginning with PowerShell 5.0, are appropriate when a model needs constructors, validation, methods, inheritance, or stable behavior:

class ServerStatus {
    [string]$ComputerName
    [bool]$Online

    ServerStatus([string]$computerName, [bool]$online) {
        $this.ComputerName = $computerName
        $this.Online = $online
    }

    [string] ToString() {
        return "$($this.ComputerName): $($this.Online)"
    }
}

$status = [ServerStatus]::new('SERVER01', $true)

Classes can include properties, constructors, methods, static members, hidden members, and inheritance. Definitions are loaded when the file or module is parsed, so module-loading order matters. For a small pipeline transformation, [pscustomobject] is usually clearer and shorter. Documentation: about_Classes.

Serialization, formatting, and remoting traps

Formatted output is not data

Format-Table and Format-List create formatting instructions for display. Keep them at the end of a pipeline; do not feed their output into later data-processing commands.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Deserialized objects are not live objects

Remoting, jobs, and imported serialized data can produce objects whose properties remain but whose original methods and behavior do not. Their type names may include Deserialized.. Before invoking a method, inspect:

$value.PSTypeNames
$value.GetType().FullName
$value | Get-Member

A familiar property set does not prove that the original .NET object is still present. Use the relevant Microsoft Learn remoting and serialization documentation for the execution mechanism you are using.

A practical troubleshooting checklist

  1. Check for null before calling methods: if ($null -eq $value) { ... }.
  2. Inspect the runtime type with $value.GetType().FullName.
  3. Inspect exposed members with $value | Get-Member.
  4. Review $value.PSTypeNames for adapted or deserialized objects.
  5. Check collection shape with $value -is [array] and normalize command output with @(...) when zero, one, or many results are valid.
  6. Convert external text explicitly before arithmetic, date handling, or Boolean decisions.
  7. Use -as when an unsuccessful conversion should yield $null rather than an exception.
  8. Check whether a function emitted accidental output from an uncaptured command or expression.
  9. Confirm that .Length or another member belongs to the collection rather than its elements.
  10. Keep formatting commands out of the data-processing portion of a pipeline.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. Shenzhen desk3 min
    HONOR Expands Beyond Smartphones With Humanoid Robot RevealHONOR said it unveiled its first humanoid robot at MWC 2026 and named shopping assistance, workplace inspections, and supportive companionship as intended uses. Later Robotics D1 claims and a reported…
  2. Cupertino desk5 min
    Apple Unveils AirPods Max 2: The Upgrade That Should Have Happened Years AgoAirPods Max 2 adds H2-powered audio features and Apple claims up to 1.5× more effective ANC, but its design, Smart Case, and 20-hour battery rating are unchanged. Wired lossless audio…
  3. Cupertino desk4 min
    Apple’s OLED Touch MacBooks Are Coming—but the Dynamic Island Is the Real GambleApple has not announced an OLED touchscreen MacBook, but reports point to high-end models arriving in late 2026 or early 2027. The reported Mac Dynamic Island could be useful, but…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
Windows Errors? Fix Them Before They SpreadFree repair scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.