Skip to content
Last updated

Microsoft Intune Distribution

Deploy Capsule Security hooks for AI coding assistants across your fleet using Microsoft Intune. Capsule supports two paths:

  • Automated (recommended) — Connect Intune as a Capsule integration. Capsule pushes and reconciles remediation scripts in your Intune tenant on your behalf, scoped to the Microsoft Entra ID groups you choose.
  • Manual — Download a hooks.json / managed-settings.json from the Capsule portal and create the Intune remediation script package yourself, following the per-product steps later in this guide.

Both paths deploy the same configuration to the same locations on Windows devices. Use the automated path when you want changes to flow continuously (new hooks, rotated JWTs, group changes) without manual touch-ups in the Intune admin center.

Prerequisites

  • Access to the Microsoft Intune admin center (https://intune.microsoft.com)
  • A Capsule Security account with admin access
  • Target devices enrolled in Intune
  • For the automated path: a Microsoft Entra ID Global Administrator (or other identity allowed to grant tenant-wide admin consent)

Automated: Connect Intune as a Capsule integration

The Intune integration lets Capsule create, update, assign, and remove Intune remediation scripts (deviceManagementScripts) directly through Microsoft Graph, scoped to the Entra ID groups you select. Once connected, you create one Distribution per target product (Cursor, GitHub Copilot, Claude Code, Kiro, Windsurf, Cline, Codex), pick the target groups, and Capsule keeps the deployed script content in sync with the corresponding integration.

Capsule operates Intune through a dedicated multi-tenant Azure AD app registration owned by Capsule. You don't create an app in your tenant — you grant the Capsule app permission to act in yours.

  1. In the Capsule portal, navigate to Integrations and locate Microsoft Intune.
  2. Click Install. You are redirected to Microsoft's authorization endpoint (login.microsoftonline.com/organizations/oauth2/v2.0/authorize with prompt=consent) so you can grant tenant-wide consent on behalf of your organization.
  3. Sign in as an Entra ID admin authorized to grant tenant-wide consent and review the requested permissions.
  4. Approve the consent. Microsoft redirects back to Capsule (/integrations/callback/INTUNE) with an authorization code, which Capsule exchanges for your Microsoft tenant ID plus a refresh token. By default Capsule acquires app-only Graph tokens via the client_credentials grant; it keeps the refresh token only to act as the connecting admin when Multi-Admin Approval blocks an app-only write.

After consent, the Capsule app appears under Microsoft Entra admin center → Enterprise applications in your tenant. You can revoke access from there at any time, which immediately disables the integration.

Permissions

The Capsule Intune app requests the following Microsoft Graph permissions. Tenant-wide admin consent grants them for both application (app-only) and delegated use — Capsule writes to Graph app-only by default and only falls back to acting as the connecting admin (via the stored refresh token) when Multi-Admin Approval blocks an app-only write:

PermissionWhy it's needed
DeviceManagementScripts.ReadWrite.AllCreate, update, assign, and delete the remediation deviceManagementScripts that deploy Capsule hooks.
DeviceManagementConfiguration.ReadWrite.AllManage the device-management configuration surface those remediation scripts are created under.
DeviceManagementManagedDevices.ReadWrite.AllValidate the connection and read managed-device metadata for status checks.
Group.Read.AllResolve the Microsoft Entra ID groups you select so distributions can be assigned to them.

The consent screen also requests the standard openid and profile sign-in scopes plus offline_access, which is what lets Capsule obtain the refresh token used for the delegated Multi-Admin Approval fallback. Because consent is granted tenant-wide, there is no per-user sign-in cost and the integration keeps working as admins rotate.

Flow

Admin clicks Install ─▶ Microsoft admin-consent page ─▶ Admin approves

                                          tenant + state ◀────┘

                              Capsule acquires app-only Graph token

              Admin creates a Distribution (target product + Entra ID groups)

              Capsule POSTs deviceManagementScripts + /assign to Graph

                  Intune pushes the remediation script to assigned devices

Day-to-day reconciliation:

  • Distribution created → Capsule creates a deviceManagementScript in your tenant and assigns it to the selected Entra ID groups.
  • Distribution edited (groups changed, target integration updated, JWT rotated) → Capsule patches the existing script content and re-runs /assign so the deployed configuration always matches what's shown in the portal.
  • Distribution removed → Capsule deletes the deviceManagementScript from your tenant and unassigns it from all groups.
  • Connection revoked in Entra ID → Graph token acquisition fails; the integration moves to an error state in Capsule and stops issuing changes. Previously deployed scripts remain in your tenant until you remove them.

Scripts deployed by Capsule run under SYSTEM (for device-targeted products like Cursor and Claude Code) or in user context (for user-targeted products like GitHub Copilot, Kiro, Windsurf, Cline, and Codex, which write under %APPDATA% or %USERPROFILE%). Capsule chooses the correct context automatically per product.

Verification

After installing the integration and creating a Distribution:

  1. In the Capsule portal, open the Intune integration → Distributions tab and confirm the distribution status is Active.
  2. In the Intune admin center, navigate to Devices → Remediations and find the script package whose name starts with Capsule – . Open it to inspect the deployed content and group assignments.
  3. On an assigned device, verify the target product picks up the hook (see the per-product Verification sections below).

Manual: download and deploy hooks yourself

If you prefer to keep deployments under your own change-management process, follow the per-product steps below. The configuration content is identical to what the automated integration would push — only the delivery mechanism differs.


Cursor

Deploy the Cursor hooks configuration using Intune's Remediation feature.

Step 1: Download the Configuration

  1. Log in to the Capsule Security portal
  2. Navigate to Settings > Integrations
  3. Locate the Cursor integration
  4. Download the hooks.json file

Windows Deployment

  1. Log in to the Microsoft Intune admin center

  2. Navigate to Devices > Remediations

  3. Click Create script package and configure:

    • Name: Capsule Security – Cursor Hooks
    • Description: Deploys Capsule Security hooks configuration for Cursor
  4. Add the Detection Script (Detect-CursorHooks.ps1):

    $hooksFile = "C:\ProgramData\Cursor\hooks.json"
    
    if (-not (Test-Path $hooksFile)) {
        Write-Output "Capsule hooks configuration is missing."
        exit 1
    }
    
    if ((Get-Content -Raw -Path $hooksFile) -match 'capsulesecurity') {
        Write-Output "Capsule hooks configuration exists."
        exit 0
    }
    
    Write-Output "Capsule hooks not found in existing hooks.json."
    exit 1
  5. Add the Remediation Script (Remediate-CursorHooks.ps1):

    $hooksDir = "C:\ProgramData\Cursor"
    $hooksFile = "$hooksDir\hooks.json"
    
    if (-not (Test-Path $hooksDir)) {
        New-Item -ItemType Directory -Path $hooksDir -Force | Out-Null
    }
    
    $newJson = @'
    <PASTE YOUR HOOKS.JSON CONTENT HERE>
    '@
    
    $newConfig = $newJson | ConvertFrom-Json
    
    if (Test-Path $hooksFile) {
        try {
            $existing = Get-Content -Raw -Path $hooksFile | ConvertFrom-Json
        } catch {
            Copy-Item $hooksFile "$hooksFile.bak" -Force
            $existing = [PSCustomObject]@{ hooks = [PSCustomObject]@{} }
        }
    
        if (-not $existing.hooks) {
            $existing | Add-Member -NotePropertyName hooks -NotePropertyValue ([PSCustomObject]@{}) -Force
        }
    
        foreach ($prop in $newConfig.hooks.PSObject.Properties) {
            $eventName = $prop.Name
            $incoming = @($prop.Value)
            $kept = @()
            if ($existing.hooks.PSObject.Properties.Name -contains $eventName) {
                $kept = @($existing.hooks.$eventName | Where-Object {
                    -not ("$($_.bash)$($_.powershell)$($_.command)" -match 'capsulesecurity')
                })
            }
            $existing.hooks | Add-Member -NotePropertyName $eventName -NotePropertyValue ($kept + $incoming) -Force
        }
    
        $final = $existing
    } else {
        $final = $newConfig
    }
    
    [System.IO.File]::WriteAllText($hooksFile, ($final | ConvertTo-Json -Depth 20), [System.Text.UTF8Encoding]::new($false))
    
    Write-Output "Capsule hooks configuration deployed successfully."
    exit 0

    Replace <PASTE YOUR HOOKS.JSON CONTENT HERE> with the contents of the hooks.json file. The script merges Capsule hooks into any existing hooks.json and re-runs are idempotent (prior Capsule entries are replaced, non-Capsule hooks are preserved).

  6. Configure the script settings:

    • Run this script using the logged-on credentials: No (runs as SYSTEM)
    • Enforce script signature check: No
    • Run script in 64-bit PowerShell: Yes
  7. Assign the script package to the appropriate device groups

Verification

After deployment, restart Cursor on target devices, then:

  1. Open Cursor Settings
  2. Navigate to the Hooks tab
  3. Confirm the hooks are listed and enabled

GitHub Copilot

Deploy the GitHub Copilot hooks configuration using Intune's Remediation feature. GitHub Copilot reads its hooks from a per-user directory (%USERPROFILE%\.copilot\hooks\), so the remediation must run as the signed-in user, not as SYSTEM, and must be targeted at user groups.

Step 1: Download the Configuration

  1. Log in to the Capsule Security portal
  2. Navigate to Settings > Integrations
  3. Locate the GitHub Copilot integration
  4. Download the hooks.json file

Windows Deployment

  1. Log in to the Microsoft Intune admin center

  2. Navigate to Devices > Remediations

  3. Click Create script package and configure:

    • Name: Capsule Security – GitHub Copilot Hooks
    • Description: Deploys Capsule Security hooks configuration for GitHub Copilot
  4. Add the Detection Script (Detect-CopilotHooks.ps1):

    $hooksFile = Join-Path $env:USERPROFILE '.copilot\hooks\hooks.json'
    
    if (-not (Test-Path $hooksFile)) {
        Write-Output "Capsule hooks configuration is missing."
        exit 1
    }
    
    if ((Get-Content -Raw -Path $hooksFile) -match 'capsulesecurity') {
        Write-Output "Capsule hooks configuration exists."
        exit 0
    }
    
    Write-Output "Capsule hooks not found in existing hooks.json."
    exit 1
  5. Add the Remediation Script (Remediate-CopilotHooks.ps1):

    $ErrorActionPreference = "Stop"
    $targetPath = Join-Path $env:USERPROFILE '.copilot\hooks\hooks.json'
    $payload = @'
    <PASTE YOUR HOOKS.JSON CONTENT HERE>
    '@
    
    try {
        $parentDir = Split-Path -Path $targetPath -Parent
        if (-not (Test-Path -Path $parentDir)) {
            New-Item -ItemType Directory -Path $parentDir -Force | Out-Null
        }
        $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
        [System.IO.File]::WriteAllText($targetPath, $payload, $utf8NoBom)
        Write-Output "Capsule: wrote GitHub Copilot hooks config to $targetPath"
        exit 0
    } catch {
        Write-Error "Capsule: failed to write GitHub Copilot hooks config to $targetPath. $_"
        exit 1
    }

    Replace <PASTE YOUR HOOKS.JSON CONTENT HERE> with the contents of the hooks.json file. This is the same script the automated Intune integration deploys: it writes Capsule's hooks.json to the per-user Copilot hooks directory as UTF-8 without a BOM, creating the directory if needed, and is safe to re-run on every Intune cycle. It replaces the entire hooks.json at that path rather than merging into an existing one.

  6. Configure the script settings:

    • Run this script using the logged-on credentials: Yes
    • Enforce script signature check: No
    • Run script in 64-bit PowerShell: Yes
  7. Assign the script package to the appropriate user groups

Verification

After deployment, start a GitHub Copilot session on a target device, then:

  1. In the Capsule portal, navigate to Inventory > Agents and confirm the GitHub Copilot agent appears
  2. Open the agent and confirm session, prompt, response, and tool-invocation events are captured

Claude Code

Deploy the Claude Code managed settings configuration using Intune's Remediation feature.

Step 1: Download the Configuration

  1. Log in to the Capsule Security portal
  2. Navigate to Settings > Integrations
  3. Locate the Claude Code integration
  4. Click Install and select Windows as the target platform
  5. Download the managed-settings.json file

Windows Deployment

  1. Log in to the Microsoft Intune admin center

  2. Navigate to Devices > Remediations

  3. Click Create script package and configure:

    • Name: Capsule Security – Claude Code Hooks
    • Description: Deploys Capsule Security managed settings for Claude Code
  4. Add the Detection Script (Detect-ClaudeCodeHooks.ps1):

    $settingsFile = "C:\Program Files\ClaudeCode\managed-settings.json"
    
    if (-not (Test-Path $settingsFile)) {
        Write-Output "Capsule managed settings is missing."
        exit 1
    }
    
    if ((Get-Content -Raw -Path $settingsFile) -match 'capsulesecurity') {
        Write-Output "Capsule managed settings exists."
        exit 0
    }
    
    Write-Output "Capsule hooks not found in existing managed-settings.json."
    exit 1
  5. Add the Remediation Script (Remediate-ClaudeCodeHooks.ps1):

    $settingsDir = "C:\Program Files\ClaudeCode"
    $settingsFile = "$settingsDir\managed-settings.json"
    
    if (-not (Test-Path $settingsDir)) {
        New-Item -ItemType Directory -Path $settingsDir -Force | Out-Null
    }
    
    $newJson = @'
    <PASTE YOUR MANAGED-SETTINGS.JSON CONTENT HERE>
    '@
    
    $newConfig = $newJson | ConvertFrom-Json
    
    if (Test-Path $settingsFile) {
        try {
            $existing = Get-Content -Raw -Path $settingsFile | ConvertFrom-Json
        } catch {
            Copy-Item $settingsFile "$settingsFile.bak" -Force
            $existing = [PSCustomObject]@{}
        }
    
        # Merge top-level keys from new config; for `hooks`, merge by event
        foreach ($prop in $newConfig.PSObject.Properties) {
            $key = $prop.Name
            if ($key -eq 'hooks') {
                if (-not $existing.hooks) {
                    $existing | Add-Member -NotePropertyName hooks -NotePropertyValue ([PSCustomObject]@{}) -Force
                }
                foreach ($eventProp in $newConfig.hooks.PSObject.Properties) {
                    $eventName = $eventProp.Name
                    $incoming = @($eventProp.Value)
                    $kept = @()
                    if ($existing.hooks.PSObject.Properties.Name -contains $eventName) {
                        $kept = @($existing.hooks.$eventName | Where-Object {
                            $blob = ''
                            if ($_.hooks) { $blob += ($_.hooks | ConvertTo-Json -Depth 10 -Compress) }
                            $blob += "$($_.command)$($_.bash)$($_.powershell)"
                            -not ($blob -match 'capsulesecurity')
                        })
                    }
                    $existing.hooks | Add-Member -NotePropertyName $eventName -NotePropertyValue ($kept + $incoming) -Force
                }
            } else {
                $existing | Add-Member -NotePropertyName $key -NotePropertyValue $prop.Value -Force
            }
        }
    
        $final = $existing
    } else {
        $final = $newConfig
    }
    
    [System.IO.File]::WriteAllText($settingsFile, ($final | ConvertTo-Json -Depth 20), [System.Text.UTF8Encoding]::new($false))
    
    Write-Output "Capsule managed settings deployed successfully."
    exit 0

    Replace <PASTE YOUR MANAGED-SETTINGS.JSON CONTENT HERE> with the contents of the managed-settings.json file. The script merges Capsule hooks into any existing managed-settings.json and re-runs are idempotent (prior Capsule entries are replaced, non-Capsule settings and hooks are preserved).

  6. Configure the script settings:

    • Run this script using the logged-on credentials: No (runs as SYSTEM)
    • Enforce script signature check: No
    • Run script in 64-bit PowerShell: Yes
  7. Assign the script package to the appropriate device groups

Verification

After deployment, restart Claude Code on target devices, then:

  1. Run /hooks in Claude Code to confirm all hooks are listed
  2. Start a session and verify events appear in the Capsule Security portal

Kiro

Deploy the Kiro hooks installer using Intune's Remediation feature. Unlike Cursor, GitHub Copilot, and Claude Code, the Kiro integration emits a complete, self-contained PowerShell installer — there is no hooks.json or managed-settings.json to paste. The installer writes the Capsule hook dispatcher under %APPDATA%\Kiro\scripts\, merges the dispatcher path into kiroAgent.trustedCommands in the user's Kiro settings.json, and fans the Capsule hook (capsule-stop.kiro.hook) out to every Kiro workspace registered on the device. See the Kiro Integration guide for the full description of what the installer does.

Because the installer writes under %APPDATA% / %LOCALAPPDATA%, the Intune remediation must run as the signed-in user, not as SYSTEM, and must be targeted at user groups.

Step 1: Download the Installer

  1. Log in to the Capsule Security portal
  2. Navigate to Settings > Integrations
  3. Locate the Kiro integration
  4. Click Install and select Windows as the target platform
  5. Download the capsule-kiro-install.ps1 file

Windows Deployment

  1. Log in to the Microsoft Intune admin center

  2. Navigate to Devices > Remediations

  3. Click Create script package and configure:

    • Name: Capsule Security – Kiro Hooks
    • Description: Deploys Capsule Security hooks configuration for Kiro
  4. Add the Detection Script (Detect-KiroHooks.ps1):

    $settingsFile = "$env:APPDATA\Kiro\User\settings.json"
    
    if (-not (Test-Path $settingsFile)) {
        Write-Output "Capsule Kiro hooks are missing."
        exit 1
    }
    
    if ((Get-Content -Raw -Path $settingsFile) -match 'capsulesecurity') {
        Write-Output "Capsule Kiro hooks exist."
        exit 0
    }
    
    Write-Output "Capsule Kiro dispatcher not found in settings.json."
    exit 1
  5. Add the Remediation Script (Remediate-KiroHooks.ps1): paste the entire contents of the capsule-kiro-install.ps1 file you downloaded in Step 1, unchanged.

    The installer is already designed for unattended deployment: it requires no admin rights, prompts for nothing, writes only under %APPDATA% / %LOCALAPPDATA%, is fully idempotent (safe to re-run on every Intune cycle), exits 0 on success, and exits 2 only if PowerShell 5.1 is unavailable.

    Do not wrap, edit, or trim the script — the embedded authentication token, dispatcher source, and hook definition must reach the endpoint exactly as the portal generated them.

  6. Configure the script settings:

    • Run this script using the logged-on credentials: Yes
    • Enforce script signature check: No
    • Run script in 64-bit PowerShell: Yes
  7. Assign the script package to the appropriate user groups

Verification

After Intune reports the script as remediated on a target device, have the user:

  1. Quit and reopen Kiro
  2. Open any Kiro workspace and run a simple agent task (for example: "Create a new file called test.txt with the content 'Hello World'")
  3. In the Capsule portal, navigate to Inventory > Agents and confirm the Kiro agent appears
  4. Open the agent and confirm session, prompt, response, and tool-invocation events are captured

If events do not appear, confirm that %APPDATA%\Kiro\User\settings.json contains kiroAgent.trustedCommands referencing the Capsule dispatcher path, and that the workspace's .kiro/hooks/ directory contains capsule-stop.kiro.hook. See Troubleshooting in the Kiro Integration guide for the full diagnostic flow.


Codex

Deploy the Codex CLI hooks configuration using Intune's Remediation feature. On Windows, Codex's hooks call an external CapsuleCodexHook.ps1 script, so deployment writes two files — the hooks.json configuration and that script — under the user's home directory (%USERPROFILE%\.codex\). Because both live under the user profile, the remediation must run as the signed-in user, not as SYSTEM, and must be targeted at user groups.

Step 1: Download the Configuration

  1. Log in to the Capsule Security portal
  2. Navigate to Settings > Integrations
  3. Locate the Codex integration
  4. Click Install and select Windows as the target platform
  5. Download both files Capsule generates: the hooks.json configuration and the CapsuleCodexHook.ps1 hook script it invokes

Windows Deployment

  1. Log in to the Microsoft Intune admin center

  2. Navigate to Devices > Remediations

  3. Click Create script package and configure:

    • Name: Capsule Security – Codex Hooks
    • Description: Deploys Capsule Security hooks configuration for Codex CLI
  4. Add the Detection Script (Detect-CodexHooks.ps1):

    $scriptFile = Join-Path $env:USERPROFILE '.codex\hooks\CapsuleCodexHook.ps1'
    $hooksFile = Join-Path $env:USERPROFILE '.codex\hooks.json'
    
    if (-not ((Test-Path $scriptFile) -and (Test-Path $hooksFile))) {
        Write-Output "Capsule Codex hooks are missing."
        exit 1
    }
    
    if ((Get-Content -Raw -Path $scriptFile) -match 'capsulesecurity') {
        Write-Output "Capsule Codex hooks exist."
        exit 0
    }
    
    Write-Output "Capsule Codex hook script not found."
    exit 1
  5. Add the Remediation Script (Remediate-CodexHooks.ps1):

    $ErrorActionPreference = "Stop"
    
    function Write-CapsuleFile($path, $content, $label) {
        $parentDir = Split-Path -Path $path -Parent
        if (-not (Test-Path -Path $parentDir)) {
            New-Item -ItemType Directory -Path $parentDir -Force | Out-Null
        }
        $utf8NoBom = New-Object System.Text.UTF8Encoding($false)
        [System.IO.File]::WriteAllText($path, $content, $utf8NoBom)
        Write-Output "Capsule: wrote $label to $path"
    }
    
    try {
        $hookScript = @'
    <PASTE YOUR CapsuleCodexHook.ps1 CONTENT HERE>
    '@
        Write-CapsuleFile (Join-Path $env:USERPROFILE '.codex\hooks\CapsuleCodexHook.ps1') $hookScript 'Codex CapsuleCodexHook.ps1'
    
        $hooksJson = @'
    <PASTE YOUR HOOKS.JSON CONTENT HERE>
    '@
        Write-CapsuleFile (Join-Path $env:USERPROFILE '.codex\hooks.json') $hooksJson 'Codex hooks'
    
        exit 0
    } catch {
        Write-Error "Capsule: failed to write managed hook files. $_"
        exit 1
    }

    Replace each placeholder with the contents of the matching file you downloaded — CapsuleCodexHook.ps1 and hooks.json. This mirrors what the automated Intune integration deploys: both files are written under the per-user Codex directory as UTF-8 without a BOM, and re-runs are idempotent. The hooks.json invokes CapsuleCodexHook.ps1 by path, so both must be present — deploying hooks.json alone would leave every hook pointing at a script that was never installed. Each file is replaced wholesale rather than merged.

  6. Configure the script settings:

    • Run this script using the logged-on credentials: Yes
    • Enforce script signature check: No
    • Run script in 64-bit PowerShell: Yes
  7. Assign the script package to the appropriate user groups

Verification

After deployment, close any running Codex CLI sessions on target devices, then:

  1. Start a new Codex CLI session so the hooks configuration is loaded
  2. In the Capsule portal, navigate to Inventory > Agents and confirm the Codex agent appears
  3. Open the agent and confirm session, prompt, response, and tool-invocation events are captured

Monitoring Deployments

After deploying remediation scripts, monitor status in the Intune admin center:

  1. Navigate to Devices > Remediations
  2. Select the relevant script package
  3. Review the deployment status:
    • Without issues: Configuration already deployed
    • With issues: Configuration missing, remediation pending
    • Remediated: Script successfully deployed the configuration

Key Considerations

  • For ongoing changes (new hook versions, rotated JWTs, group adjustments), the automated integration reconciles your Intune tenant on every distribution edit so the deployed scripts always match the portal. The manual path needs the remediation script package to be edited in the Intune admin center each time.
  • Remediation scripts run every 24 hours by default, ensuring ongoing compliance
  • Detection scripts look for the Capsule URL marker in the configuration file, so devices with unrelated hooks already configured will still trigger remediation
  • The Cursor and Claude Code remediation scripts merge Capsule hooks into any existing configuration, so non-Capsule hooks and other settings are preserved (and if the existing file is unparseable it is renamed to <file>.bak first). The GitHub Copilot script writes a fresh hooks.json, and the Codex script writes a fresh hooks.json plus its CapsuleCodexHook.ps1 companion — the same files the automated integration drops, replacing whatever is already at those paths. All re-runs are idempotent.
  • Cursor and Claude Code use system-level paths — deploy with SYSTEM context and target device groups
  • GitHub Copilot, Kiro, Windsurf, Cline, and Codex use user-level paths (%APPDATA% / %USERPROFILE%) — deploy with user context and target user groups
  • All seven integrations can be deployed as separate remediation packages and assigned independently

Support

For help with deployment:

  • Email: support@capsule.security
  • Include: Your organization ID, Intune tenant details, and any error messages

References