Proof · case studies

What would you hand me on day one?

Choose the situation closest to yours. You get what I would do in the first week, and the case where I have done it before: the problem, what I built, what it proves, and what went wrong on the way. Client cases are anonymised; my own products are named.

Situations and week-one plans

Mail goes missing between on-premises and cloud

What I would do in week one: Message trace and headers for the affected paths, a list of connectors and accepted domains, protocol logging switched on. By the end of the week: the first finding with evidence, and no change made blindly.

Cause proven, not guessed One connector that took precedence plus one outdated accepted domain; routing then corrected in three phases, each with backup and restore.

The case behind it: Exchange hybrid, fixed and then switched off

We must prove our Microsoft 365 settings to an auditor

What I would do in week one: Agree scope and target values, collect read-only by script with reader roles, and deliver a first findings list with target, actual, rating and measure, plus the raw data with timestamps.

Same check, next year Fixed check IDs with target, actual, rating and measure, raw data with timestamps.

The case behind it: Evidence instead of screenshots

Conditional Access scares us

What I would do in week one: Check that the break-glass accounts really work (role, second factor, excluded everywhere, alert), export every existing policy as JSON, and put new policies into report-only mode while reading the sign-in logs.

Report-only by design No code path creates an enforced policy. Enabling is a separate, explicit step.

The case behind it: Conditional Access without lockouts

Autopilot takes hours

What I would do in week one: Measure provisioning time, list the blocking apps on the Enrollment Status Page, check detection rules and assignment timing, and read the logs of one stuck device.

~3 h → < 45 min Windows Autopilot provisioning time after removing blocking app assignments and dependencies.

The case behind it: Autopilot that finishes

Our PDFs must be accessible

What I would do in week one: Check a representative sample against PDF/UA and WCAG like veraPDF and PAC do, sort the findings into automatically repairable and needs-the-source, and run a pilot batch with a report.

241,880 → 31 veraPDF errors in one run on a 1,181-page municipal budget, then fully green in veraPDF and PAC after new font rules.

The case behind it: DokAudit: accessible PDFs with AI, proven

Someone sends mail in our name

What I would do in week one: Publish DMARC with reporting if it is missing, start the sender inventory from the aggregate reports, and put parked domains on v=spf1 -all and p=reject straight away.

p=none → p=reject Three undocumented systems found sending in the domain's name, fixed one by one before enforcement.

The case behind it: DMARC to p=reject

We run many tenants and they drift

What I would do in week one: Write the baseline down as one versioned file, connect the tenants read-only first, and start a daily evidence collection so changes are kept beyond Microsoft's log retention.

0 certificates on the runner Semaphore jobs exchange a ticket for a short-lived app-only token. The tenant certificate never leaves the API.

The case behind it: M365 Control Plane

We want AI to touch production, safely

What I would do in week one: List what the AI should be able to do, turn each item into a scoped tool with its own switch that starts off, log every call, and decide which actions need a person's approval.

Every switch starts off MCP and AI write access are enabled per tenant by a person, and every call is logged.

The case behind it: AI that proposes, a human who approves

Microsoft Graph · automation · MSP

M365 Control Plane

An MSP runs many Microsoft 365 tenants. Each one drifts, Microsoft deletes the logs after weeks, and every script that holds a tenant certificate is one more place where it can leak.

0 certificates on the runnerSemaphore jobs exchange a ticket for a short-lived app-only token. The tenant certificate never leaves the API.

Problem
  • Same baseline needed in every tenant, applied the same way
  • Entra logs kept 30 days (7 without P1/P2), Unified Audit Log 180 days
  • Automation needs tenant access without spreading credentials
What I built
  • Baseline as code, Overview, Changes, Risks and Automations for many tenants
  • Evidence 3.0: deduplicated changes and hash-chained snapshots, archived daily
  • A runner broker: PowerShell 7 jobs in Semaphore get short-lived tokens, never a certificate
What it proves
  • Microsoft Graph and app registrations at depth, certificates instead of secrets
  • Multi-tenant operations with drift detection and change evidence
  • Shipping to Docker and to Kubernetes with Argo CD

How a Semaphore job reaches a tenant without holding a certificate

  1. Browser appSvelte. Admin picks tenant and template, sees jobs, changes and evidence.
  2. Control Plane APINode.js. Checks the tenant mode, issues a ticket bound to tenant, template and task.
  3. Semaphore runnerPowerShell 7 template receives one JSON envelope with the ticket and a callback URL.
  4. Microsoft 365 tenantMicrosoft Graph, Exchange Online, SharePoint of that tenant only.
