Skip to main content

Free tool · Runs in your browser

Intune Win32 Detection & Requirement Script Builder

Build a PowerShell detection or requirement script for an Intune Win32 app, or a Configuration Manager script detection method, without starting from a blank file. Pick a file version, registry value, MSI product code or Windows service check and the script updates as you type. Every script writes to STDOUT and exits 0 only when the app is found, exits 1 silently when it is not, and catches errors so a typo in a path never writes to STDERR.

Nothing you type leaves the browser. Test the script on a pilot device before you assign the app beyond a test group.

Script type
Detection type

Full path. Environment variables such as %ProgramData% are expanded on the device.

Match what the vendor bumps each release. Check with (Get-Item <path>).VersionInfo.

Compared as [version] with missing parts padded to zero, so 1.4 equals 1.4.0.0.

Used in the script header and the download file name.

PowerShellDetect-VendorApp.ps1
<#
.SYNOPSIS
    Intune Win32 detection script for Vendor App.
    Detected when C:\Program Files\Vendor\App\app.exe ProductVersion >= 1.4.2.0.

.DESCRIPTION
    Detected     : one line on STDOUT, exit 0
    Not detected : no STDOUT, exit 1
    Any error    : no STDOUT or STDERR, exit 1 (reported as not detected)

.NOTES
    Intune: Detection rules > Use a custom detection script.
    Run script as 32-bit process on 64-bit clients: No. Enforce script signature check: No
    unless the script is signed. Save as UTF-8 with BOM.
    Generated by the AdminSignal Intune Win32 Detection Script Builder:
    https://www.adminsignal.com/tools/intune-win32-detection-generator
#>

$ErrorActionPreference = 'Stop'

function ConvertTo-ComparableVersion {
    # Pads to four parts so 1.4 compares equal to 1.4.0.0, and keeps only the leading
    # dotted number so values such as '1.4.2.0 (x64)' or '1, 4, 2, 0' still compare.
    param([AllowNull()][object]$Value)
    if ($null -eq $Value) { return $null }
    $text = ([string]$Value).Trim() -replace '\s*,\s*', '.'
    $match = [regex]::Match($text, '\d+(\.\d+){0,3}')
    if (-not $match.Success) { return $null }
    $parts = @($match.Value.Split('.') | ForEach-Object { [int]$_ })
    while ($parts.Count -lt 4) { $parts += 0 }
    return [version]::new($parts[0], $parts[1], $parts[2], $parts[3])
}

try {
    $detected = $false
    $evidence = ''

    $required = ConvertTo-ComparableVersion '1.4.2.0'
    $path = [Environment]::ExpandEnvironmentVariables('C:\Program Files\Vendor\App\app.exe')

    if (Test-Path -LiteralPath $path -PathType Leaf) {
        # ProductVersionRaw is built from the numeric version resource, not the display string
        $installed = ConvertTo-ComparableVersion (Get-Item -LiteralPath $path).VersionInfo.ProductVersionRaw
        if ($null -ne $installed -and $installed -ge $required) {
            $detected = $true
            $evidence = "$path ProductVersion $installed"
        }
    }

    if ($detected) {
        Write-Output $evidence
        exit 0
    }

    # Not detected: no output, non-zero exit
    exit 1
}
catch {
    # Write nothing: any STDERR output makes Intune report the app as not installed
    exit 1
}

What IntuneManagementExtension.log expects

Exit codeSTDOUTResult
Exit 0Text on STDOUTDetected (installed)
Exit 0Empty STDOUTNot detected
Exit ≠ 0AnythingNot detected (script failed)
Exit 0Any STDERR textNot detected, even with STDOUT

Current IME builds log Win32 detection and requirement results to AppWorkload.log in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs; older builds write them to IntuneManagementExtension.log. ConfigMgr script detection uses the same STDOUT rule but reports a non-zero exit as Unknown.

Add the script to a Win32 app

  1. Pick the detection type and operator, then replace the example path, key, product code or version with the values from a device where the app is installed.
  2. Copy or download the script. The download is saved as UTF-8 with BOM, which Intune recommends for uploaded scripts.
  3. In the Intune admin center, open the Win32 app, go to Detection rules, choose "Use a custom detection script" and upload the file. For a requirement script, add it under Requirements > Script with output data type Boolean, operator Equals, value Yes.
  4. Leave "Run script as 32-bit process on 64-bit clients" at No unless you have a reason to change it. Registry reads in these scripts open an explicit registry view, so the result does not change either way.
  5. Prove the rule on a pilot device three times: not detected before install, detected after install, not detected after uninstall. Run the script as SYSTEM (for example with PsExec -s) to see what Intune sees.

32-bit, 64-bit and Sysnative

Most “installed but not detected” tickets come from looking in the wrong half of the registry. The Intune Management Extension launches install commands as a 32-bit process, so a reg.exe or powershell.exe call in the install command writes to HKLM\SOFTWARE\WOW6432Node unless it is called through %SystemRoot%\Sysnative\. A 32-bit MSI does the same by design.

The generated scripts open the registry with RegistryKey.OpenBaseKey and an explicit RegistryView, so the 32-bit toggle decides which view is read, not the bitness of the process Intune happens to start. MSI checks look in both Uninstall keys and never query Win32_Product, which runs a consistency check against every installed MSI.

Version checks pad each side to four parts before comparing, so a vendor that writes 1.4 to the registry still matches a required 1.4.0.0, and a [version] comparison never sorts 1.10 below 1.9 the way a string comparison does.