Issue #004March 9, 2026·🛡️ Security Automation

Automate Intune Baselines
Across All Clients With CIPP

If you're managing Intune for 20+ tenants, you already know the pain: every new client means clicking through CIPP to apply baselines one by one, test groups have to be created manually, and you have no systematic way to verify which tenants are actually compliant. Here's how to fix all of that with OpenIntuneBaselines, CIPP Standards, and a single n8n workflow.

TL;DR

  • OpenIntuneBaselines gives you Low/Medium/High pre-built Intune policy sets — importable directly into CIPP
  • CIPP Standards can apply those baselines to all tenants via API — no manual clicking per tenant
  • n8n workflow below: trigger from webhook → fetch tenant list → apply baseline per tenant → Slack/Teams summary report
  • Test groups are the secret — always stage in a pilot group first; the workflow handles this automatically
  • • Full n8n JSON at the bottom — import and configure in 20 minutes

The Problem With Manual Intune Baseline Deployment

A typical 30-tenant MSP deploying Intune baselines manually looks like this: open CIPP, select tenant, navigate to Standards, apply policies, create a pilot group, wait for sync, verify, move to broad deployment. Multiply by 30. That's a half-day of work — and it's almost never done consistently across all clients because it's soul-crushing.

The result: your "standard build" is actually 30 slightly different builds, each applied at different times, with no audit trail. When a client gets hit by ransomware and the incident report asks what endpoint policies were in place, you're scrolling through CIPP per-tenant hoping you applied that baseline 8 months ago.

OpenIntuneBaselines solves the policy content problem. CIPP solves the multi-tenant delivery problem. n8n ties them together and adds the audit trail, staging logic, and notification layer you need to actually run this at scale.

Step 1: Set Up OpenIntuneBaselines

OpenIntuneBaseline (from the community, maintained by SkipToTheEndpoint) is a set of JSON exports you can import directly into Intune or CIPP. It ships in three tiers:

Low

Minimum viable posture. Good for SMBs that resist change. Covers BitLocker, Defender AV baseline, and basic Windows Update rings.

Medium

Recommended for most MSP clients. Adds Firewall rules, LAPS, Account Protection, Attack Surface Reduction rules.

High

Healthcare / finance tier. Full CIS Level 2, App Control (WDAC), Credential Guard, strict browser policy.

Download the release ZIP from GitHub. You'll get a folder structure like:

OpenIntuneBaseline/
├── Low/
│   ├── Configuration Profiles/
│   ├── Compliance Policies/
│   └── Windows Update Rings/
├── Medium/
│   └── (same structure, more policies)
└── High/
    └── (same structure, strictest policies)

Each policy is a JSON file importable via CIPP or directly via the Intune Graph API. You don't need to understand every setting — the project is well-documented and community-vetted. Choose your tier per client and import.

Note: Recommended starting point: deploy Medium to all clients via a test group first. Upgrade specific clients to High based on compliance requirements (HIPAA, SOC2). Keep Low available for legacy clients that can't absorb breaking changes yet.

Step 2: Import Baselines Into CIPP

CIPP (Cloud Identity Partner Portal) has a Standards feature that lets you define a policy template and apply it to one or all tenants simultaneously. This is where OpenIntuneBaselines + CIPP becomes powerful — you define the template once, then push it everywhere.

Import the baseline policies into your CIPP instance:

  1. In CIPP → go to Endpoint Management → Configuration Policies
  2. Click Add Policy → Import from JSON
  3. Paste in each JSON file from OpenIntuneBaseline (do this for each policy in your chosen tier)
  4. Save as a named template (e.g. MSP-Standard-Medium-v1)

Set up a CIPP Standard for cross-tenant deployment:

  1. In CIPP → Tenant Administration → Standards
  2. Click Add Standard → Intune → Configuration Policies
  3. Select your imported template
  4. Set scope: Pilot Group first (see below), then All Devices
  5. Enable Run daily → CIPP will continuously enforce the standard, auto-remediate drift

