Modern Intune Configuration Management with progressive deployment rings and automated success gates
IntuneStack is a foundation to provide CI/CD orchestration. IntuneStack focuses purely on deployment orchestration of policy - adding progressive group deployment, automated success criteria evaluation, and OIDC-enabled CI/CD pipeline to operationalize through deployment rings (dev → test → prod).
🚧 Beginning of a Series: This is the foundation of IntuneStack's deployment orchestration capabilities. As with all development, this is a living project that will continue to evolve and improve based on real-world usage and community feedback.
- Progressive Deployment Groups: Automated dev → test → production group promotion with configurable success gates
- Automated Group Promotion: Automatic promotion based on predefined success criteria from device counts, success rates, and error thresholds
- OIDC Authentication: Secure GitHub Actions integration with Azure App Registration (no stored credentials)
- Code Quality Enforcement: PSScriptAnalyzer integration with pre-commit hooks and quality gates
- GitHub Actions: Fully automated CI/CD pipeline with environment protection and approval gates
This repository is configured to protect sensitive tenant information:
- ✅ Code quality results and unit test results are uploaded as artifacts (no sensitive data)
- ❌ Integration test results are NOT uploaded as artifacts (contain real Intune tenant data)
- 📋 All integration test results are available in GitHub Actions workflow logs
- 🛡️ Fork pull requests cannot create artifacts
- ⏱️ Artifacts are retained for 7 days only
Why this matters: Integration tests connect to your real Intune tenant and may contain:
- Tenant IDs and configuration details
- Policy names and assignments
- Group names and membership information
- Device deployment statistics
By not uploading these as artifacts, we ensure this sensitive information remains private even in a public repository.
When you fork this repository:
- Set up your own App Registration with OIDC
- Configure your own GitHub secrets (AZURE_TENANT_ID, AZURE_CLIENT_ID)
- Run workflows manually to test against your tenant
- Review workflow logs for detailed results (no public artifacts created)
IntuneStack/
├── README.md
│
├── .github/                            # GitHub Actions CI/CD
│   └── workflows/
│       ├── policy-promotion.yml         # Main CI/CD pipeline
│       └── pr-validation.yml            # PR quality gates
│
├── .vscode/                            # VS Code integration
│   ├── extensions.json                 # Recommended extensions
│   ├── settings.json                   # PowerShell formatting rules
│   └── tasks.json                      # Quality check tasks
│
├── config/                             # Configuration files
│   ├── .editorconfig                   # Code formatting rules
│   ├── .pre-commit-config.yaml         # Pre-commit hooks
│   └── PSScriptAnalyzerSettings.psd1   # Custom analyzer rules
│
├── src/
│   ├── Get-DeviceConfigPolicies.ps1
│   ├── Invoke-CodeQuality.ps1
│   └── PolicyPromotion.ps1
│
├── output/                             # Generated deployment artifacts
│   └── reports/                        # Success and promotion reports
│
└── tests/                              # Pester tests
    ├── Configuration.Tests.ps1
    └── PolicyPromotion.Tests.ps1
- Azure App Registration with OIDC configured for GitHub Actions
- PowerShell 7+ (for local development)
- Microsoft Graph PowerShell SDK (automatically installed)
- GitHub repository with appropriate secrets and variables
- Understanding of risk: Test in a non-production environment first
Click the "Fork" button at the top of this repository to create your own copy.
Create an App Registration with the following Graph API permissions:
# Required Microsoft Graph API permissions:
- DeviceManagementConfiguration.Read.All
- DeviceManagementConfiguration.ReadWrite.All  # For automated promotion
- Directory.Read.All                           # For group lookups
- Policy.Read.All
- Policy.ReadWrite.ConditionalAccess           # If managing CA policiesIn your Azure App Registration:
- Go to Certificates & secrets → Federated credentials
- Add credential for GitHub Actions deploying Azure resources
- Set:
- Organization: Your GitHub username/org
- Repository: Your repository name
- Entity type: Branch
- GitHub branch name: main
 
In your GitHub repository settings (Settings → Secrets and variables → Actions):
Secrets (sensitive):
AZURE_TENANT_ID=your-tenant-id
AZURE_CLIENT_ID=your-application-client-idVariables (optional, for custom group names):
INTUNESTACK_DEV_GROUP=Your-Dev-Group-Name
INTUNESTACK_TEST_GROUP=Your-Test-Group-Name
INTUNESTACK_PROD_GROUP=Your-Prod-Group-NameIf variables are not set, IntuneStack uses default group names:
Intune-Dev-Users,Intune-Test-Users,Intune-Prod-Users
Create three Entra ID groups for your deployment rings:
- Dev Group: Initial deployment and testing
- Test Group: Broader testing before production
- Prod Group: Production deployment
These groups can be any Entra ID groups - no special configuration needed.
- Go to Actions → Policy Promotion Testing
- Click Run workflow
- Enter parameters:
- Policy ID: The GUID of the Intune policy to promote
- Current Stage: dev,test, orprod
- Success Threshold: Minimum success rate % for promotion (default: 80%)
- Auto Promote: Enable to automatically promote if criteria met
- Output Level: Minimal,Normal, orDetailed
- Run tests only: Check to run Pester tests without connecting to Graph API
 
