F# pattern matching for cleaner systems administration scripts

Administration scripts often begin as a small success check and end as a thicket of exit codes, temporary files and conditional branches. F# pattern matching provides a clearer shape: describe the outcomes a tool can produce, then handle each one explicitly.

F# is practical on Windows, Linux and macOS because it runs on .NET and can orchestrate PowerShell, SSH and command-line tools. Its type-safe discriminated unions and exhaustive matching are especially useful when a check may pass, warn, fail or return no usable data.

Consider a script that verifies a backup, web service or storage pool. Instead of flattening every result to a Boolean, a union such as Healthy, Warning or Failed preserves the distinction. The compiler identifies missing branches, while unit tests turn operational states into readable examples.

Clean logic matters for Australian teams working in Sydney, Melbourne and Brisbane, who must also account for time zones and daylight-saving changes that complicate overnight schedules. Local cloud regions, Australian support arrangements and privacy obligations also shape what a trustworthy script should do. The goal is maintainable automation, not academic elegance.

Model operational outcomes as explicit states

A useful first step is to separate command execution from interpretation. Model what the check means rather than passing raw exit codes through every layer.

type ServiceState =
    | Running
    | Stopped
    | Degraded of reason: string
    | Unknown

let describe state =
    match state with
    | Running -> "healthy"
    | Stopped -> "not running"
    | Degraded reason -> $"degraded: {reason}"
    | Unknown -> "no reliable answer"

The benefit is not shorter code alone. A new state forces a decision about behaviour, and an unhandled state becomes visible during compilation. Keep Unknown separate from Failed; treating missing telemetry as a confirmed outage can trigger unnecessary restarts.

Match command results without defensive clutter

Wrapping tools in a small function lets the rest of the script match a standard result. A command can return Ok output or Error details, with the wrapper responsible for timeouts, stderr and exit-code translation. This keeps vendor-specific quirks at the boundary.

That explicit contract improves handovers as much as maintainability. The emphasis on clear expectations in Elizabeth Mitchell’s interview insights fits the same operational need: automation should report what happened, not merely that it finished. A named failure is more useful than an ambiguous empty string.

Use Option when absence is legitimate, such as no matching hosts, but keep genuine execution failures as Error. Pattern matching then forces callers to distinguish those cases. For cloud APIs, active patterns can extract a status field while ignoring irrelevant JSON properties.

Turn deployments into testable decisions

Deployment checks often parse JSON, CSV or command output before deciding what to do. Parse that data into a union first, then match on it. A rollout might have Ready, RollingBack, NeedsApproval and Completed states, each with different consequences.

This arrangement makes tests straightforward. A table or list of named cases can assert that Ready starts the next region, NeedsApproval pauses and RollingBack raises an alert. Unusual inputs belong in the model too, rather than appearing as mysterious fallback branches.

Keep irreversible actions behind small functions with clear names. Isolate stopping a service from evaluating its health. It becomes obvious during code review that a match cannot accidentally reboot a host. Error handling also stays close to the operation that failed.

Connect software checks to real hardware

Storage monitoring is where clean abstractions meet messy devices. SMART attributes, controller tools and vendor-specific output can expose the same disk problem in different formats. Before writing the parser, compare hardware vendor comparisons to see which tools and capabilities apply to your actual equipment.

Normalise the relevant readings into a small union, then match on them. A disk can be Healthy, Failing, Unreadable or Unchecked. The last state matters: a failed query is not evidence that the disk has failed and should not be folded into either answer.

For an Australian home lab built around a spare mini PC or retired business server, this separation is especially valuable. Consumer disks and second-hand controllers may report differently. Local resellers and managed service providers can also influence the choice through warranty support, spare-part availability and repair turnaround.

Weigh RAID choices for Australian workloads

RAID decisions need the same care. The trade-offs summarised in hardware versus software RAID show why there is no universal winner. A hardware controller can provide dedicated processing, while software RAID or ZFS offers flexibility and useful diagnostics. Existing skills often matter more than a small benchmark difference.

For Australian organisations, data location and recovery time deserve equal attention. A copy held in an overseas cloud region may satisfy some backup goals but still be awkward to reach during a local outage. Local-region infrastructure can improve latency, although residency alone does not prove recoverability.

