Two different abstractions, often confused
Jaws Deploy gives you two ways to share deployment logic. They look related, but they solve different problems and you will use both.
// Step templates
A reusable step with a UI
Encapsulate a deployment action - extract a package, configure a service, restart IIS - with structured inputs and validation. Used by selecting it in a project's deployment process.
// Script modules
Shared PowerShell functions
Pure code reuse. A library of functions that any deployment script can import-module and call. No UI, no inputs - just functions you don't want to redefine.
Step templates: structured, reusable, validated
A step template is a parameterized step you can drop into any project's deployment process. It has:
Beyond "a script in a file"
- Typed inputs - strings, multi-line text, secrets, references to packages, choices from a dropdown.
- Per-input validation - required vs. optional, default values, help text, even sensitive-data marking.
- Versioning - bump the template version when you change behavior; projects opt in to the new version.
- Permissions - team members can use the template without seeing or editing its body.
- Discoverability - templates show up in the step picker with their description. New team members find them.
What you author once, what every project gets
The template defines inputs and a body. Projects pick the template, fill in the inputs, and get a validated step.
# Template: Deploy-WindowsService
#
# Inputs:
# ServiceName (string, required)
# PackageName (package reference, required)
# StopTimeoutSec (number, default 30)
# RunAsUser (string, optional, sensitive: true)
#
# Body (PowerShell):
param($ServiceName, $PackagePath, $StopTimeoutSec, $RunAsUser)
Stop-Service $ServiceName -Force -Timeout $StopTimeoutSec
Expand-Archive -Path $PackagePath -DestinationPath "C:\Services\$ServiceName" -Force
if ($RunAsUser) {
sc.exe config $ServiceName obj= $RunAsUser
}
Start-Service $ServiceName
Script modules: shared PowerShell functions
A script module is a regular PowerShell module the platform manages. You write functions, you publish the module, and any deployment step in any project can Import-Module it and call the functions.
The rule of thumb: if you have written the same five-line helper in three scripts, it belongs in a module.
Things that live well in a script module
Invoke-Migration, Wait-DatabaseReady, Backup-BeforeChange - the small functions every team rewrites.
Versioning, ownership, and the politics of shared code
The usual trap with shared deployment code is the same as with any internal library: one team owns it, another team needs a feature, the owners are busy, the consumers fork it. A few practical decisions help.
Lessons from teams that did this and lived
- Pick owners. Templates and modules need a maintainer. "Everyone" means "no-one".
- Version on change. Bump the template version whenever behavior changes. Don't silently mutate.
- Deprecate, don't delete. Keep old versions usable while consumers migrate.
- Document inputs. The help text on each template input is what the consumer sees. Treat it like API docs.
- Treat shared code like product code. It deserves PR review, tests, and a changelog.
The pay-off, six months in
A team that has invested in a small set of well-named step templates and one or two reliable script modules ends up with deployment processes that read like sentences. The deployment process for a new service is mostly "select template, fill three fields, select template, fill two fields." The interesting custom code lives in modules where it is reused.
That is the long-term shape Jaws Deploy is built for - and it is the part that pays back the hours you spend setting it up in the first place.