Skip to content

[GRAPH-API] Cannot programmatically create or update device control rules in configurationPolicies #286

@hopsecutioner-svg

Description

@hopsecutioner-svg

DESCRIPTION:

Device control rules in Microsoft Intune can only be created and managed through the Intune Admin Portal UI. There is no programmatic way to add rules to existing configurationPolicies via the Microsoft Graph API.

This prevents organizations from:

  • Automating device control policy deployments
  • Creating rules programmatically based on inventory or business logic
  • Integrating device control with infrastructure-as-code (Terraform, PowerShell DSC, etc.)
  • Bulk managing rules across multiple policies

CURRENT BEHAVIOR:

All attempts to update device control rules via Graph API fail with BadRequest errors:

  1. PATCH Operations: "Delta patch payload must contain @context : #$delta"
  2. Navigation Property Updates: "Cannot apply PATCH to navigation property 'settings' on entity type 'microsoft.management.services.api.deviceManagementConfigurationPolicy'"
  3. PUT Operations: Same navigation property errors

Error Examples:

POST /deviceManagement/configurationPolicies
Status: 400 Bad Request
Error: "Delta patch payload must contain @context : #$delta"
PATCH /deviceManagement/configurationPolicies/{policyId}/settings
Status: 400 Bad Request
Error: "Cannot apply PATCH to navigation property 'settings'"

EXPECTED BEHAVIOR:

Organizations should be able to:

  1. Create new device control rules programmatically
  2. Update existing rules via PATCH/PUT operations
  3. Manage rules through Graph API just like other configuration policies
  4. Automate rule deployment using standard IaC tools

USE CASE / SCENARIO:

Enable bulk deployment of USB device control rules across multiple devices based on:

  • Inventory systems (device model, location, department)
  • Business requirements (new security standards)
  • Automated provisioning workflows
  • Multi-tenant management scenarios

CURRENT WORKAROUND:

None. Rules must be created manually in the Intune Admin Portal, which:

  • Doesn't scale for large organizations
  • Prevents automation
  • Creates compliance and consistency issues
  • Blocks DevOps/IaC workflows

IMPACT:

  • Organizations with thousands of devices cannot automate device control rules
  • Blocks Terraform provider support (microsoft/terraform-provider-msgraph)
  • Blocks PowerShell DSC support (Microsoft365DSC)
  • Limits enterprise automation capabilities
  • Affects organizations managing multiple tenants

RELATED ISSUES:

This is a known limitation affecting multiple organizations and tools:

  1. deviceManagement/configurationPolicies - update fails microsoft/terraform-provider-msgraph#36
    "deviceManagement/configurationPolicies - update fails"
    deviceManagement/configurationPolicies - update fails microsoft/terraform-provider-msgraph#36

  2. IntuneDeviceControlPolicyWindows10: Error, Count Of List of Setting Values 3, does not meet bound requirements. microsoft/Microsoft365DSC#5086
    "IntuneDeviceControlPolicyWindows10: Cannot add device control rules"
    IntuneDeviceControlPolicyWindows10: Error, Count Of List of Setting Values 3, does not meet bound requirements. microsoft/Microsoft365DSC#5086

  3. IntuneExploitProtectionPolicyWindows10SettingCatalog: Cannot update exploitprotectionsettings after deployment or delete policy microsoft/Microsoft365DSC#3962
    "Cannot update configurationPolicies settings"
    IntuneExploitProtectionPolicyWindows10SettingCatalog: Cannot update exploitprotectionsettings after deployment or delete policy microsoft/Microsoft365DSC#3962

  4. Feature Request: Support for Endpoint Security Policies  microsoft/Microsoft365DSC#4229
    "Feature Request: Support for Endpoint Security Policies"
    Feature Request: Support for Endpoint Security Policies  microsoft/Microsoft365DSC#4229

TESTING EVIDENCE:

