Bulk changes are where careers end: 400 mailboxes modified from a CSV with one bad column, and no record of the previous state. Three conventions — validate the input, dry-run the change, write the rollback file before touching anything — let you run AI-generated bulk operations against AD, Entra and M365 and still sleep.
Tier: Core · Workflow area: Scripting & automation · ~35 minutes
This playbook wraps every CSV-driven bulk operation in three mandatory layers: input validation that rejects bad data loudly, a dry-run pass whose output a human reads, and a generated rollback file capturing prior state — with AI writing the boilerplate for all three so the safety net costs minutes, not discipline.
Generate the wrapper with all three layers demanded up front. Extend the pb-21 prompt:
Write a PowerShell script for a bulk operation via Microsoft Graph:
set the department attribute for users listed in a CSV
(columns: UserPrincipalName, NewDepartment).
Mandatory structure:
PHASE 1 — VALIDATE: check CSV headers exactly match; every UPN
well-formed and resolvable in Entra; NewDepartment non-empty and in
the allowed list passed as a parameter; duplicates flagged. Any
failure: write a validation report and EXIT before any change.
PHASE 2 — ROLLBACK CAPTURE: for every valid row, fetch and write
current state (UPN, current department) to rollback_[timestamp].csv.
Exit if this file cannot be written.
PHASE 3 — DRY RUN (default mode): print the full change list
(UPN: old -> new) and a count summary. Make no changes unless
-Execute is explicitly passed.
PHASE 4 — EXECUTE: only with -Execute; per-row try/catch, failures
logged and skipped, final summary (changed / skipped / failed).
Also produce: Undo-BulkChange.ps1 that replays rollback_*.csv.
Validate the CSV — trust nothing from a spreadsheet. Run phase 1 alone first. The failures it should catch loudly:
VALIDATION FAILED — 3 issues, no changes made:
Row 14: UPN "j.smith@corp .com" contains whitespace
Row 89: UPN not found in tenant: "mwilliams@corp.com"
Row 90/91: duplicate UPN "achen@corp.com" with different values
Report: validation_20260806_0912.csv
Send the report back to the CSV's author; do not "fix a few rows yourself" — that makes you the owner of their data quality forever.
Confirm the rollback file exists and is sane. Open it. Row count matches valid input rows; prior values look plausible (a column of blanks may itself be correct — but know that before, not after). This file is the operation's insurance policy; it is written even if you never execute.
Read the dry run like it is the change. The dry-run output is your last cheap exit. Check the count first ("did I expect 312?"), then scan for the surprising: VIP accounts, service accounts, values changing that should be no-ops. Ten minutes here is the whole discipline.
Execute in a pilot slice, verify, then full run. -Execute against the first 10 rows (or one department), verify in the admin console — the actual console, not your script's own success message — then run the remainder. Keep the per-row log.
Verify the end state independently. Re-query the platform for all affected objects and diff against intended state:
Import-Csv .\input.csv | ForEach-Object {
$u = Get-MgUser -UserId $_.UserPrincipalName -Property Department
if ($u.Department -ne $_.NewDepartment) {
"{0}: expected {1}, got {2}" -f $_.UserPrincipalName,
$_.NewDepartment, $u.Department } }
Zero output is the goal; every line is a follow-up.
Test the rollback before you need it. In the pilot phase, actually run Undo-BulkChange.ps1 against one object and confirm restoration. An untested rollback script is a hope, not a control. Then file everything — input CSV, validation report, rollback file, dry-run output, execution log — with the change record.
-WhatIf gives you phase 3 nearly free, and rollback capture uses Get-ADUser -Properties on every target attribute you plan to touch.Bulk-operation CSVs are PII by nature — names, UPNs, departments, sometimes term dates; store them and the rollback files in the change record's restricted location, not your desktop, and strip real identifiers before pasting samples into an external assistant while building the wrapper.
Validate loudly, dry-run with your eyes open, and write the tested rollback before the first change — AI makes these three layers nearly free to build, which removes the last excuse for running bulk operations without them.