Enterprise automation. Replacing an unused platform that carried a significant annual license.
The Automation Existed. Adoption Was the Problem.
An automation platform wasn’t being adopted. I built a replacement that let engineers keep their working scripts and take better care of them.
Why weren’t people using what we already had?
Executive perspective
Why does this matter?
We were paying for something we weren’t using.
The commercial platform was capable, but it hadn’t been adopted. Buying more features wasn’t going to fix that. I started with the scripts engineers already depended on, including my own, and built a shared place to run them.
People could bring the work they already had.
Engineers could put a working script in source control, run it with controlled credentials, and keep a record of what happened. They still owned the script. They didn’t have to hand their work to another team or rewrite it before getting any benefit.
It was being used. There was still work to do.
The recorded review shows about a third of the builds coming from groups outside mine. That was a start, not adoption across the organization. We replaced a significant annual license renewal with no license cost, but still had infrastructure to pay for and a platform to run.
Architecture perspective
Why was it designed this way?
The requirements had to stand on their own.
I asked for five things: source in version control, a repeatable way to run it, controlled credentials, useful output, and a named owner. Teams could meet those requirements with another tool. They didn’t have to use mine.
A working script was a place to start.
I didn’t want engineers rebuilding something they already trusted just to get it onto the platform. We could move it into source control and a shared runtime first, then add parameters, pre-checks, saved results, and approvals where they made sense. Each step helped on its own.
The engineers still owned the work.
The engineer owned what the script did, whether it was right, and how it handled failure. My platform handled the runtime, credentials, version tracking, access, and saved output. I’d consider it adopted when the team could run its workflow without routinely needing me.
Technical perspective
How does it actually work?
GitLab held the code. Jenkins ran it.
GitLab stored source and runbooks. Jenkins scheduled jobs, coordinated the steps, and saved logs and output files. Purpose-built container agents supplied Windows and Linux runtimes. Jobs ran with scoped credentials.
Some steps needed a stop sign.
Higher-risk jobs required approval. The detailed account below describes what the platform ran and how it was used.
The detailed project account
These details come from the account written before the September 2026 site update. I’ve rewritten the wording, but kept the measurements, findings, and qualifications. “Today” and other time references describe that earlier period. I haven’t remeasured the results or assumed that open issues were fixed.
What was needed
We were paying a significant annual license for a commercial infrastructure automation platform. The product could do much of what we needed, and arguably more.
Nobody used it.
It had been poorly implemented and never adopted. We kept paying for it while the automation people actually used lived on laptops and shared servers. Those scripts worked, but someone else couldn’t safely change them.
I had the same problem. My infrastructure health checks had replaced manual work done by a separate operations team. They ran successfully on Windows Task Scheduler on a tools server. But I had no version history, saved output files, or record of what had run. I wouldn’t have been comfortable telling someone else to depend on that setup.
Earlier attempts to get systems administrators working with shared source control and repeatable deployments hadn’t stuck. As far as I know, this was the first to reach production and stay there.
What I built
What bothered me was that we already had a capable tool. People weren’t using it. I needed to address the reasons engineers hesitate to move their work: losing control of it, handing ownership to someone else, or having to rewrite scripts that already work.
I separated the requirements from the platform I was building.
The requirements were five minimum controls for automation touching production: versioned source, a repeatable way to run it, controlled credentials, useful output or evidence, and a named owner. Any tool meeting those five points was fine.
My platform was one way to meet them. GitLab held source, history, and runbooks. Jenkins scheduled and coordinated jobs, accepted parameters, required approvals, and retained logs and output files. Purpose-built Docker agents provided isolated Windows and Linux runtimes so workflows didn’t interfere with each other. Credentials were controlled and scoped to the job that needed them.
I wanted to say clearly that teams didn’t have to move everything onto my tool. That was close to what had gone wrong before. The requirements mattered more than my choice of software.
Engineers kept ownership of their logic, its correctness, and its failure handling. The platform handled the runtime, credential control, saved results, version tracking, access control, and audit logs. They could keep their scripts and run them somewhere another person could repeat the work.
For a working script, I used this sequence: put it in source control, run it manually through Jenkins, add parameters, add pre-checks, save the results, add an approval where the risk called for one, and document the owner. Each addition was useful without requiring a rewrite.
I wanted the team to be able to run and own its workflow without routinely depending on whoever wrote it. A job merely existing in Jenkins didn’t tell me that had happened.
What was running at the time
At the time of this account, three of my own workflows ran on a schedule against production infrastructure:
| Workflow | Production runs | Average | Cadence |
|---|---|---|---|
| Storage health check | 1,256 | 4.4 min | 3× daily |
| Virtualization health check | 738 | 10.0 min | 3× daily |
| Directory-to-IPAM sync | 421 | 0.4 min | nightly |
Those workflows had 2,415 production runs, with 209 of 213 succeeding in the retained window. Every pipeline pulled its secrets from the credential store, and none had secrets written into its pipeline file. Agent images explicitly pinned their contents. Higher-risk build workflows required approval.
Across the platform, thousands of builds had run, about a third of them from groups outside mine. One of those groups accounted for most of that outside work, including scheduled jobs. Those counts measured work, not users. At the time, I and a handful of other systems administrators, engineers, and architects used the platform directly.
It was in production, but use was still early. I was communicating what it could do, helping engineers find repeatable work, and helping them move that work onto it. The target was a few dozen people building, operating, or running workflows. Those were targets, not achieved user counts.
What it replaced
A significant annual license renewal, replaced at no license cost.
The commercial platform could do more than mine. It was a mature product with features I hadn’t built and might never build.
But we weren’t using it. My replacement had thousands of real executions and no license cost, though we still paid for infrastructure and had to operate it. I cared about which jobs people actually ran and whether the next person could change them safely.
What I learned
-
We had paid for the license, setup, and support of a platform nobody adopted. Before replacing it, I needed to understand why people hadn’t used it. More features wouldn’t answer that.
-
I wrote down the minimum controls separately from my tool. Other teams could meet them without giving me their work or using my platform.
-
A working script was worth keeping. Asking someone to rebuild it made starting harder. I could add source control and safer execution around what they already had.
-
One successful run wasn’t enough. I wanted someone else to be able to run it next quarter and see what it did.
-
Jenkins log rotation hid older builds. The UI showed 92 builds for a job that had run 1,256 times.
nextBuildNumber - 1survived rotation. I was undercounting my own platform by a factor of thirteen until I checked that.