Tested multiple approaches with /deviceManagement/configurationPolicies endpoint:

  1. PATCH with full settings array - FAILED

    • Error: Delta patch format required
  2. PATCH with delta format (@context) - FAILED

    • Error: Delta patch not supported for settings navigation property
  3. PUT entire policy - FAILED

    • Error: Navigation property PATCH not supported
  4. POST new settings - FAILED

    • Error: No POST endpoint for settings

All attempts confirmed that write operations to configurationPolicies settings are intentionally blocked at the API level.

REQUESTED CHANGES:

  1. Enable PATCH/PUT operations on configurationPolicies/settings navigation property
  2. Document the correct format for programmatic rule creation
  3. Provide Graph API support equivalent to what exists in the Intune UI
  4. Consider applying the same approach used in PR New Script to find App Protection policy unlicensed users #80 of terraform-provider-msgraph (preserving @odata.type fields for polymorphic resources)

ADDITIONAL CONTEXT:

  • Organization Type: Enterprise
  • Tenant Size: Mid to Large
  • Use Case: Device control policy automation
  • Estimated Impact: Affects automation of security policy deployment

API Endpoint being used:
POST/PATCH: https://graph.microsoft.com/beta/deviceManagement/configurationPolicies

Policy ID: (Example format)
d8659ddd-f590-4b65-bab7-24105435d83f

Current Settings Count: 2 (one group, one enabled toggle)

SUGGESTED SOLUTION:

Option 1 (Preferred): Enable full PATCH/PUT support for settings navigation property

  • Allow updating existing rules via PATCH
  • Allow adding new rules via POST to settings collection
  • Document the correct request format

Option 2: Create dedicated endpoint for rule management

  • POST /deviceManagement/configurationPolicies/{policyId}/rules
  • PATCH /deviceManagement/configurationPolicies/{policyId}/rules/{ruleId}
  • DELETE /deviceManagement/configurationPolicies/{policyId}/rules/{ruleId}

Option 3: Support OMA-URI XML directly in API

  • Allow setting raw OMA-URI/CSP values programmatically
  • Simplify the nested JSON structure for device control

VERSION INFORMATION:

  • Microsoft Graph API Version: Beta
  • Testing Date: January 2026

FOLLOW-UP QUESTIONS:

  1. Is this a design limitation or oversight?
  2. Are there plans to enable write operations for device control rules?
  3. Can early access be provided if this is in development?
  4. Is there an alternative supported method for programmatic rule creation?
  5. What permissions would be required once this is enabled?

SCRIPT:

USB Device Control Policy - View & Create Rules

Supports querying AD for SIDs and creating new USB device control rules

param(
[Parameter(HelpMessage = "Action to perform: View or Create")]
[ValidateSet("View", "Create")]
[string]$Action
)

$TenantId = ""
$ClientId = ""
$ClientSecret = ""
$policyId = "d8659ddd-f590-4b65-bab7-24105435d83f"

Color output functions

function Write-Success {
param([string]$Message)
Write-Host $Message -ForegroundColor Green
}

function Write-Warning {
param([string]$Message)
Write-Host $Message -ForegroundColor Yellow
}

function Write-Info {
param([string]$Message)
Write-Host $Message -ForegroundColor Cyan
}

function Write-Error {
param([string]$Message)
Write-Host $Message -ForegroundColor Red
}

Module installation

$requiredModules = @("Microsoft.Graph.Authentication")
foreach ($mod in $requiredModules) {
if (-not (Get-Module -ListAvailable $mod)) {
Write-Info "Installing module: $mod"
Install-Module $mod -Scope CurrentUser -Force -ErrorAction Stop
}
Import-Module $mod -ErrorAction Stop
}

Connect to Microsoft Graph

function Connect-ToMgGraph {
$SecureSecret = ConvertTo-SecureString $ClientSecret -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential($ClientId, $SecureSecret)

try {
    Connect-MgGraph -ClientSecretCredential $Cred -TenantId $TenantId -NoWelcome
    Write-Success "Connected to Microsoft Graph`n"
}
catch {
    Write-Error "Failed to connect to Microsoft Graph: $_"
    return $false
}
return $true

}

