Intune Win32 apps, without the maze

Win32Forge

Win32Forge takes an app folder, packaging scripts, and an icon, then turns them into a ready-to-upload .intunewin package with the Intune metadata wired in.

Plain-language overview

What does it handle?

It handles the repeatable packaging and Microsoft Graph upload work between your source folder and Intune.

Step one

Prepare the folder

Keep the app payload, install script, uninstall script, detection rule, and icon together.

Step two

Create the package

Win32Forge builds the `.intunewin` package Intune expects.

Step three

Add the metadata

It adds the app name, publisher, version, install command, uninstall command, and detection rule.

Step four

Publish to Intune

It uploads the package through Microsoft Graph so the app shows up as a Win32 app.

Before publishing

Set up the module.

You need PowerShell 7, two helper modules, an Intune tenant, and permission to create Win32 apps.

Install Win32Forge
Install-Module Win32Forge -Scope CurrentUser
Import-Module Win32Forge
Install helpers
Install-Module Microsoft.Graph.Authentication, SvRooij.ContentPrep.Cmdlet -Scope CurrentUser

Publish an app

Run the publish command.

Use `-WhatIf` for a dry run. Use `-Force` when replacing an existing app with the same display name.

Interactive sign-in
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0'
Dry run
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -WhatIf
Product code detection
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @{
        Type = 'ProductCode'
        ProductCode = '{11111111-1111-1111-1111-111111111111}'
    }
PowerShell script detection
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @{
        Type = 'PowerShellScript'
        ScriptPath = 'detection.ps1'
        EnforceSignatureCheck = $false
        RunAs32Bit = $false
    }
File system detection
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @{
        Type = 'FileSystem'
        Path = '%ProgramFiles%\Contoso'
        FileOrFolderName = 'Contoso.exe'
        DetectionType = 'exists'
        Check32BitOn64System = $false
    }
Registry detection
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @{
        Type = 'Registry'
        KeyPath = 'HKEY_LOCAL_MACHINE\Software\Contoso'
        ValueName = 'Version'
        DetectionType = 'version'
        Operator = 'greaterThanOrEqual'
        DetectionValue = '1.0.0'
    }
Raw Graph detection
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @{
        '@odata.type' = '#microsoft.graph.win32LobAppProductCodeDetection'
        productCode = '{11111111-1111-1111-1111-111111111111}'
        productVersionOperator = 'notConfigured'
        productVersion = ''
    }
Multiple detection rules
Publish-IntuneWin32App `
    -SourceDirectory ./Examples/ContosoSampleApp `
    -Name 'Contoso Sample App' `
    -Publisher 'Contoso' `
    -Version '1.0.0' `
    -DetectionRule @(
        @{
            Type = 'FileSystem'
            Path = '%ProgramFiles%\Contoso'
            FileOrFolderName = 'Contoso.exe'
            DetectionType = 'exists'
        }
        @{
            Type = 'Registry'
            KeyPath = 'HKEY_LOCAL_MACHINE\Software\Contoso'
            ValueName = 'Version'
            DetectionType = 'version'
            Operator = 'greaterThanOrEqual'
            DetectionValue = '1.0.0'
        }
    )

GitHub Pages setup

The page lives in `docs/index.html`. The `Deploy GitHub Pages` workflow publishes that folder when docs change on `main`.