Bulk Win32 App Deployment to Intune Using PowerShell and Microsoft Graph API

Managing Win32 applications in Microsoft Intune can quickly become repetitive and time-consuming, especially when deploying multiple applications across environments.

To simplify the process, I built a PowerShell automation framework that can:

  • Read app configurations from JSON files
  • Package applications into .intunewin
  • Upload Win32 apps to Intune
  • Create Entra ID groups automatically
  • Assign apps to groups
  • Validate configuration files before deployment
  • Generate deployment logs using a transcript and centralized logging

This script is designed to support bulk application onboarding with minimal manual effort.

Prerequisites

  • Active Microsoft Intune and Microsoft Entra administrator access.
  • Entra App Registration with Microsoft Graph Application permissions
  • Required PowerShell modules installed: (MALS & IntuneWin32 App)
  • Download IntuneWinAppUtil.exe from Microsoft Win32 Content Prep Tool GitHub Repository.
  • Store application source files and config.json inside individual app folders under the Apps directory.
  • Configure PowerShell execution policy if required:

Current Limitations

Currently Supported

  • MSI Detection Rules

Planned for Future Release

  • File, Registry, and Script Detection Rules
  • Icon Upload Support
  • Supersedence Support
  • Requirement Rules Expansion

Folder Structure

The application installation source and configuration files need to be aligned as per the folder structure.

Intune_Win32App_AutoDeploy/
│
├── Apps/
│   ├── Notepad++ 8.9.1 x64/
│   │   ├── npp.8.9.1.Installer.x64.msi
│   │   └── config.json
│   │
│   └── 7Zip 24.09/
│       ├── 7z2409-x64.msi
│       └── config.json
│
├── IntuneWinAppUtil.exe
├── Intune_Win32App_AutoDeploy.ps1
└── Logs/

Script Workflow

The script follows the workflow below:

Read App Folder
      ↓
Read Config.json
      ↓
Validate Configuration
      ↓
Create .intunewin Package
      ↓
Authenticate to Graph
      ↓
Upload Win32 App
      ↓
Create Entra Group
      ↓
Assign Application
      ↓
Write Logs & Transcript

Configuration File Example

Each application folder contains a config.json.

Example:

{
  "DisplayName": "Notepad++ 8.9.1 x64",
  "Description": "Notepad++",
  "Publisher": "Notepad++",
  "AppVersion": "8.9.1",
  "InstallerName": "npp.8.9.1.Installer.x64.msi",

  "InstallCmd": "msiexec /i npp.8.9.1.Installer.x64.msi /qn /norestart",
  "UninstallCmd": "msiexec /x npp.8.9.1.Installer.x64.msi /qn /norestart",

  "CreateGroup": "Yes",
  "GroupName": "APP - Notepad++",

  "AssignApp": "Yes",

  "DetectionRules": [
    {
      "Type": "MSI",
      "Enabled": true,
      "ProductCode": "{7349B4F3-02E1-4234-A67A-FA85B33B67AF}",
      "ProductVersionOperator": "equal",
      "ProductVersion": "8.9.1"
    }
  ]
}

Important Script Components

1. Configuration Validation

The script validates:

  • Required JSON properties
  • Empty values
  • Installer file existence
  • Folder name vs DisplayName mismatch
  • Detection rule structure

Example validation logic:

if ($folderName -ne $Config.DisplayName) {

    Write-Log @"
Folder name does not match DisplayName.

Folder Name : $folderName
DisplayName : $($Config.DisplayName)
"@ "ERROR"

    $validationFailed = $true
}

This helps avoid deployment issues caused by copied configuration files. This helps in cleaner transcript logs and easier troubleshooting.

2. Centralized Logging

Instead of scattered Write-Host calls, the script uses a centralized logging function.

Example:

function Write-Log {

    param(
        [string]$Message,

        [ValidateSet("INFO","WARN","ERROR","SUCCESS")]
        [string]$Level = "INFO"
    )

    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

    switch ($Level) {

        "INFO" { $color = "White" }
        "WARN" { $color = "Yellow" }
        "ERROR" { $color = "Red" }
        "SUCCESS" { $color = "Green" }
    }

    Write-Host "[$timestamp] [$Level] $Message" `
        -ForegroundColor $color
}

3. Service Principal Authentication

The script uses a Service Principal for unattended authentication.

Recommended permissions:

DeviceManagementApps.ReadWrite.All
Group.ReadWrite.All

Example authentication:

Connect-MSIntuneGraph `    -TenantID $tenantId `    -ClientID $clientId `    -ClientSecret $clientSecret

4. Automated Packaging

The script automatically creates .intunewin packages using IntuneWinAppUtil.exe.

Example:

Start-Process `    -FilePath $intuneUtilPath `    -ArgumentList $arguments `    -Wait `    -WindowStyle Hidden

5. Entra Group Creation

The script checks whether a group already exists before creating it.

Benefits:

  • Prevents duplicate groups
  • Safe re-execution
  • Better bulk deployment experience

6. Assignment Handling

The script:

  • Assigns apps automatically
  • Prevents duplicate assignments
  • Supports Available intent

Configuration Validation Mode

The script supports a validation-only mode. This is useful before large bulk deployments, as you can validate the configurations before bulk upload. Any issues identified with the configuration can be fixed before the bulk upload.

Example:

.\Intune_Win32App_AutoDeploy.ps1 -ValidateConfig

This mode:

  • Validates JSON files
  • Checks the installer’s existence
  • Verifies folder naming
  • Skips upload and assignment

Useful before large bulk deployments.

Running the Script

Normal Deployment

.\Intune_Win32App_AutoDeploy.ps1

Validation Only

.\Intune_Win32App_AutoDeploy.ps1 -ValidateConfig

Transcript Logging

The script automatically generates PowerShell transcripts.

Example:

Start-Transcript -Path ".\Logs\Deploy.log"

Logs help with:

  • Troubleshooting
  • Auditing
  • Deployment history

Recommended Security Practice

Avoid storing secrets directly in the script. Instead, use environment variables:

$clientSecret = $env:INTUNE_CLIENT_SECRET

Set the user environment variable using the PowerShell command below. You need to run this with elevated PowerShell.

[System.Environment]::SetEnvironmentVariable(    "INTUNE_CLIENT_SECRET",    "YOUR_SECRET",    [System.EnvironmentVariableTarget]::User)

Benefits of This Automation

This framework helps:

  • Reduce repetitive Intune administration
  • Standardize application onboarding
  • Improve deployment consistency
  • Minimize manual errors
  • Scale Win32 deployments

Especially useful for:

  • Managed Service Provider (MSP) environments
  • Large enterprise deployments
  • Lab environments
  • Application packaging teams

Future Enhancements

Planned improvements include:

  • File and Registry detection rules
  • Script detection support
  • Icon uploads
  • Supersedence support
  • Requirement rule expansion
  • Dependency support
  • Retry logic improvements

Script Download

Download the complete script from Techuisitive GitHub repository.

Related Posts

Subscribe to Techuisitive Newsletter

Be the first to know about our new blog posts. Get our newsletters directly in your inbox and stay up to date about Modern Desktop Management technologies & news.

Scroll to Top