# Analyze a policy for promotion readiness
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev"
# Automatically promote if success criteria met
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev" -AutoPromote
# Use custom success threshold
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev" -ComplianceThreshold 85
# Detailed output for debugging
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev" -OutputLevel Detailed
# Custom output path
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev" -OutputPath "./my-reports"┌─────────────────────────────────────────────────────────────┐
│  Policy Created in Intune (not assigned to any group)       │
└────────────────────────┬────────────────────────────────────┘
                         │
                         ▼
┌─────────────────────────────────────────────────────────────┐
│  Stage 1: DEV                                               │
│  ✓ Assign to Dev Group                                      │
│  ✓ Monitor success rate (target: 80%)                       │
│  ✓ Minimum devices & time requirements                      │
└────────────────────────┬────────────────────────────────────┘
                         │ Auto-promote if criteria met
                         ▼
┌─────────────────────────────────────────────────────────────┐
│  Stage 2: TEST                                              │
│  ✓ Assign to Test Group                                     │
│  ✓ Monitor success rate (target: 80%)                       │
│  ✓ Validate across larger user base                         │
└────────────────────────┬────────────────────────────────────┘
                         │ Auto-promote if criteria met
                         ▼
┌─────────────────────────────────────────────────────────────┐
│  Stage 3: PROD                                              │
│  ✓ Assign to Prod Group                                     │
│  ✓ Policy now in production                                 │
│  ✓ Continue monitoring for issues                           │
└─────────────────────────────────────────────────────────────┘
The script analyzes each policy and determines:
- 
Current State: Which groups is the policy currently assigned to? 
- 
Target Stage: Where should the policy go next? 
- 
Success Metrics: - Total devices receiving the policy
- Success rate (% of devices with successful deployment)
- Error rate (% of devices with errors)
- Compliance with threshold requirements
 
- 
Action Decision: - ✅ Ready for promotion: Success rate meets or exceeds threshold
- ⏳ Not ready: Success rate below threshold
- 🎉 Complete: Already deployed to all stages
 
🔥 IntuneStack Policy Promotion Analysis v1.0.0
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
🔐 Connecting to Microsoft Graph...
✓ Connected to Microsoft Graph
📋 Analysis Parameters:
   Policy ID:         ********-****-****-****-************
   Current Stage:     dev
   Success Threshold: 80%
   Auto Promote:      ✅ Enabled
🔍 Detecting policy type...
   ✓ Found: Skip User ESP
     Type: DeviceConfiguration
📋 Getting current policy assignments...
✅ Found 1 group assignment(s)
   - Intune-Dev-Users
📊 Analyzing policy deployment status...
📋 Current Policy Status:
   Policy Name: Skip User ESP
   Success Rate: 100%
🎯 Promotion Analysis:
   Ready for Promotion: ✅ YES
   Current Stage Assignment: ✅ YES
   Action: Promote to test
   Target Stage: test
   Target Group: Intune-Test-Users
🚀 Auto-deployment enabled - deploying to test...
🔍 Current assignments before deployment:
   - Intune-Dev-Users (********-****-****-****-************)
✅ Policy successfully deployed to test stage
🔍 Verifying updated assignments...
✅ Policy now assigned to 2 group(s):
   - Intune-Dev-Users (********-****-****-****-************)
   - Intune-Test-Users (********-****-****-****-************)