Certificate + evidence storeTenant certificate never leaves the API container. Results land in the evidence archive.
Runner brokerInternal network only. Ticket in, short-lived app-only token out.
  1. The API refuses write actions for tenants connected in audit-only mode, before anything starts.
  2. It issues a random ticket, keeps only its SHA-256 hash in memory and starts the Semaphore template.
  3. The script calls the broker with the ticket and asks for graph, exchange or the tenant's own SharePoint host. Nothing else is accepted, and only from the internal network.
  4. The broker signs in with the tenant's existing app registration and returns a short-lived token.
  5. The script posts its result back; it is archived as evidence with template, task, action and requester.
  6. When the task ends, its ticket is revoked. The time limit (60 minutes by default) or a restart of the API invalidates it too.
Engineering notes

What I built, in detail

  • Designed and written by me, from PowerShell to the user interface, while working for a Swiss Microsoft MSP; started in February 2026, about 280 commits of mine. Svelte, Node.js and Express, PowerShell 7 in the container with the Exchange Online, Graph, Teams, PnP and Maester modules.
  • Baseline as one versioned JSON file: mail security, Conditional Access rings, Intune, tenant hardening, documented deviations from CIS, known break risks and a nine-step onboarding checklist. It changes through a reviewed commit, never through the UI.
  • Changes: deduplicated events with before/after values, affected users and a remediation proposal. Risks: one queue for failed Maester tests (CISA SCuBA, CIS Microsoft 365, EIDSCA, ORCA) and critical changes.
  • Evidence 3.0 on top of the untouched raw archive: deterministic event fingerprints, so overlapping collections never duplicate an event, append-only monthly logs, resource snapshots chained by SHA-256 content hashes.
  • Onboarding creates a single-tenant app registration, permissions, Entra roles and a certificate (no client secret) in one device-code sign-in. Tenants connected for an independent audit get a separate read-only app with Global Reader; every write is blocked on the server.
  • Two environments: Docker Compose deployed by a self-hosted runner on my server, and on Kubernetes a GitOps flow where CI builds the images, commits the new tag to the Helm values and Argo CD syncs it, with secrets from Vault.

Guardrails and decisions

  • Conditional Access policies are always created in report-only mode; enabling is a separate, explicit step.
  • The tool only manages objects in its own naming scheme. Existing objects are never renamed; after a naming change it searches all known patterns, so it never creates a second, empty break-glass exclusion group next to the real one.
  • AI and MCP write access is a per-tenant switch that is off by default.
  • Jobs move to Semaphore one type at a time (strangler pattern), the local path stays as fallback.
  • Risk scoring runs on the server; heuristics never claim a compliance violation on their own.
  • Honest limit: the broker token carries the permissions of the tenant's app, the job's action label is not enforced at token level. Protection comes from who may start which template, the short lifetime and the log.
  • Where the tool reads a third-party database it may not write to, read-only is enforced four times: connection option, read-only transaction, a wrapping query with a row limit, and a statement filter.

The application is behind a login and holds tenant data, so there are no screenshots. I am happy to demo it with a test tenant.

Own product · AI · accessibility

DokAudit: accessible PDFs with AI, proven

Public bodies and companies publish thousands of PDFs that have to work with a screen reader, and most of them fail on structure, fonts and tables. Fixing them by hand does not scale, and AI alone gets tables wrong.

241,880 → 31veraPDF errors in one run on a 1,181-page municipal budget, then fully green in veraPDF and PAC after new font rules.

Problem
  • Accessibility rules (PDF/UA, WCAG, EN 301 549) and documents that fail them by the thousand
  • Checks only count if veraPDF and PAC both come back green
  • Large language models are good at text and unreliable with table cells
What I built
  • A SaaS that checks like veraPDF and PAC and repairs tagging, headings, lists, tables, fonts, form tooltips, links and artifacts
  • A local layout model for structure, an LLM only for uncertain pages, every result cross-checked against the page image
  • An own worker fleet with GPU, a cost limit per page and a learning system with a cross-check gate
What it proves
  • Building and running a product end to end, on my own initiative
  • Using AI where it measurably helps, and checking it where it does not
  • Engineering for large inputs: budgets, guards and measurable results

