Field notes · onboarding

The onboarding intake form that ended the email tag

The manager-facing form and 5-second approval gate that replaced my new-hire email threads: the fields, the validation that matters, and what it caught.

·7 min read

In my onboarding post I built the provisioning script and admitted up front that it leaned on a promise: clean, structured inputs. This post builds the thing that keeps the promise, the intake form. An intake form is the structured, validated capture of a request, and it is the least glamorous and most valuable component in the whole onboarding system.

I know that sounds backwards. The PowerShell is the part that looks like automation. But the script only ever failed me when its inputs were wrong, and before the form, every input arrived by email, hallway, or guess. I once spent three email threads establishing the legal spelling of a new hire’s last name. The account took ninety seconds to create. The name took two days.

Key takeaways

  • The provisioning script was never the bottleneck. Collecting clean inputs was, so the form is where the value lives.
  • Every field a lookup can fill should be a dropdown, not a text box. Free text is where group mappings go to die.
  • Validate at the boundary twice: once in the form for the manager, again in the script that consumes the request.
  • The approval gate costs about 5 seconds per hire and catches the class of mistake no validation rule anticipates.

Why is the form the most valuable part?

Because it converts an interrupt into a record. Before the form, a new hire reached me as a conversation, and conversations have no required fields. After it, a hire reaches me as a complete, validated request I can act on whenever I choose. The urgency moved out of my inbox and into a queue.

The form also changes who does the waiting. When I chased missing fields, I waited on managers. Now the form refuses to submit without them, so the two days of name-spelling email tag happen inside one screen, before the request exists. The manager fills in the blanks because the form will not let them not.

What fields does the intake form need?

Fewer than you think, and stricter than you think. Mine has eight. The rule for each: if a lookup can produce the valid answers, the field is a dropdown backed by that lookup, never free text.

Field Input type Why it’s strict
Legal first and last name Text, required Feeds the account and payroll; the one field only the manager knows
Preferred name Text, optional Drives the display name; defaults to legal
Department Dropdown from config Keys the department-to-groups map; free text breaks it
Role / title Text, required Lands on the account; searchable later
Manager Dropdown from the directory A typo here misroutes approvals and org charts
Start date Date, must be today or later A past date is always a mistake
Employment type Dropdown Full-time, part-time, seasonal; drives account expiry
Notes Text, optional The escape hatch for everything I didn’t predict

The department dropdown deserves the emphasis. It reads from the same configuration file the provisioning script uses for its department-to-groups map, so the form literally cannot submit a department the script doesn’t know. Before I wired that, I found the same department living under two spellings in two systems, and the group lookup silently missed for one of them. One source of truth ended it.

How strict should validation be?

Strict at both ends. The form validates for the manager’s benefit, so they get a red box instead of a bounce-back email. Then the provisioning script validates the request again on its own, because the script is the security boundary and a form is just one polite way to reach it. Boundary validation means re-checking every input where it is consumed, not just where it is collected.

# The script trusts nothing, including its own form.
$request = Get-Content $requestFile -Raw | ConvertFrom-Json

if (-not $DepartmentGroups.ContainsKey($request.Department)) {
    throw "Unknown department '$($request.Department)' in request $($request.Id)"
}
if (-not (Get-ADUser -Filter "SamAccountName -eq '$($request.ManagerSam)'")) {
    throw "Manager '$($request.ManagerSam)' not found for request $($request.Id)"
}
if ([datetime]$request.StartDate -lt (Get-Date).Date) {
    throw "Start date $($request.StartDate) is in the past for request $($request.Id)"
}

That looks redundant. It is redundant on purpose. The day someone submits a request by a path that isn’t the form, an API call, a hand-edited file, a well-meaning coworker, the script’s own checks are the ones that hold.

How does the approval gate work?

A submitted request becomes a pending record, and nothing happens until I glance at it and click approve. That glance takes about 5 seconds. The first week the form was live, it caught a request where the manager had listed themselves as the new hire’s manager and typed a start date in the past. Validation caught the date. Only a human noticed the manager field was technically valid and still wrong.

That is the whole argument for the gate. Validation catches malformed requests; a person catches plausible nonsense. The approve click is also my audit record: who asked, who approved, when, and what the script did about it, all in one place. In the offboarding post I called the checklist the system. Here, the request record is the system. The account is just its output.

What did I build it with, and does it matter?

A small internal web app, and no, it mostly doesn’t matter. The pattern needs a form with server-side validation, a place to store pending requests, and something the approval click can trigger. Any stack that does those three things works. If you’d rather not host anything, Microsoft Forms plus Power Automate can capture the request and drop it somewhere a script watches, and a ticket system with required fields gets you most of the way too.

What does matter: the request must end up as structured data a script can read, not as prose a human re-types. If your intake produces an email that someone transcribes into a terminal, you’ve automated the paperwork and kept the error rate.

What broke, and what I would change

The form nobody can find might as well not exist. My first version lived at an address I emailed to managers once, and for weeks they kept emailing me instead, because the form wasn’t where they already looked. Putting the link on the intranet page they actually use, and replying to every hallway request with the link (politely, every time), is what changed the habit. I learned that adoption is a distribution problem, not a software problem.

Duplicates surprised me too. A manager, unsure the first submission took, submitted the same hire twice. The provisioning script’s idempotency check caught it, but the right fix was earlier: the form now warns when a pending request already matches the same name and start date.

And I’d design the notes field in from day one. Mine started as an afterthought and instantly became the most-used field, holding everything from “needs the same access as the person retiring” to badge details. Whatever you don’t model, the notes field will catch, and reading it is part of the approval glance.

FAQ

What should an onboarding intake form ask for?

Legal name, preferred name, department, role, manager, start date, and employment type, with a free-text notes field for the rest. Make department and manager dropdowns backed by your config and your directory, so an invalid value cannot be submitted in the first place.

Do you really need a custom web app for intake?

No. The pattern is a validated form, a stored request, and an approval that triggers provisioning. Microsoft Forms with Power Automate, or a ticket system with required fields, both work. The non-negotiable is that the request lands as structured data, not as an email someone re-types.

Why keep a human approval if the form validates everything?

Because validation catches malformed input and a human catches plausible nonsense: the wrong-but-real manager, the duplicate hire, the request that smells off. The glance costs seconds. In my first week it caught two mistakes validation passed.

How do you get managers to actually use the form?

Put the link where they already look, and answer every out-of-band request by pointing at the form instead of fulfilling it. Adoption is habit-building, not software. It took a few weeks of polite redirection before the hallway requests stopped.