Resolve SID to name

function Resolve-SIDToName {
param([string]$SID)
try {
$objSID = New-Object System.Security.Principal.SecurityIdentifier($SID)
$objUser = $objSID.Translate([System.Security.Principal.NTAccount])
return $objUser.Value
}
catch {
return $SID
}
}

Get SID from AD for a user or computer using .NET SecurityIdentifier (same mechanism as Resolve-SIDToName)

function Get-SIDFromAD {
param(
[Parameter(Mandatory = $true)]
[string]$SamAccountName,

    [Parameter(Mandatory = $false)]
    [string]$ObjectType = "User",
    
    [Parameter(Mandatory = $false)]
    [string]$Domain
)

try {
    # For computer objects, ensure the account name has the $ suffix
    $accountNameToLookup = $SamAccountName
    if ($ObjectType -eq "Computer" -and -not $SamAccountName.EndsWith('$')) {
        $accountNameToLookup = "$SamAccountName`$"
    }
    
    # Use the reverse of Resolve-SIDToName approach
    # Build the NTAccount name (domain\username)
    $domainName = if ($Domain) { $Domain } else { $env:USERDOMAIN }
    
    Write-Info "Current Domain: $domainName"
    Write-Info "Looking up: $SamAccountName ($ObjectType)"
    Write-Host ""
    
    # Try with the specified/default domain first
    Write-Info "Attempting lookup as: $domainName\$accountNameToLookup"
    
    try {
        $objNTAccount = New-Object System.Security.Principal.NTAccount($domainName, $accountNameToLookup)
        $objSID = $objNTAccount.Translate([System.Security.Principal.SecurityIdentifier])
        
        $sidValue = $objSID.Value
        Write-Success "Found SID: $sidValue"
        return $sidValue
    }
    catch {
        Write-Warning "Not found in domain: $domainName"
        
        # If it's a computer and we haven't specified a domain, try alternative methods
        if ($ObjectType -eq "Computer" -and -not $Domain) {
            Write-Info "Trying alternative lookup methods..."
            
            # Try just the account name without domain qualification
            Write-Info "Attempting lookup as: $accountNameToLookup (no domain)"
            $objNTAccount = New-Object System.Security.Principal.NTAccount($accountNameToLookup)
            $objSID = $objNTAccount.Translate([System.Security.Principal.SecurityIdentifier])
            
            $sidValue = $objSID.Value
            Write-Success "Found SID: $sidValue"
            return $sidValue
        }
        else {
            throw $_
        }
    }
}
catch {
    Write-Error "Failed to retrieve SID for $SamAccountName ($ObjectType)"
    Write-Warning "Details: $_"
    Write-Warning ""
    Write-Warning "Troubleshooting steps:"
    Write-Warning "  1. Verify the exact computer name in AD: $SamAccountName"
    Write-Warning "  2. Try specifying the domain explicitly: -ADDomain HSCDOM"
    Write-Warning "  3. Try different domain formats:"
    Write-Warning "     - NetBIOS name (e.g., HSCDOM)"
    Write-Warning "     - FQDN (e.g., hscdom.local or hscdom.com)"
    Write-Warning "  4. Verify network connectivity to domain controllers"
    Write-Warning "  5. Check that the computer/user actually exists in AD"
    Write-Warning "  6. Verify the computer name spelling and case"
    return $null
}

}

Export existing rule structure for debugging