How a PDF goes through DokAudit

  1. PDF inSingle file, batch or a whole website
  2. CheckLike veraPDF and PAC: PDF/UA, WCAG
  3. Layout modelLocal (Docling/Heron) recognises structure
  4. LLM, only if unsureClaude for uncertain pages, within a cost limit
  5. Cross-checkResult compared with the page image
  6. RepairTags, fonts, forms, links, artifacts
  7. ReportRe-checked until green, documented
  • What went wrong: tables produced by the LLM looked right but were wrong in content, with numbers in the wrong cell. What I changed: a local layout model recognises the structure, the LLM only steps in on uncertain pages, and its results are checked against the page image.
  • What went wrong: a large learning run together with one huge PDF (8.7 GB of RAM) made the platform hang. What I changed: a RAM guard, and learning runs only with a budget and a lock.
Engineering notes

Architecture and numbers

  • Structure recognition with a local layout model (Docling with the Heron layout model). Measured correct structure per character rose from 63.1% to 95.5% with it.
  • The LLM (Claude) is only called for pages the layout model is unsure about, and every result is compared with the rendered page image before it is used.
  • Own worker fleet: two server containers and a GPU PC with an RTX 3070 Ti, about 1.8 seconds per page. A dispatcher works on the pull principle: workers fetch jobs, nothing pushes to them.
  • A cost limit per page keeps LLM use predictable.
  • Learning system: rules learned on one document only become global after they pass a cross-check.

Product facts

  • Live on dokaudit.com (English and French) and dokaudit.de; the app itself is mostly German.
  • Automatic repair: structure tagging, headings, lists, tables; fonts (embedding, ToUnicode mapping, widths); form field tooltips, links, artifacts; optionally colour contrast.
  • The 1,181-page example is a city's budget plan in Germany, anonymised here: in one run the veraPDF errors fell from 241,880 to 31; after new font rules the document was fully green in veraPDF and PAC.
  • The European Accessibility Act has applied since 28 June 2025 to products and services placed on the EU market, such as e-commerce, banking services and e-books. That can matter for companies outside the EU that sell there too (AccessibleEU).

Article: making 1,000-page PDFs accessible with AI

Exchange · mail flow

Exchange hybrid, fixed and then switched off

After a partial migration, mail between on-premises and cloud mailboxes went missing, sporadically and not reproducibly, and the last Exchange server could not be switched off because nobody knew what still depended on it.

Cause proven, not guessedOne connector that took precedence plus one outdated accepted domain; routing then corrected in three phases, each with backup and restore.

Problem
  • Sporadic mail loss between on-premises and cloud
  • Wrong target and proxy addresses in a hybrid setup
  • Scanners and applications sending with passwords and MFA exceptions
What I did
  • Traced the cause in message trace and connector configuration, documented it, wrote a runbook
  • Corrected routing by script: pilot, cloud-only mailboxes, everyone, each with backup and restore
  • Moved SMTP relay to Microsoft Graph with a certificate, scoped to the sending mailboxes
What it proves
  • Mail flow at the level of connectors, accepted domains and headers
  • Bulk changes that can be rolled back
  • Removing legacy authentication without breaking devices
Engineering notes

Retiring the last server

  • Prerequisites: no on-premises mailboxes, no relay, no hybrid features needed.
  • Every sender inventoried from protocol and message tracking logs, relays moved, hybrid and DNS cleaned up, then switched off.
  • Since Exchange 2019 CU12, recipients can be managed with the Exchange Management Tools without a running server.

Relay without passwords

  • App registration with a certificate, Mail.Send granted through RBAC for Applications and limited to a management scope.
  • No parallel tenant-wide grant in Entra ID, which would override the scope.

Article: decommissioning the last Exchange server

Email authentication

DMARC to p=reject

A domain had to be protected against spoofing, but every step towards enforcement could block a legitimate sender nobody remembered.

p=none → p=rejectThree undocumented systems found sending in the domain's name, fixed one by one before enforcement.

Problem
  • Unknown senders without SPF or DKIM alignment
  • Fear of losing invoices and newsletters
What I built
  • DMARC Geeks: report collection by IMAP, upload or API, multi-tenant
  • An advisor that says when quarantine or reject is safe
  • DNS check, mail tester and a Microsoft 365 threat test
