DEV Community

MartinJ
MartinJ

Posted on

NgSysV2-10.2: PowerShell Scripting essentials

This post series is indexed at NgateSystems.com. You'll find a super-useful keyword search facility there too.

Last reviewed: Apr'26

Introduction

The concept of "scripting" for PowerShell terminal session procedures was introduced in Post 4.3 without any attempt to describe the language's syntax.

This post still doesn't fully cover the subject, but here are the essentials, plus one or two "extras" I've found invaluable.

Variables, Arrays and Operators

A variable in PowerShell is a named container that holds a value, such as a string, number, array or object. PowerShell variables are dynamically typed, meaning you don't need to declare a variable's data type when assigning a value; it is determined by the assigned value. But note that once assigned, types are strongly enforced.

Variable names in PowerShell are introduced with a $ symbol. Variable names are not case sensitive, so, for instance, $MyVariable and $myvariable refer to the same variable.

Operators

Arithmetical — For mathematical calculations (+, -, *, /, %)
Comparative — For comparing values (-eq, -ne, -gt, -lt, -ge, -le)
Logical — For combining conditions (-and, -or, -not)

Comments

Introduce these with a # symbol,

Output

You can write to the console with the following arrangement

Write-Output "$MyMessage" # write this to the terminal
Enter fullscreen mode Exit fullscreen mode

You can write to a file as follows:

$LogPath = "c:/path-to-my-log-file"
$MyMessage  = " .... "
Add-Content -Path $LogPath -Value $Message
Enter fullscreen mode Exit fullscreen mode

Loops

For loop — Used when you know the exact number of iterations required. It’s commonly used for tasks such as incrementing counters or processing arrays.
While loop — Continues executing as long as a specified condition evaluates to True. It’s ideal for scenarios where the number of iterations depends on a dynamic condition.
ForEach loop — Designed for iterating through collections like arrays or output from commands.For example:

$i = 0 # Initialise a counter
while ($i -lt 5) {    
Write-Output "Iteration: $i"   
 $i++
}
Enter fullscreen mode Exit fullscreen mode

Conditionals

Powershell's If-Else syntax follows the following model:

$num = 10
if ($num -gt 5) 
{    Write-Output "$num is greater than 5"} 
else 
{    Write-Output "$num is less than or equal to 5"}
Enter fullscreen mode Exit fullscreen mode

"Null"

In PowerShell,

$MyVariable = $null
Enter fullscreen mode Exit fullscreen mode

means “This variable exists, but it contains no value”

It is particularly useful because it evaluates to "false", along with :

  • $false → explicit boolean false
  • $0 → numeric zero
  • $"" → empty string
  • $@() → empty array

Which is very handy because you can now do:

$MyVariable = $null

if ($MyVariable) {
    Write-Output "True" # or - a handy shortcut - just say "True"
}
else {
    Write-Output "False"
}
Enter fullscreen mode Exit fullscreen mode

Functions

PowerShell lets you define and reference shared blocks of code with the following model:

function Display-Greeting {
    param(
        [string]$Name,
        [int]$Count
    )
    Write-Output "Name: $Name"
    Write-Output "Count: $Count"

    for ($i = 1; $i -le $Count; $i++) {
        Write-Output "Hello $Name ($i)"
    }
}
...
Display-Greeting -Name "Martin" -Count 3
Enter fullscreen mode Exit fullscreen mode

Options exist for the function to accept only valid parameter values - ask ChatGPT for details

Referencing a script with parameters

A parent script can call a subordinate "child" script as follows:

& ".\child.ps1" -Param1 value1 -Param2 value2
Enter fullscreen mode Exit fullscreen mode

Meanwhile, the slave script might be configured as follows:

param(
    [Parameter(Mandatory = $true)]
    [string]$Param1,

    [Parameter(Mandatory = $true)]
    [string]$Param2
)
Enter fullscreen mode Exit fullscreen mode

The "Try ... Catch" block

Just as in JavaScript, you can capture exceptions and direct them to a "problem-resolution" block:

try {    
    # Code that might throw an error   
} catch {    
    Write-Output "An error occurred: $_"} 
finally {    
    Write-Output "This code always runs, regardless of errors"
}
Enter fullscreen mode Exit fullscreen mode

More usefully, you might consider opening an account with pushover and configuring your script to send a notification to your mobile phone. Registration and configuration are extremely easy and, last time I checked, a lifetime account with pushovercosts just $5.

} catch {    
    curl.exe -s -o NUL --form-string "priority=1" `
        --form-string "token=aiu7yk ..obfuscated... 5uerqq6ix" `
        --form-string "user=ueczz ..obfuscated... jrv54u22" `
        --form-string "message=Something has gone wrong with your nightly .. run" `
        https://api.pushover.net/1/messages.json
}
Enter fullscreen mode Exit fullscreen mode

The -s -o NUL parameter bit above simply suppresses the display of the "response" from curl.exe, which is no help at all when this is running in the Windows scheduler.

But when adding a try block, you need to know that PowerShell does not throw exceptions for many errors by default (especially for external commands). You can fix this either by adding explicit error-handling instructions to individual commands:

Some-Command -ErrorAction Stop
Enter fullscreen mode Exit fullscreen mode

or, more realistically, by setting global instructions with:

$ErrorActionPreference = "Stop"
Enter fullscreen mode Exit fullscreen mode

The "pipeline"

An advanced PS1 script will make extensive use of an arrangement that lets you "chain" commands together with a "pipe" symbol - | - that passes the output from one command as an object that then provides input to the next. So, in

Get-Process | Sort-Object CPU
Enter fullscreen mode Exit fullscreen mode
  • Get-Process → produces "process objects"
  • Sort-Object → receives those objects and sorts them by a property

No string parsing, no fragile text handling — just structured data flowing through. PowerShell passes objects, not text, and binds them by property name or type. Here's another example:

Get-Service | Where-Object {$_.Status -eq 'Running'}
Enter fullscreen mode Exit fullscreen mode
  • Get-Service → outputs service objects
  • Where-Object → filters them, selecting those with status "running"

Most pipelines follow this shape:

Producer | Filter | Transform | Output
Enter fullscreen mode Exit fullscreen mode

For example:

Get-Process |
Where-Object {$_.CPU -gt 100} |
Select-Object Name, CPU |
Out-File processes.txt
Enter fullscreen mode Exit fullscreen mode

You’ll use these constantly:

  • Where-Object → filter
  • Select-Object → pick properties
  • Sort-Object → sort
  • ForEach-Object → act on each item

Top comments (0)