Perl and PowerShell for Build Automation
The two languages mature build systems actually run on. Reading and maintaining legacy Perl without rewriting it, and writing PowerShell that fails loudly instead of silently on Windows agents.
Overview
What the job description is telling you
Perl and PowerShell together means an established build system with a Unix heritage and a Windows product surface. Nobody starts a new project in Perl, and nobody automates a Linux-only shop with PowerShell. The role keeps legacy tooling alive on one side and Windows agents on the other.
Perl is the maintenance problem
It was the right choice in 2008: the best regex engine, installed on every Unix system, unbeatable at the text manipulation build scripts are made of. That code still runs, is still correct, and is often faster than its replacement would be.
> [!NOTE] The skill tested is not writing new Perl. It is opening an unfamiliar script, understanding it quickly, changing it safely, and making a defensible call about migrating it.
- Sigils and context — What an expression means in scalar vs list context
- Scoping — my vs our vs local
- References — Two dereference syntaxes, often mixed in one file
- Data shapes — Hashes of arrays for targets and options
- Text — Regexes with captures; here-documents and their quoting rule
- Process execution — system, backticks and qx, piped open: exit status handling most legacy scripts get partly wrong
PowerShell is where new code goes, and it misleads bash users
- Good: the object pipeline — Pipes carry typed .NET objects, so filtering and selecting are property operations, not column-cutting
- Bad: error handling — Default ErrorActionPreference is Continue; non-terminating errors neither stop the script nor get caught by try/catch; native executables like msbuild raise no PowerShell errors at all
> [!IMPORTANT] That is the interview question hiding in the job description: why did the Windows build report green when it was broken? The answer involves ErrorActionPreference and the last-exit-code variable, and separates people who have run Windows CI from people who have read about it.
The operational probes
- Execution policy — What it is, its scopes, and that Microsoft documents it as not a security system restricting user actions
- PowerShell 7 vs Windows PowerShell 5.1 — When each is the right target
- Pester — Untested PowerShell is as dangerous as untested bash
- Windows toolchain — Locate Visual Studio, enter the developer shell so the compiler environment exists, and run MSBuild and signtool with exit codes that propagate
Key concepts
- use strict; use warnings;
- The two pragmas that make Perl maintainable. strict forces variable declaration and forbids symbolic references; warnings surfaces undefined-value use, numeric conversion of non-numbers, and duplicate subroutine definitions. A legacy script missing both is the first thing to fix, and the fix is usually noisy enough to deserve its own commit.
- Perl system() exit status
- system returns the wait status, not the exit code. Shift right by eight for the actual exit value. A return of -1 means the program failed to start or the wait call errored, with the reason in the error variable. Masking the low seven bits of the status gives the signal number if the child was killed.
- Getopt::Long
- The standard Perl option parser. GetOptions maps specifications to variable references and removes recognised options from the argument array. Specifications include =s for string, =i for integer, =f for float, ! for negatable, + for incrementing, =s@ to collect into an array, and =s% into a hash. It returns false when it detected parse errors, which callers routinely ignore.
- File::Find
- The core directory walker. find takes a callback and a list of directories; inside the callback the module sets the current directory, the bare filename, and the full path in three package variables. The no_chdir option stops it changing directory, in which case the filename variable holds the full path instead.
- Object pipeline
- PowerShell pipes .NET objects, not text. Get-ChildItem emits FileInfo objects so Where-Object filters on a numeric Length with no column parsing. Get-Member enumerates an object properties and methods. This is the biggest mental shift for someone arriving from bash.
- ErrorActionPreference
- Controls how PowerShell responds to non-terminating errors. Documented values are Continue, SilentlyContinue, Stop, Inquire, Ignore, and Break, with Continue as the default. Setting it to Stop escalates non-terminating errors to script-terminating errors, which is what makes try and catch and CI exit codes behave the way people expect.
- Native command exit codes
- The last-exit-code variable holds the exit code of the last native executable, as distinct from the boolean success variable. Native tools like msbuild.exe and signtool.exe raise no PowerShell error. PowerShell 7.4 added a preference variable that makes non-zero native exits issue errors according to ErrorActionPreference, with a documented default of false.
- Execution policy
- A safety feature controlling whether PowerShell loads configuration files and runs scripts. Values include Restricted, AllSigned, RemoteSigned, Unrestricted, Bypass, Undefined, and Default, and enforcement occurs only on Windows. Microsoft documents it as not a security system that restricts user actions, since script contents can simply be typed at the command line.
When to use it
- Inheriting a Unix build system with Perl scripts you must change without a rewrite budget
- Any Windows build agent — MSBuild, the Visual Studio developer shell, signtool, and installer packaging are all driven from PowerShell
- Text-heavy transformation of build output where a regex-first language genuinely is the shortest correct solution
- Cross-platform automation targeting Windows, Linux, and macOS agents from one script using PowerShell 7
- Deciding, with evidence rather than taste, which legacy scripts to migrate and which to leave alone
Interview questions
- You inherit a 4,000-line Perl build script. Walk through how you read it and how you decide whether to maintain it or migrate it.
- In Perl, how do you run an external command and correctly determine whether it failed? Cover system, backticks, and pipes.
- A PowerShell CI script reports success but the build is broken. Walk through why, and how you fix it.
- Explain the PowerShell object pipeline to someone who only knows bash. What actually changes in how you write scripts?
- How do you drive MSBuild and the Visual Studio toolchain from PowerShell on a build agent? Include the environment problem.
- How do you test PowerShell build scripts, and what does execution policy mean in CI?
Sign up free to read the full topic
More DevOps topics
- Notifications, Alerts and Webhooks
- OpenFeature & Feature Flag Governance
- OpenTelemetry
- OpenTelemetry Collector — Pipelines & Deployment
- Overlay vs Underlay Networking
- PCI-DSS and SOC 2 for Kubernetes
- Pipeline-as-Code
- Platform Engineering
- Platform Engineering & IDP Design
- Platform Engineering Maturity Model
- Pod Startup and Scheduling Errors — ImagePullBackOff, CrashLoopBackOff, Pending, Evicted
- Policy as Code
Start free on Cariara · Coding problems · System design studio