What it proves
  • SPF, DKIM and DMARC alignment in depth
  • Enforcement with every legitimate sender authenticated
  • Building and running a multi-tenant SaaS (FastAPI, PostgreSQL)
Engineering notes
  • Parses XML, .gz and .zip reports from Google, Microsoft and Yahoo; strict data separation per tenant, several domains per tenant with DNS verification.
  • API keys shown once, webhooks signed with HMAC-SHA256, audit log, rate limiting.

Entra ID · identity

Conditional Access without lockouts

After policies were tightened, partner companies could no longer reach shared Teams and SharePoint sites, and a "filled" break-glass group turned out to hold an account that could not have repaired anything.

Report-only by designNo code path creates an enforced policy. Enabling is a separate, explicit step.

Problem
  • B2B guests locked out by policies without guest targeting
  • Conditional Access can lock out a whole tenant
What I built
  • Policy sets for three licence levels, always deployed report-only, four protection groups excluded
  • A four-point break-glass check: enabled, a role that can repair, a second factor, excluded from every policy
  • Guest policies redesigned with a test plan and emergency access
What it proves
  • Phased rollout from report-only to enforced
  • Thinking in failure modes
  • Turning a near miss into a permanent check
  • What went wrong: the tool reported the break-glass group as filled. The account in it was excluded from every policy, but had neither a directory role nor a second factor. What I changed: the check now tests whether the account could actually repair the tenant, and warns before any policy is enabled.
Engineering notes
  • Policy sets based on Alex Filipin's open-source Conditional Access framework.
  • State templates copy which policies are enforced from a reference tenant, but never create or delete a policy; only policies in the tool's own naming scheme are touched.
  • Microsoft-managed policies that appear later do not know the own exclusion groups; the break-glass check covers them too.

Exchange Online Protection · encryption

Mail filtering and encryption on one mail path

Default quarantine rules nobody understands, legacy spam filter switches that produce false positives behind encryption gateways, and encryption that depends on users ticking a box.

Tested, not assumedHarmless EICAR and GTUBE test strings show what Microsoft 365 actually delivers, junks or quarantines.

Problem
  • Unclear quarantine rights and release logic
  • SPF hard fails for mail passing an encryption gateway
  • Encrypted mail the filter cannot read
What I built
  • A mail security baseline deployed app-only and idempotently
  • Two quarantine policies for two risk levels; legacy filter options off
  • A target/actual comparison and a threat test in DMARC Geeks
What it proves
  • EOP and Defender policies at parameter level
  • Understanding the whole path: gateway, encryption, filter, archive
Engineering notes
  • Anti-phishing with spoof intelligence and honouring DMARC, anti-spam, anti-malware with zero-hour auto purge.
  • Self-release for spam and bulk; request-release with admin control for high-confidence phishing and malware.
  • Encryption design: TLS enforced per partner domain with MTA-STS and TLS reports; S/MIME and PGP at the gateway; portal delivery or Purview Message Encryption for recipients without certificates; inbound mail decrypted before filter and archive.

Article: MTA-STS and TLS-RPT

Compliance · audit

Evidence instead of screenshots

A regulated client in the Swiss financial sector had to prove its Microsoft 365 settings to the supervisor, and screenshots only prove what a portal showed on one day.

Same check, next yearFixed check IDs with target, actual, rating and measure, raw data with timestamps.

Problem
  • Settings had to be proven to a supervisor
  • Results must be comparable from year to year
What I built
  • A script-based evidence kit with gap analysis and management summary
  • A read-only review in six areas: identity, data location, sharing, retention, employee data, email
  • Collection with reader roles, no access to mail, chat or document content
What it proves
  • Translating regulation into checkable settings
  • Read-only collection with the smallest roles that work
Engineering notes
  • Microsoft Graph and Exchange Online PowerShell under Global Reader and Security Reader.
  • Raw data with timestamps stays with the client for next year's comparison.

Backup · restore

Backups that have been restored

Microsoft protects the service, not your data against deletion or encryption by someone with valid rights, and many backups have never been restored.

Restore never overwritesThe Intune restore only creates new policies with a [Restored] prefix and no assignments.

Problem
  • Built-in recovery windows of 14 to 93 days
  • Configuration is not covered by retention at all
What I built
  • An operating model for Microsoft 365 backup with logged restore tests
  • An app-only Intune configuration backup with non-destructive restore