Logs can contain personal information, so storing every diagnostic dump indefinitely is not a neutral choice. The Privacy Act 1988 and the Australian Privacy Principles require governance of covered information. Restrict access, define retention and avoid putting customer identifiers into routine alert messages.

Put the patterns into a reliable workflow

These practices fit into a workflow that works beyond a single script:

  • Model operational outcomes as named states instead of raw exit codes.
  • Keep command execution separate from interpretation and decision-making.
  • Handle missing data explicitly; never let Unknown become success by default.
  • Test normal, warning, failed and incomplete scenarios as separate cases.
  • Log structured context and correlation identifiers without exposing secrets.
  • Make retries idempotent and verify timeouts around daylight-saving changes.

These checks are easier to review when they live beside the scripts they protect. Start with read-only reporting, compare its output with the current manual process, and add actions only after the states and ownership are clear.

The next step is concrete: choose one read-only service check, convert its outcomes into a discriminated union, and add a test for each branch. Run it in report-only mode through an Australian business day, then automate a response once the logs and owners are agreed. That small cycle turns a brittle shell script into dependable operational tooling.

Experience

Information Technology Consulting

Independent Practice

Provides IT consulting services focused on infrastructure planning, cloud migration strategy, and systems architecture. Engagements draw on years of hands-on sysadmin and development experience across Linux, Windows, and hybrid environments.

K9 Search & Rescue Volunteer

Ongoing

Active participant in K9 Search & Rescue operations, combining technical logistics skills with field support for canine search teams.

Karl Katzke's Blog

October 2006 – May 2014

Published a long-running personal technology blog covering cloud vs. in-house infrastructure, F# and Mono on OSX, hardware vendor critiques, RAID card performance analysis, and sysadmin storytelling. Notable posts include "When Sysadmins Ruled the Earth" (May 15, 2014) and "Getting Started with F# and Mono on OSX" (December 22, 2012).

Credentials

A small badge icon with a shield shape in muted blue tones on a light background

Systems Administration

Deep experience with Linux (RHEL, SLES, CentOS), high-availability clusters, and STONITH configurations.

A small badge icon with a gear shape in muted blue tones on a light background

Cloud Infrastructure

Practical knowledge of AWS EC2, reserved instances, and cost analysis for cloud vs. on-premises deployments.

A small badge icon with a code symbol in muted blue tones on a light background

Development

Proficient in F#, PHP (Symfony), and cross-platform tooling including Mono and MonoDevelop on OSX.

Studies

F# & Functional Programming

Self-directed, 2012

Explored strongly typed functional programming with F# on OSX using the Mono runtime. Published a detailed getting-started guide covering toolchain setup and cross-platform game development research.

High-Availability & Cluster Management

Professional Development, 2009

Configured and documented crm_mon email alerting for STONITH events on SLES11-HAE clusters, integrating with Nagios monitoring for production environments.

Hardware & Storage Performance

Ongoing

Conducted hands-on benchmarking of SATA/SAS RAID controllers including HighPoint RocketRaid 2740 and LSI/SuperMicro AOC-USASLP2-H8iR, comparing against software RAID configurations.

Skills

A small icon representing a server with clean geometric lines in slate blue

Linux Administration

RHEL, SLES, CentOS — package management, kernel tuning, HA clustering, and monitoring integration.

A small icon representing a cloud shape with clean geometric lines in slate blue

Cloud Architecture

AWS EC2, reserved-instance planning, cost modeling, and hybrid infrastructure strategy.

A small icon representing code brackets with clean geometric lines in slate blue

F# & .NET/Mono

Functional programming on OSX, MonoDevelop toolchain, and cross-platform game-dev exploration.

A small icon representing a database cylinder with clean geometric lines in slate blue

PHP & Symfony

Web application development with the Symfony framework and the broader PHP ecosystem.

A small icon representing a storage drive with clean geometric lines in slate blue

Storage & RAID

SATA/SAS controller evaluation, md RAID configuration, and performance benchmarking.

A small icon representing a shield with clean geometric lines in slate blue

High Availability

Pacemaker, STONITH, crm_mon alerting, and Nagios integration for production cluster monitoring.