The "Run daily" toggle is the key insight most MSPs miss. This isn't a one-time push — it's continuous enforcement. If someone manually changes a policy in a tenant, CIPP will revert it to the standard on the next daily run. That's configuration drift protection built in.

Step 3: Always Stage With a Pilot Group

This is the step most MSPs skip and then regret. Intune baseline policies can break things — specific line-of-business apps, legacy hardware drivers, or custom browser configurations. Deploying directly to all devices in a client tenant without staging is how you get an emergency call on a Tuesday morning.

Create a pilot group structure in each tenant:

# Target group names (create these in each tenant via CIPP or Graph API)
MSP-Intune-Pilot          # 2-3 IT-savvy users willing to take risk
MSP-Intune-Broad          # Remaining staff after 7-day pilot passes
MSP-Intune-Exclude        # Kiosks, service accounts, shared devices — never in scope

Apply the CIPP Standard to MSP-Intune-Pilot first. Wait 7 days. If no complaints, update the Standard scope to MSP-Intune-Broad. The n8n workflow below automates this handoff — it logs pilot start time and sends a Slack reminder to check pilot status before broad rollout.

Creating these groups manually across 30 tenants is also tedious. You can create them in bulk using the CIPP API:

POST https://your-cipp-instance.com/api/AddGroup
Authorization: Bearer {CIPP_API_TOKEN}
Content-Type: application/json

{
  "tenantFilter": "client-tenant.onmicrosoft.com",
  "displayName": "MSP-Intune-Pilot",
  "groupType": "Security",
  "mailNickname": "MSP-Intune-Pilot",
  "membershipType": "Assigned"
}

Step 4: The n8n Automation Workflow

Here's where it comes together. This n8n workflow does the following when triggered:

  1. Fetches all active tenants from the CIPP API
  2. For each tenant: creates MSP-Intune-Pilot and MSP-Intune-Broad groups if they don't exist
  3. Applies the CIPP Standard (your baseline template) scoped to the Pilot group
  4. Logs the pilot start timestamp to a Google Sheet
  5. Posts a Slack summary: tenants processed, any errors, pilot timer set
  6. Sets a 7-day follow-up reminder to review pilot status before broad rollout

n8n Workflow: CIPP Intune Baseline Deployer