What it proves
  • Precise knowledge of retention limits
  • Restore paths that cannot make things worse
Engineering notes
  • Switching products with a parallel run and a plan for the old backups; restore tests logged with date, result and duration.
  • Settings types that cannot be restored reliably are left out of the Intune backup on purpose, instead of offering false safety.

Intune · Autopilot

Autopilot that finishes

Windows Autopilot stalled on about 40% of devices: the Enrollment Status Page ran into timeouts and devices had to be finished by hand.

~3 h → < 45 minProvisioning time after removing blocking app assignments and dependencies.

Problem
  • Timeouts on the Enrollment Status Page
  • Users had to move from AD-joined to Entra ID-joined devices
What I did
  • Removed blocking app assignments and dependencies that slowed each other down
  • Profile migration by script with pre-checks and three phases that run on their own
  • Printer inventory per device rebuilt as Intune configuration
What it proves
  • Intune and Autopilot troubleshooting beyond the portal
  • Measurable improvement
Engineering notes

Infrastructure · DNS · mail

My own infrastructure, run like production

Products need hosting, TLS, DNS, mail and deployments, and the deployment server should not be reachable from the internet.

git push → liveA runner inside the network pulls deploy jobs, so the server needs no inbound SSH.

What I built
  • Proxmox with containers per application, reverse proxy with Let's Encrypt
  • DNS managed through the provider's API; my own mail server with SPF, DKIM and DMARC
  • This site: strict Content Security Policy, no inline script or style
What it proves
  • Linux, Docker, reverse proxies, TLS and DNS, hands-on
  • Running mail infrastructure, not just configuring Exchange Online
  • CI/CD that respects network boundaries

AI · MCP · approval

AI that proposes, a human who approves

An AI assistant that can change a tenant or a server needs the controls of an administrator, and more: no invented rules, no secrets, no action where nobody allowed it.

Every switch starts offMCP and AI write access are enabled per tenant by a person, and every call is logged.

What I built
  • An MCP endpoint with hashed API keys, a per-tenant permission matrix and an audit log
  • A ticket copilot that gets server-prepared context, never tenant or certificate access
  • MCP tools for my own server where secrets are referenced by placeholder
What it proves
  • Practical work with AI agents and the Model Context Protocol
  • Least privilege for machines, not just people
Engineering notes
  • The baseline is readable over MCP, so an AI advises "according to baseline vX.Y" instead of inventing rules.
  • In DokAudit, AI suggests alternative texts and a person confirms each one.

Don't take my word for it

Verify it yourself

A few things on this page you can check in a minute, without asking me.

  • Security headers of this website

    Strict Content Security Policy without unsafe-inline, no inline scripts or styles, HSTS, frame and referrer policies.

    Check on securityheaders.com
  • My CV as an accessible PDF

    Rendered from this site and run through DokAudit: veraPDF PDF/UA-1 passed, no findings in the accessibility checks. Open it in PAC or veraPDF.

    Download the CV (PDF)
  • DMARC on my own domains

    dmarc-geeks.ch publishes p=reject and SPF with -all. dokaudit.com sends no mail and is locked down the way I recommend for parked domains: v=spf1 -all and p=reject.

    dmarc-geeks.ch dokaudit.com
  • DokAudit on a real website

    Enter a website address and DokAudit checks the linked PDFs against PDF/UA and WCAG, without registration. The scan page is in German.

    dokaudit.com/scan

At a glance

Which case proves which skill

Which case demonstrates which skill
CaseExchangeIdentityIntuneSecurityGraph & automationAIInfrastructure
M365 Control Planeyesyesyesyesyesyesyes
DokAudit: accessible PDFs with AI, provennononoyesyesyesyes
Exchange hybrid, fixed and then switched offyesyesnonoyesnono
DMARC to p=rejectyesnonoyesnonoyes
Conditional Access without lockoutsnoyesnoyesyesnono
Mail filtering and encryption on one mail pathyesnonoyesyesnono
Evidence instead of screenshotsyesyesnoyesyesnono
Backups that have been restoredyesnoyesnoyesnono
Autopilot that finishesnoyesyesnoyesnono
My own infrastructure, run like productionnononoyesyesnoyes
AI that proposes, a human who approvesnononoyesyesyesyes

Which problem would you hand me first?

Tell me the situation. I will tell you what I would do in week one, and show you the code, the runbook or the evidence behind the matching case.