Onboarding and offboarding automation
Provisioning and deprovisioning people across SSO, groups, and hardware — without the half-applied state a failed script leaves behind. Build idempotent onboard/offboard tasks in OrchStep.
blog/onboarding-offboardingOnboarding a new hire touches half a dozen systems: SSO account, group memberships, a laptop, a welcome checklist. Offboarding undoes all of it. Most teams run this from a script, and the script has one nasty property — when it fails on step four, it leaves the person half-provisioned, and re-running it either errors out or double-creates whatever step one already did.
The cure is idempotency: every step is phrased so running it twice is a no-op. "Ensure the account exists," not "create the account." Then a failed run is just a re-run, and a partially-offboarded person is one more orchstep run offboard away from clean. This post builds both tasks that way.
Two tasks, one file
onboard and offboard live in the same workflow — the systems they touch are the same, just in reverse. Each step "ensures" a state rather than performing a one-shot action.
name: identity
# Provision (onboard) and deprovision (offboard) a person across systems.
# Every step is phrased to be idempotent: running it twice is a no-op.
defaults:
person: jordan
tasks:
# `orchstep run onboard --var person=jordan`
onboard:
steps:
- name: account
func: shell
do: echo "ensuring an SSO account exists for {{ vars.person }}"
- name: groups
func: shell
do: echo "ensuring {{ vars.person }} is in the engineering groups"
- name: laptop
func: shell
do: echo "ensuring a laptop is assigned to {{ vars.person }}"
- name: welcome
func: shell
do: echo "{{ vars.person }} onboarded — sending the welcome checklist"
# `orchstep run offboard --var person=jordan`
offboard:
steps:
- name: revoke
func: shell
do: echo "ensuring {{ vars.person }}'s SSO sessions are revoked"
- name: groups
func: shell
do: echo "ensuring {{ vars.person }} is removed from all groups"
- name: archive
func: shell
do: echo "ensuring {{ vars.person }}'s mailbox is archived"
finally:
- name: record
func: shell
do: echo "offboarding of {{ vars.person }} recorded for audit"Every do: here is echo-only so the demo runs anywhere. In your version each step shells out to the real API — Okta, your IdP, an MDM endpoint — but the phrasing is the contract: each call is a "make it so," safe to repeat.
Why idempotent steps change the failure story
A one-shot script and an idempotent workflow diverge the moment something fails halfway:
create_sso_account "$USER" # already ran last time -> errors "exists"
add_to_groups "$USER"
assign_laptop "$USER" # this is where it died
send_welcome "$USER"
# re-run? step 1 now fails, and you're stuck editing the script by hand- name: account
do: echo "ensuring an SSO account exists for {{ vars.person }}"
- name: groups
do: echo "ensuring {{ vars.person }} is in the engineering groups"
- name: laptop
do: echo "ensuring a laptop is assigned to {{ vars.person }}"
# re-run? every step is a no-op until it reaches the one that failedWith the idempotent version, recovery is the same command you ran the first time. No "where did it stop" archaeology, no commenting out the steps that already succeeded. The offboard task adds a finally: so the audit record is written even if a deprovisioning step fails — because the one thing you can't afford to lose is the record that you tried to offboard someone.
Preview before you provision
Onboarding touches real accounts, so seeing the plan first matters. A dry run resolves the person and prints every step without calling a single API:
orchstep run onboard --var person=jordan --dry-runSwap the name, read the plan, then run it for real. More: Previewing with Dry Run.
What you gained
| Concern | one-shot script | OrchStep |
|---|---|---|
| Failed halfway | manual surgery | re-run the same command |
| Onboard + offboard | two scripts | two tasks, one file |
| Audit on failure | lost if it crashed | finally: record step |
| Who to provision | edit the script | --var person= |
If your team adds one person a quarter, a checklist is fine. At enterprise hiring volume, the half-applied state is the expensive part — idempotent steps make it cheap.
Where to go next
- Variables & Outputs — driving a task with
--var - Error Handling —
finally:and guaranteed steps - Quick Start — your first workflow in two minutes
Got an onboarding script that breaks when you re-run it? Phrase every step as "ensure," and recovery becomes a repeat.
curl -fsSL https://orchstep.dev/install.sh | sh