{
  "name": "CIPP Intune Baseline Deployer",
  "nodes": [
    {
      "id": "webhook-trigger",
      "name": "Webhook — Trigger",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "path": "cipp-baseline-deploy",
        "httpMethod": "POST",
        "responseMode": "lastNode"
      }
    },
    {
      "id": "set-config",
      "name": "Set Config",
      "type": "n8n-nodes-base.set",
      "parameters": {
        "values": {
          "string": [
            { "name": "cipp_base_url", "value": "{{ $env.CIPP_BASE_URL }}" },
            { "name": "cipp_token", "value": "{{ $env.CIPP_API_TOKEN }}" },
            { "name": "baseline_standard_name", "value": "{{ $json.body.standard_name || 'MSP-Standard-Medium-v1' }}" },
            { "name": "slack_channel", "value": "{{ $json.body.slack_channel || '#intune-ops' }}" }
          ]
        }
      }
    },
    {
      "id": "get-tenants",
      "name": "CIPP — Get All Tenants",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "GET",
        "url": "={{ $node['Set Config'].json.cipp_base_url }}/api/ListTenants",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Authorization", "value": "=Bearer {{ $node['Set Config'].json.cipp_token }}" }
          ]
        }
      }
    },
    {
      "id": "split-tenants",
      "name": "Split Into Tenants",
      "type": "n8n-nodes-base.splitInBatches",
      "parameters": { "batchSize": 1 }
    },
    {
      "id": "create-pilot-group",
      "name": "CIPP — Create Pilot Group",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "POST",
        "url": "={{ $node['Set Config'].json.cipp_base_url }}/api/AddGroup",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth",
        "sendBody": true,
        "bodyContentType": "json",
        "jsonBody": "={
  "tenantFilter": "{{ $json.defaultDomainName }}",
  "displayName": "MSP-Intune-Pilot",
  "groupType": "Security",
  "mailNickname": "MSP-Intune-Pilot",
  "membershipType": "Assigned"
}"
      }
    },
    {
      "id": "apply-standard",
      "name": "CIPP — Apply Standard to Pilot",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "POST",
        "url": "={{ $node['Set Config'].json.cipp_base_url }}/api/AddStandardsDeploy",
        "sendBody": true,
        "bodyContentType": "json",
        "jsonBody": "={
  "tenantFilter": "{{ $json.defaultDomainName }}",
  "standardName": "{{ $node['Set Config'].json.baseline_standard_name }}",
  "assignmentTarget": "MSP-Intune-Pilot",
  "runDaily": true
}"
      }
    },
    {
      "id": "log-to-sheet",
      "name": "Google Sheets — Log Pilot Start",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "{{ $env.BASELINE_LOG_SHEET_ID }}",
        "sheetName": "DeploymentLog",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "Tenant": "={{ $json.defaultDomainName }}",
            "Standard": "={{ $node['Set Config'].json.baseline_standard_name }}",
            "PilotStartDate": "={{ $now.toISO() }}",
            "BroadRolloutDue": "={{ $now.plus({ days: 7 }).toISO() }}",
            "Status": "Pilot Started"
          }
        }
      }
    },
    {
      "id": "aggregate-results",
      "name": "Aggregate Results",
      "type": "n8n-nodes-base.aggregate",
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "destinationFieldName": "tenants"
      }
    },
    {
      "id": "slack-summary",
      "name": "Slack — Send Summary",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "resource": "message",
        "operation": "post",
        "channel": "={{ $node['Set Config'].json.slack_channel }}",
        "text": "=🛡️ *Intune Baseline Deployment Complete*

*Standard applied:* {{ $node['Set Config'].json.baseline_standard_name }}
*Tenants processed:* {{ $json.tenants.length }}
*Scope:* MSP-Intune-Pilot group
*Broad rollout window:* 7 days from today

✅ Pilot phase active. Review results in 7 days before expanding to MSP-Intune-Broad.

_Deployment log: <https://docs.google.com/spreadsheets/d/{{ $env.BASELINE_LOG_SHEET_ID }}|Open Sheet>_"
      }
    },
    {
      "id": "schedule-followup",
      "name": "HTTP — Schedule Follow-Up",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "method": "POST",
        "url": "={{ $env.N8N_WEBHOOK_BASE_URL }}/webhook/baseline-followup-reminder",
        "sendBody": true,
        "bodyContentType": "json",
        "jsonBody": "={
  "message": "7-day Intune Pilot Review Due: Check MSP-Intune-Pilot in all tenants before broad rollout.",
  "run_at": "{{ $now.plus({ days: 7 }).toISO() }}",
  "channel": "{{ $node['Set Config'].json.slack_channel }}"
}"
      }
    }
  ],
  "connections": {
    "Webhook — Trigger": { "main": [["Set Config"]] },
    "Set Config": { "main": [["CIPP — Get All Tenants"]] },
    "CIPP — Get All Tenants": { "main": [["Split Into Tenants"]] },
    "Split Into Tenants": { "main": [["CIPP — Create Pilot Group"]] },
    "CIPP — Create Pilot Group": { "main": [["CIPP — Apply Standard to Pilot"]] },
    "CIPP — Apply Standard to Pilot": { "main": [["Google Sheets — Log Pilot Start"]] },
    "Google Sheets — Log Pilot Start": { "main": [["Aggregate Results"]] },
    "Aggregate Results": { "main": [["Slack — Send Summary"]] },
    "Slack — Send Summary": { "main": [["HTTP — Schedule Follow-Up"]] }
  }
}

Environment variables required:

CIPP_BASE_URL=https://your-cipp-instance.azurewebsites.net
CIPP_API_TOKEN=your-cipp-bearer-token
BASELINE_LOG_SHEET_ID=your-google-sheet-id
N8N_WEBHOOK_BASE_URL=https://your-n8n-instance.com

