In the course of my daily work on complex IT infrastructures and automation, useful small helpers and modules emerge. I share these tools on GitHub and via the PowerShell Gallery to make administration and development easier for others.

Split-Array

PowerShell module
Repository on GitHub

Sequential processing of large data sets can take a long time — especially with cloud APIs. The answer is parallelisation, and for that the data first has to be split into portions (chunks).

So this wheel isn’t reinvented in every script, Split-Array takes care of exactly this step: it splits an array into an array of arrays — either by maximum chunk size or into a fixed number of chunks.

Small but neat: edge cases are handled, and input works both as an argument and via the pipeline.

ONE ARRAY · 8 ELEMENTS 1 2 3 4 5 6 7 8 Split-Array 1 2 3 4 5 6 7 8 ARRAY OF ARRAYS · 3 CHUNKS

Installation

The module is installed straight from the PowerShell Gallery:

Install-Module SplitArray          # PowerShellGet
Install-PSResource SplitArray      # PSResourceGet

PowerShell 5.1 or newer is required. Alternatively, clone the repository and import the module via its manifest SplitArray.psd1.

Note: Published in the PowerShell Gallery as SplitArray.

Usage examples

1. Split by maximum chunk size (-ChunkSize)

Defines the maximum number of elements allowed in a sub-array. Ideal for API batches.

# Greedy distribution (default): fills chunks to the maximum
Split-Array -InputObject 1..10 -ChunkSize 3
# Result: (1,2,3), (4,5,6), (7,8,9), (10)

# Even distribution: spreads the remainder evenly
Split-Array -InputObject 1..10 -ChunkSize 3 -Distribution Even
# Result: (1,2,3), (4,5,6), (7,8), (9,10)

2. Split into exactly N chunks (-MaxChunk)

Splits the array into a fixed number of chunks.

# Even distribution (default): produces exactly 4 balanced chunks
Split-Array -InputObject 1..10 -MaxChunk 4
# Result: (1,2,3), (4,5,6), (7,8), (9,10)

3. Pad the last chunk (-Pad)

Fills the last chunk with a value until it matches the size of the first chunk — useful when downstream code expects equally sized chunks.

# Pad with $null up to the full chunk size
Split-Array -InputObject 1..10 -ChunkSize 3 -Pad $null
# Result: (1,2,3), (4,5,6), (7,8,9), (10,$null,$null)

Distribution strategies

Comparison of the Greedy and Even distribution strategies
Strategy Behaviour Default for
Greedy Fills each chunk to the maximum; the last chunk takes the remaining elements. -ChunkSize
Even Spreads the remainder element by element across the first chunks; always produces exactly the requested number of chunks. -MaxChunk

Parameters

Overview of the Split-Array parameters
Parameter Function
InputObject The array or elements to split. Accepts pipeline input.
ChunkSize Maximum number of elements per chunk. Mutually exclusive with -MaxChunk.
MaxChunk Desired number of output chunks. Mutually exclusive with -ChunkSize.
Distribution Distribution strategy Greedy or Even — controls how the remainder is placed.
Pad Value used to fill the last chunk to a uniform size (e.g. $null, 0, "x").

Join-Object

PowerShell module
Repository on GitHub

Within a single cmdlet the PowerShell pipeline is elegant. But as soon as the outputs of several cmdlets have to be combined, the manual work begins: loops, temporary variables and hand-maintained hashtable lookups.

Join-Object combines the outputs of two cmdlets by a shared identity — such as an SMTP address or GUID — into a single object, right in the pipeline.

Each cmdlet is called exactly once, without any explicit loops. The result stays a compact, readable one-liner.

CMDLET A · ID + A + B ID A B CMDLET B · ID + C + D ID C D by identity ID A B C D ONE OBJECT · ID + A + B + C + D

Installation

The module is installed straight from the PowerShell Gallery:

Install-Module JoinObject          # PowerShellGet
Install-PSResource JoinObject      # PSResourceGet

PowerShell 5.1 or newer is required. A short alias Join is available for calling it.

Note: Published in the PowerShell Gallery as JoinObject.

Usage examples

1. Join scheduled tasks with runtime info

