Case study · Retail, ~600,000 users

A Microsoft-to-Google migration for 600,000 users

The migration itself was the visible part. The work that decided whether it succeeded was the provisioning, reconciliation and audit tooling around it.

The situation

Several business units, one directory

Roughly 600,000 users across retail brands, each with its own stakeholders.

The migration from Microsoft to Google Workspace was already running when I joined. The directory move was one problem; the other was everything that had to happen around it. Every new user, group, shared drive and site needed to be created, attributed and audited consistently, and every one of those steps had been manual up to that point.

Requirements came from several directions at once: product and platform teams, a facilities division, an external integrator, and the business units themselves. Exceptions had been handled by email, which meant nobody could say afterwards who had approved what.

What I built

Tooling that made the migration repeatable

Six pieces of work, all of them in production before the handover.

  • A Pulumi provider for Google Drive, Sites and Groups, covering search, permissions, labels and memberships, deployed through Pulumi in Docker.
  • A Go service for the GWS API that processed 160,000 users in six minutes, with PostgreSQL persistence, a River job queue, workforce IDs and history records.
  • Sites and Drive provisioning with permission management, BigQuery reconciliation and audit logs, so a failed run could be compared against the directory instead of guessed at.
  • A read-only exception self-service application with a REST backend, MyAPI integration, Entra ID lookup, a Prometheus exporter, cyclic checks and backups.
  • An event-driven audit-log path from Google Workspace into BigQuery, plus a SIAM-to-BigQuery pipeline and bulk imports from Sheets through JSONL.
  • Architecture decision records and knowledge transfer sessions on Pulumi, the backend and the Sites tooling, so the internal teams could take the work over.

What changed

Repeatable instead of heroic

  • Provisioning became repeatable: adding a business unit meant a configuration change, not a new script.
  • Reconciliation against BigQuery caught drift between the directory, Drive and Sites before it reached users.
  • Exceptions had a written process and a self-service path, instead of an email queue.
  • The migration continued after the engagement with the internal teams running it.

Stack

What it runs on

Go · Pulumi (Go) · Google Cloud: BigQuery, Pub/Sub, Cloud Functions, Cloud Storage, GKE · PostgreSQL and River · Terraform · Entra ID · OpenAPI

Platform and cloud modernization

Start the conversation

Running something similar?

A short note with the environment, the constraint and the timing is enough for me to say whether this is a fit.