Step 5: Broad Rollout After Pilot Clears

After 7 days with no incidents from the pilot group, update the CIPP Standard scope from MSP-Intune-Pilot to MSP-Intune-Broad. You can do this in bulk via the API (same endpoint as above, just change the assignmentTarget), or build a second n8n workflow triggered from the Google Sheet when the "Status" column is updated to "Pilot OK."

The Google Sheet becomes your deployment tracker. Sort by BroadRolloutDue column every Monday morning. Update Status to Pilot OK → a Watch trigger on the Sheet fires the broad-rollout workflow automatically.

What you end up with:

  • ✅ All new clients get baselines applied on day 1, via webhook from your onboarding workflow
  • ✅ Existing clients get consistent policy — no more per-tenant drift
  • ✅ 7-day pilot stage catches app compatibility issues before they hit everyone
  • ✅ Google Sheet audit trail: who got what baseline and when
  • ✅ CIPP's daily re-enforcement prevents manual config drift
  • ✅ Slack summary each time you run — full visibility without logging into CIPP per tenant

Getting CIPP API Access

CIPP exposes a REST API backed by Azure Function keys. To get your CIPP_API_TOKEN:

  1. Open your CIPP deployment in Azure Portal → Function App
  2. Go to Functions → CIPPcore → Function Keys
  3. Copy the default key — this is your bearer token
  4. Test: curl -H "Authorization: Bearer YOUR_KEY" https://your-cipp.azurewebsites.net/api/ListTenants
Note: CIPP's API surface is evolving — some endpoints (like AddStandardsDeploy) may not be in older self-hosted builds. Check your CIPP version and the CIPP GitHub for the current API reference. The community-hosted CIPP-API repo documents all available endpoints.

Practical Tips From the Field

Start with one client, not all of them

Run the workflow against a single low-risk tenant first. Verify the group was created, the Standard applied, the Sheet logged. Only after a clean first run should you kick it off against all tenants. The Split Into Tenants node runs sequentially — if one tenant fails (API timeout, missing permissions), the rest still process.

Handle the "group already exists" error gracefully

The AddGroup call will fail with a 409 if MSP-Intune-Pilot already exists. Add a Continue On Fail toggle on that node in n8n — or add an IF node to check the response code and skip the group creation step. The Standard application will still succeed even if the group creation is skipped.

Tag the Standard version in your policy names

Use names like MSP-Standard-Medium-v1-2026Q1 instead of just MSP-Standard. When OpenIntuneBaseline releases an update (they do quarterly), you create a new Standard version, run the workflow again pointing to the new standard name, and you have a clean migration path. Old versions remain in CIPP as historical reference.

Wire into your onboarding workflow

Add a webhook call to this workflow from your new client onboarding flow (the 04-new-client-onboarding.json workflow in the MSP Easy pack does this). Pass the tenant's defaultDomainName in the body. Now every new client gets Intune baselines applied automatically within hours of going live in CIPP — no engineer action required.

What This Actually Takes to Set Up

30 minDownload + review OpenIntuneBaseline
45 minImport policies into CIPP + create Standard template
20 minImport n8n workflow + configure env vars
15 minTest run against 1 pilot tenant
5 min (automated)Full rollout across all tenants

Total: roughly 2 hours of setup, then zero manual work per tenant going forward. For a 30-tenant MSP, you're replacing 10–15 hours of manual CIPP clicking with a one-time setup and a webhook call. The ongoing value is in the audit trail, drift detection, and automatic enforcement — every new tenant gets the same baseline in minutes instead of days.

Want All 12 MSP Automation Workflows?

The n8n Workflow Starter Pack includes the CIPP Intune Baseline Deployer above, plus client onboarding, QBR prep, security alert escalation, patch compliance monitoring, and 8 more — all ready to import.

See the Workflow Pack →

Or subscribe free — next issue covers n8n in 2026 after the tunnel deprecation.