Links Get-ScheduledTask and Get-ScheduledTaskInfo by their shared TaskName property.

Get-ScheduledTask | Join Get-ScheduledTaskInfo -IdentityProperty TaskName |
    Select-Object TaskName, State, LastRunTime, LastTaskResult

2. Enrich mailbox statistics

Adds its statistics to each shared mailbox — one call per cmdlet, no loop.

Get-Mailbox -RecipientTypeDetails SharedMailbox |
    Join-Object Get-MailboxStatistics |
    Select-Object PrimarySmtpAddress, TotalItemSize, ItemCount

3. Pass through parameters and overwrite fields

Via -Options (alias -With) additional parameters go to the target cmdlet; -Force overwrites fields of the same name instead of suffixing them.

$Users | Join-Object Get-ADUser -With @{ Properties = 'Department', 'Office' } -Force

Parameters

Overview of the Join-Object parameters
Parameter Function
Cmdlet Name of the cmdlet whose output is joined.
InputObject The object from the pipeline; passed automatically.
IdentityProperty Explicit identity property, if it is not detected automatically.
Options (With) Hashtable of additional parameters for the target cmdlet.
Force Overwrites fields of the same name instead of suffixing them.

Invoke-WithEcho

PowerShell module
Repository on GitHub

What DOS batch files always offered with ECHO ON is still missing from PowerShell: a log that records, before each command, what is about to run. In long logs, output therefore often can no longer be attributed to the command that produced it.

Invoke-WithEcho runs a script block and logs the command text beforehand — together with type and current value of every variable the block reads. Combined with Start-Transcript, every line in the log becomes attributable to its trigger.

Resolution only reads the variables from the caller’s scope — nothing is executed twice, no side effects. SecureStrings and credentials appear masked, and the block’s output passes through the pipeline unchanged.

ONE SCRIPT BLOCK { Get-ChildItem $sourcePath } Invoke-WithEcho >> Get-ChildItem $sourcePath $sourcePath = C:\data\import a.csv · b.csv ECHO IN THE TRANSCRIPT RETURN UNCHANGED

Installation

The module is installed straight from the PowerShell Gallery:

Install-Module InvokeWithEcho          # PowerShellGet
Install-PSResource InvokeWithEcho      # PSResourceGet

PowerShell 5.1 or newer is required.

Note: Published in the PowerShell Gallery as InvokeWithEcho.

Usage examples

1. Log a command including variable values

The command text appears literally as written, with type and value of every variable read below it. The assignment belongs before the call — the block runs in a child scope, so assignments inside the block evaporate.

$sourcePath = 'C:\data\import'
$files = Invoke-WithEcho { Get-ChildItem $sourcePath -Filter *.csv }

# Echo output (also lands in the transcript):
# >> Get-ChildItem $sourcePath -Filter *.csv
#    $sourcePath  String  1  C:\data\import

2. Working with Start-Transcript

The echo lines travel via the information stream and therefore land in the transcript — every piece of output in the log can be attributed to the command that produced it.

Start-Transcript deploy.log
Invoke-WithEcho { Copy-Item $source $target -Recurse }
Invoke-WithEcho { Restart-Service $serviceName }
Stop-Transcript
# deploy.log holds each command with its values — before its output

3. Control and redirect the output

With -NoExpand only the command text is logged; via 6> the echo lines can be redirected to a file or suppressed — the return value stays untouched.

# Log only the command text, without variable values
Invoke-WithEcho { Get-Content $configPath } -NoExpand

# Redirect the echo lines to a file instead of the console
$result = Invoke-WithEcho { Get-Process } 6> echo.log

Parameters

Overview of the Invoke-WithEcho parameters
Parameter Function
ScriptBlock The block to execute. Mandatory, may be passed positionally.
MaxValueLength Maximum length per logged variable value (default 100); longer values end with “…”.
NoExpand Logs only the command text, without variable values.
CommandColor Console colour of the command lines (default Cyan) — affects the console only, the transcript stays plain.
ValueColor Console colour of the variable lines (default DarkGray).
NoColor Writes the echo lines in the console’s default colour.
Looking ahead

More over time

I have set out to share small helpers from my day-to-day work here, one by one. Whatever proves itself in practice earns its place on this page.