✅ Policy promotion analysis completed!
Do not run integration tests on the public IntuneStack repository. Integration tests connect to your real Intune tenant and may expose tenant details in workflow logs, even with masking enabled.
# Test policy promotion locally with your own tenant
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev"
# Run with auto-promotion
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev" -AutoPromote- Fork this repository
- Keep your fork private
- Configure your Azure App Registration and GitHub secrets
- Run integration tests in your private fork safely
If you must run integration tests on a public repository:
- Use a test/demo tenant with no production data
- Create test policies specifically for validation
- Accept that some details may appear in logs despite masking
On push and pull requests, these tests run automatically and are safe for public repositories:
- ✅ Code quality checks (PSScriptAnalyzer) - No tenant connection
- ✅ Unit tests (Pester) - No tenant connection
- ✅ Mock/synthetic tests - No tenant connection
On manual workflow dispatch only:
- ⚠️ Integration tests - Connects to real Intune tenant (use with caution)
When integration tests run on your fork:
- 🔒 Tenant ID, Client ID, and Policy ID are masked in logs
- 🔒 OIDC tokens are masked immediately
- 🔒 No artifacts with tenant data are uploaded
- 🔒 GUIDs in output are redacted where possible
- ⚠️ Some tenant details may still appear in Graph API responses
# Run all Pester tests
Invoke-Pester -Path "./tests/PolicyPromotion.Tests.ps1"
# Run with code coverage
$config = New-PesterConfiguration
$config.Run.Path = "./tests/PolicyPromotion.Tests.ps1"
$config.CodeCoverage.Enabled = $true
$config.CodeCoverage.Path = "./src/PolicyPromotion.ps1"
Invoke-Pester -Configuration $config- ✅ Script syntax validation
- ✅ Function parameter validation
- ✅ Ring progression logic (dev → test → prod)
- ✅ Code quality (PSScriptAnalyzer)
Automatically used in CI/CD - no secrets stored in code:
- name: Request OIDC token
  id: oidc
  run: |
    OIDC_TOKEN="$(curl -s -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
      "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange" | jq -r .value)"For testing locally, the script automatically falls back to interactive authentication:
# Interactive browser authentication
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "dev"After each run, a JSON report is generated at ./output/reports/promotion-report.json:
{
  "Timestamp": "2024-01-15 10:30:00 UTC",
  "PolicyId": "12345678-1234-5678-9abc-def012345678",
  "PolicyType": "DeviceConfiguration",
  "PolicyName": "Skip User ESP",
  "CurrentStage": "dev",
  "NextStage": "test",
  "ReadyForPromotion": true,
  "PromotionExecuted": true,
  "PromotionTargetStage": "test",
  "PromotionTargetGroup": "Intune-Test-Users",
  "PromotionTimestamp": "2024-01-15 10:30:15 UTC",
  "Metrics": {
    "TotalDevices": 8,
    "SuccessfulDevices": 8,
    "SuccessRate": 100,
    "ErrorDevices": 0
  }
}Detailed logs are written to ./output/reports/promotion.log:
2024-01-15 10:30:00 - [Info] Policy ID: ********-****-****-****-************, Stage: dev
2024-01-15 10:30:05 - [Success] Connected to Microsoft Graph
2024-01-15 10:30:10 - [Info] Policy found: Skip User ESP (DeviceConfiguration)
2024-01-15 10:30:12 - [Success] Policy ready for test stage
2024-01-15 10:30:15 - [Success] Successfully promoted to test stage
Note: In GitHub Actions, these reports are generated but not uploaded as artifacts to protect sensitive tenant data. They are available in the workflow logs only.
Default success thresholds by stage:
| Stage | Default Threshold | Recommended | 
|---|---|---|
| Dev | 80% | 70-80% | 
| Test | 80% | 80-85% | 
| Prod | 80% | 85-95% | 
Customize per-run with -ComplianceThreshold:
# Require 90% success for production
.\src\PolicyPromotion.ps1 -PolicyId "" -CurrentStage "test" -ComplianceThreshold 90 -AutoPromoteConfigure custom group names using GitHub repository variables:
# Default group names (if variables not set)
INTUNESTACK_DEV_GROUP=Intune-Dev-Users
INTUNESTACK_TEST_GROUP=Intune-Test-Users
INTUNESTACK_PROD_GROUP=Intune-Prod-Users
# Custom group names (set as repository variables)
INTUNESTACK_DEV_GROUP=IT-Pilot-Ring
INTUNESTACK_TEST_GROUP=Finance-Pilot-Ring
INTUNESTACK_PROD_GROUP=All-Company-DevicesContributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Run tests: Invoke-Pester -Path "./tests"
- Run code quality: Invoke-ScriptAnalyzer -Path "./src" -Recurse
- Submit a pull request
- Microsoft Graph PowerShell SDK - Graph API interaction
- Maester Documentation - OIDC authentication patterns
- GitHub OIDC - Secure authentication
- Intune Graph API - API documentation
- Pester - PowerShell testing framework
USE AT YOUR OWN RISK: This software is provided "as is" without warranty of any kind. The authors and contributors are not responsible for any damages or issues that may arise from using this software. Always:
- Test in a non-production environment first
- Review all code before running against your tenant
- Understand the permissions you're granting
- Monitor your deployments closely
- Have a rollback plan
License: This project is licensed under the GPL License - see the LICENSE file for details
- Andrew Taylor - Intune management function foundation
- Maester Team - OIDC and testing patterns inspiration
- Microsoft Graph Team - Comprehensive PowerShell SDK