function Export-RuleStructure {
try {
Write-Info "Exporting first existing rule structure for inspection..."
Write-Host ""

    $settingsUri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId/settings"
    $settingsResponse = Invoke-MgGraphRequest -Method GET -Uri $settingsUri
    
    foreach ($setting in $settingsResponse.value) {
        if ($setting.settingInstance['@odata.type'] -eq "#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance") {
            $groupCollection = $setting.settingInstance['groupSettingCollectionValue']
            
            if ($groupCollection -and $groupCollection.Count -gt 0) {
                $firstRule = $groupCollection[0]
                $jsonOutput = $firstRule | ConvertTo-Json -Depth 10
                
                Write-Host "=== FIRST RULE STRUCTURE ===" 
                Write-Host $jsonOutput
                Write-Host ""
                Write-Host "=== RULE TYPE ===" 
                Write-Host $firstRule['@odata.type']
                Write-Host ""
                
                # Save to file for review
                $exportPath = "$env:USERPROFILE\Desktop\rule-structure.json"
                $jsonOutput | Out-File -FilePath $exportPath -Force
                Write-Success "Full structure exported to: $exportPath"
            }
            break
        }
    }
}
catch {
    Write-Error "Failed to export structure: $_"
}

}

View existing rules

function View-USBControlRules {
try {
$settingsUri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId/settings"
$settingsResponse = Invoke-MgGraphRequest -Method GET -Uri $settingsUri

    Write-Info "USB Device Control Policy - Block All USB Storage Devices"
    Write-Info "================================================================`n"
    
    if ($settingsResponse.value) {
        foreach ($setting in $settingsResponse.value) {
            if ($setting.settingInstance['@odata.type'] -eq "#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance") {
                Write-Info "DEVICE CONTROL RULES:"
                Write-Info "────────────────────────────────────────────────────────────────"
                
                $groupCollection = $setting.settingInstance['groupSettingCollectionValue']
                $ruleCount = 0
                
                if ($groupCollection) {
                    foreach ($ruleGroup in $groupCollection) {
                        $ruleCount++
                        $ruleId = $null
                        $ruleName = $null
                        $computerSid = $null
                        $userSid = $null
                        $accessType = $null
                        $accessMask = @()
                        
                        $children = $ruleGroup['children']
                        if ($children) {
                            foreach ($child in $children) {
                                $groupVal = $child['groupSettingCollectionValue']
                                if ($groupVal) {
                                    foreach ($ruleData in $groupVal) {
                                        $ruleChildren = $ruleData['children']
                                        if ($ruleChildren) {
                                            foreach ($dataChild in $ruleChildren) {
                                                $dataDefId = $dataChild['settingDefinitionId']
                                                $simpleValue = $dataChild['simpleSettingValue']
                                                $groupValue = $dataChild['groupSettingCollectionValue']
                                                
                                                if ($dataDefId -match "ruledata_id$" -and $simpleValue) {
                                                    $ruleId = $simpleValue['value']
                                                }
                                                elseif ($dataDefId -match "ruledata_name$" -and $simpleValue) {
                                                    $ruleName = $simpleValue['value']
                                                }
                                                elseif ($dataDefId -match "ruledata_entry$" -and $groupValue) {
                                                    foreach ($entry in $groupValue) {
                                                        $entryChildren = $entry['children']
                                                        if ($entryChildren) {
                                                            foreach ($entryChild in $entryChildren) {
                                                                $entryDefId = $entryChild['settingDefinitionId']
                                                                $entryChoice = $entryChild['choiceSettingValue']
                                                                $entryChoiceCollection = $entryChild['choiceSettingCollectionValue']
                                                                $simpleVal = $entryChild['simpleSettingValue']
                                                                
                                                                if ($entryDefId -match "entry_type$" -and $entryChoice) {
                                                                    $typeValue = $entryChoice['value']
                                                                    $accessType = if ($typeValue -match "deny") { "Deny" } else { "Allow" }
                                                                }
                                                                elseif ($entryDefId -match "entry_accesmask$" -and $entryChoiceCollection) {
                                                                    foreach ($maskItem in $entryChoiceCollection) {
                                                                        $maskValue = $maskItem['value']
                                                                        if ($maskValue -match "accesmask_1") { $accessMask += "Read" }
                                                                        elseif ($maskValue -match "accesmask_2") { $accessMask += "Write" }
                                                                        elseif ($maskValue -match "accesmask_4") { $accessMask += "Execute" }
                                                                    }
                                                                }
                                                                elseif ($entryDefId -match "entry_sid$" -and $simpleVal) {
                                                                    $sidValue = $simpleVal['value']
                                                                    if ($sidValue -match "^S-1-5-") {
                                                                        $userSid = $sidValue
                                                                    }
                                                                }
                                                                elseif ($entryDefId -match "entry_computersid$" -and $simpleVal) {
                                                                    $sidValue = $simpleVal['value']
                                                                    if ($sidValue -match "^S-1-5-") {
                                                                        $computerSid = $sidValue
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        
                        Write-Host ""
                        Write-Host "Rule $($ruleCount):"
                        Write-Host "  Name:              $ruleName"
                        Write-Host "  ID:                $ruleId"
                        Write-Host "  Access Type:       $accessType"
                        if ($accessMask.Count -gt 0) {
                            Write-Host "  Access Mask:       $($accessMask -join ', ')"
                        }
                        Write-Host "  Reusable Setting:  All Removable Storage"
                        if ($computerSid) {
                            $computerName = Resolve-SIDToName -SID $computerSid
                            Write-Host "  Computer:          $computerName [$computerSid]"
                        }
                        if ($userSid) {
                            $userName = Resolve-SIDToName -SID $userSid
                            Write-Host "  User:              $userName [$userSid]"
                        }
                    }
                }
                Write-Host ""
            }
            
            if ($setting.settingInstance['@odata.type'] -eq "#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance") {
                $enabledValue = $setting.settingInstance['choiceSettingValue']['value']
                $isEnabled = if ($enabledValue -match "enabled_1") { "ENABLED" } else { "DISABLED" }
                Write-Info "DEVICE CONTROL STATUS:"
                Write-Info "────────────────────────────────────────────────────────────────"
                Write-Host "Status: $isEnabled`n"
            }
        }
    }
    
    $policy = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId"
    Write-Info "POLICY DETAILS:"
    Write-Info "────────────────────────────────────────────────────────────────"
    Write-Host "Policy Name:     $($policy.name)"
    Write-Host "Policy ID:       $($policy.id)"
    Write-Host "Platform:        $($policy.platforms)"
    Write-Host "Created:         $($policy.createdDateTime)"
    Write-Host "Last Modified:   $($policy.lastModifiedDateTime)`n"
}
catch {
    Write-Error "Failed to retrieve rules: $_"
}

}

Create a new rule

function New-USBControlRule {
param(
[Parameter(Mandatory = $true)]
[string]$MachineName,

    [Parameter(Mandatory = $false)]
    [string]$UserID,
    
    [Parameter(Mandatory = $false)]
    [string]$ADDomain
)

Write-Info "Creating new USB Device Control rule...`n"

# Validate machine name format
if ($MachineName -notmatch '^[a-zA-Z0-9]+$') {
    Write-Error "Invalid machine name format: $MachineName"
    return $false
}

# Get machine SID
$computerSID = Get-SIDFromAD -SamAccountName $MachineName -ObjectType "Computer" -Domain $ADDomain

if (-not $computerSID) {
    return $false
}

Write-Host ""

# Build rule name and get user SID if provided
$ruleName = $MachineName
$userSID = $null

if ($UserID) {
    $userSID = Get-SIDFromAD -SamAccountName $UserID -ObjectType "User" -Domain $ADDomain
    
    if (-not $userSID) {
        return $false
    }
    Write-Host ""
    $ruleName = "$MachineName`:$UserID"
}

# Generate a unique rule ID (GUID)
$ruleID = [System.Guid]::NewGuid().ToString()

Write-Info "Rule Configuration:"
Write-Info "────────────────────────────────────────────────────────────────"
Write-Host "Rule Name:           $ruleName"
Write-Host "Rule ID:             $ruleID"
Write-Host "Machine Name:        $MachineName"
Write-Host "Machine SID:         $computerSID"
if ($UserID) {
    Write-Host "User ID:             $UserID"
    Write-Host "User SID:            $userSID"
}
Write-Host "Access Type:         Allow"
Write-Host "Access Mask:         Read, Write, Execute"
Write-Host "Reusable Setting:    All Removable Storage`n"

# Build the rule payload
$rulePayload = Build-RulePayload -RuleID $ruleID -RuleName $ruleName -ComputerSID $computerSID -UserSID $userSID

if (-not $rulePayload) {
    Write-Error "Failed to build rule payload"
    return $false
}

# Submit the new rule by PATCH the policy with settings
try {
    Write-Info "Submitting rule to policy..."
    
    # Fetch current settings
    Write-Info "Fetching current settings..."
    $settingsUri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId/settings"
    $settingsResponse = Invoke-MgGraphRequest -Method GET -Uri $settingsUri
    
    # Get the device control rules setting
    $dcRuleSetting = $null
    foreach ($setting in $settingsResponse.value) {
        if ($setting.settingInstance['@odata.type'] -eq "#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance") {
            $dcRuleSetting = $setting
            Write-Info "Found device control setting with ID: $($setting.id)"
            break
        }
    }
    
    if (-not $dcRuleSetting) {
        Write-Error "Could not find device control rules setting"
        return $false
    }
    
    # Add the new rule to the collection
    $groupCollection = $dcRuleSetting.settingInstance['groupSettingCollectionValue']
    if ($null -eq $groupCollection) {
        $groupCollection = @()
    }
    $groupCollection += @($rulePayload)
    
    # Update the setting instance with the new rules
    $dcRuleSetting.settingInstance['groupSettingCollectionValue'] = $groupCollection
    
    # Build the complete settings array
    $updatedSettings = @()
    foreach ($setting in $settingsResponse.value) {
        if ($setting.settingInstance['@odata.type'] -eq "#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance") {
            # Update with new rules
            $setting.settingInstance['groupSettingCollectionValue'] = $groupCollection
        }
        $updatedSettings += $setting
    }
    
    # Build the policy update payload with settings embedded
    $policyUpdatePayload = @{
        settings = $updatedSettings
    }
    
    $body = ConvertTo-Json $policyUpdatePayload -Depth 50
    
    # Debug: Show the payload being submitted
    Write-Info "DEBUG: Payload being submitted:"
    Write-Info "───────────────────────────────────────────────────────────────"
    # Show just the new rule part for debugging
    $newRuleJson = ConvertTo-Json $rulePayload -Depth 20
    Write-Host $newRuleJson
    Write-Host ""
    
    $policyUri = "https://graph.microsoft.com/beta/deviceManagement/configurationPolicies/$policyId"
    
    Write-Info "Updating policy with embedded settings..."
    Write-Info "  Policy URI: $policyUri"
    Write-Info "  Number of settings: $($updatedSettings.Count)"
    
    Invoke-MgGraphRequest -Method PUT -Uri $policyUri -Body $body | Out-Null
    
    Write-Success "Rule created successfully!`n"
    return $true
}
catch {
    Write-Error "Failed to create rule: $_"
    Write-Warning "Error details: $_"
    return $false
}

}

Build rule payload structure based on actual API format from existing rules

function Build-RulePayload {
param(
[string]$RuleID,
[string]$RuleName,
[string]$ComputerSID,
[string]$UserSID
)

# Build the rule using the exact structure from actual API responses
# Root object has settingValueTemplateReference but no @odata.type
$rulePayload = @{
    settingValueTemplateReference = $null
    children = @(
        @{
            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance'
            settingDefinitionId = "ruledata_id"
            settingInstanceTemplateReference = $null
            simpleSettingValue = @{
                '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue'
                settingValueTemplateReference = $null
                value = $RuleID
            }
            auditRuleInformation = $null
        },
        @{
            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance'
            settingDefinitionId = "ruledata_name"
            settingInstanceTemplateReference = $null
            simpleSettingValue = @{
                '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue'
                settingValueTemplateReference = $null
                value = $RuleName
            }
            auditRuleInformation = $null
        },
        @{
            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationGroupSettingCollectionInstance'
            settingDefinitionId = "ruledata_entry"
            settingInstanceTemplateReference = $null
            auditRuleInformation = $null
            groupSettingCollectionValue = @(
                @{
                    settingValueTemplateReference = $null
                    children = @(
                        @{
                            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingInstance'
                            settingDefinitionId = "entry_type"
                            settingInstanceTemplateReference = $null
                            auditRuleInformation = $null
                            choiceSettingValue = @{
                                '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'
                                settingValueTemplateReference = $null
                                value = "allow_1"
                            }
                        },
                        @{
                            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingCollectionInstance'
                            settingDefinitionId = "entry_accesmask"
                            settingInstanceTemplateReference = $null
                            auditRuleInformation = $null
                            choiceSettingCollectionValue = @(
                                @{
                                    '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'
                                    settingValueTemplateReference = $null
                                    value = "accesmask_1"
                                },
                                @{
                                    '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'
                                    settingValueTemplateReference = $null
                                    value = "accesmask_2"
                                },
                                @{
                                    '@odata.type' = '#microsoft.graph.deviceManagementConfigurationChoiceSettingValue'
                                    settingValueTemplateReference = $null
                                    value = "accesmask_4"
                                }
                            )
                        },
                        @{
                            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance'
                            settingDefinitionId = "entry_sid"
                            settingInstanceTemplateReference = $null
                            simpleSettingValue = @{
                                '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue'
                                settingValueTemplateReference = $null
                                value = $UserSID
                            }
                            auditRuleInformation = $null
                        },
                        @{
                            '@odata.type' = '#microsoft.graph.deviceManagementConfigurationSimpleSettingInstance'
                            settingDefinitionId = "entry_computersid"
                            settingInstanceTemplateReference = $null
                            simpleSettingValue = @{
                                '@odata.type' = '#microsoft.graph.deviceManagementConfigurationStringSettingValue'
                                settingValueTemplateReference = $null
                                value = $ComputerSID
                            }
                            auditRuleInformation = $null
                        }
                    )
                }
            )
        }
    )
}

return $rulePayload

}

Main execution

try {
if (-not (Connect-ToMgGraph)) {
exit 1
}

if (-not $Action) {
    Write-Info "USB Device Control Policy Management"
    Write-Info "════════════════════════════════════════"
    Write-Host "1. View existing rules"
    Write-Host "2. Create new rule"
    Write-Host "3. Export rule structure (for debugging)"
    Write-Host ""
    $choice = Read-Host "Select an option (1, 2, or 3)"
    
    switch ($choice) {
        "1" { $Action = "View" }
        "2" { $Action = "Create" }
        "3" { $Action = "Export" }
        default {
            Write-Error "Invalid selection"
            exit 1
        }
    }
}

switch ($Action) {
    "View" {
        View-USBControlRules
    }
    "Export" {
        Export-RuleStructure
    }
    "Create" {
        Write-Info "Create New USB Device Control Rule"
        Write-Info "═══════════════════════════════════"
        Write-Host ""
        
        $MachineName = Read-Host "Enter machine name (e.g., mxl12345)"
        if (-not $MachineName) {
            Write-Error "Machine name is required"
            exit 1
        }
        
        $UserID = Read-Host "Enter user ID (optional, press Enter to skip)"
        if (-not $UserID -or $UserID.Trim() -eq "") {
            $UserID = $null
        }
        
        $ADDomain = Read-Host "Enter AD domain if different from default (optional, press Enter to use default)"
        if (-not $ADDomain -or $ADDomain.Trim() -eq "") {
            $ADDomain = $null
        }
        
        Write-Host ""
        $success = New-USBControlRule -MachineName $MachineName -UserID $UserID -ADDomain $ADDomain
        if (-not $success) {
            exit 1
        }
    }
}

}
catch {
Write-Error "Unexpected error: $_"
exit 1
}
finally {
if (Get-MgContext) {
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions