8 hours ago8 hr Most real software gets into Intune as a Win32 app. That covers EXE installers, MSIs with transforms, and anything that needs a script to do some work before or after setup. Building the package is the easy part. What actually breaks deployments is detection rules, install context and return codes, and usually you find out when someone opens a ticket saying the app they were promised never showed up. This is the process we follow, including the testing step that saves us the most time. Tools to grab first The Microsoft Win32 Content Prep Tool (IntuneWinAppUtil.exe) from Microsoft's GitHub. The installer and its silent install and uninstall switches. Check the vendor's documentation, or run it with /?. A test VM or spare PC, ideally with a snapshot you can roll back. Sysinternals PsExec, for testing as SYSTEM. Start with a clean source folder Put only what the install needs into one folder, like the installer, any transforms or config files, and an optional wrapper script. Everything in that folder ends up in the package, so don't point the tool at your Downloads folder. C:\Packaging\AcmeApp\Source\ AcmeApp-5.2.msi settings.xml Install.ps1 C:\Packaging\AcmeApp\Output\ Test the silent install as SYSTEM This is the step I'd never skip. Intune installs Win32 apps in SYSTEM context by default, and an installer that works fine when you double-click it can behave completely differently as SYSTEM. There's no user profile, no mapped drives and no HKCU. So test it the way Intune will run it. # Opens a PowerShell window running as SYSTEM (run from an elevated prompt) psexec.exe -s -i powershell.exe # In the SYSTEM window, confirm who you are, then run your exact install line whoami msiexec /i "C:\Packaging\AcmeApp\Source\AcmeApp-5.2.msi" /qn /norestart /l*v C:\Windows\Temp\AcmeApp-install.log $LASTEXITCODE Write down the exit code, then test the uninstall line the same way. If either one needs anybody to click anything, it'll hang in Intune until the timeout. Build the .intunewin .\IntuneWinAppUtil.exe -c "C:\Packaging\AcmeApp\Source" -s "AcmeApp-5.2.msi" -o "C:\Packaging\AcmeApp\Output" -q -c is the source folder, -s is the setup file (relative to the source folder), -o is the output folder, and -q is quiet mode. When the setup file is an MSI, the tool reads its metadata and Intune can prefill the product code for detection. Creating the app in Intune In the Intune admin center, add a Windows app of type "Windows app (Win32)," upload the .intunewin, and fill in the commands and behavior. Install command: msiexec /i "AcmeApp-5.2.msi" /qn /norestart, or for a wrapper, powershell.exe -ExecutionPolicy Bypass -File .\Install.ps1. Uninstall command: for an MSI, msiexec /x {PRODUCT-CODE-GUID} /qn. Install behavior: System or User. Use System unless the app installs per user into the profile. Device restart behavior: usually "Determine behavior based on return codes." The default return codes are 0 (success), 1707 (success), 3010 (soft reboot), 1641 (hard reboot) and 1618 (retry, another install in progress). Add any vendor-specific success codes your installer uses. If you don't, a perfectly good install gets reported as failed, and somebody burns an afternoon chasing it. Requirement rules decide who gets it Requirements decide whether the app even applies to a device. You can check OS architecture, minimum Windows version, disk space and RAM, and optionally add a file, registry or script check. If a requirement isn't met, the device reports "Not applicable" instead of failing. We use a script or file requirement to limit apps to a subset of devices, for example only machines with a marker file dropped by a department provisioning step. Detection rules, where most of the trouble lives Detection is how Intune decides whether the app is installed, right after the install runs and on every check after that. You've got four options. The MSI product code is the most reliable for MSIs, and you can check the version too. A file or folder rule checks that something exists, or compares the version or date on a specific file, for example C:\Program Files\Acme\acme.exe with version greater than or equal to 5.2. A registry rule checks that a key or value exists or matches, like the app's entry under the Uninstall key. Pay attention to the "associated with a 32-bit app on 64-bit clients" option, which controls whether Intune looks in the WOW6432Node view. A custom PowerShell script decides for itself. I reach for it when the other options can't express the condition. # Detection script: detected = exit 0 AND something written to STDOUT $exe = "C:\Program Files\Acme\acme.exe" if (Test-Path $exe) { $ver = [version](Get-Item $exe).VersionInfo.FileVersion if ($ver -ge [version]"5.2.0") { Write-Output "AcmeApp $ver detected" exit 0 } } exit 1 Pilot it Assign it as Required to a small device group, or as Available to a user group for Company Portal. Sync the test device and watch it. How we confirm it landed The app's device install status in Intune shows Installed, not "Failed" or "Not detected." The Intune Management Extension logs on the client tell you what actually ran. They live in C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\, and the ones I open are IntuneManagementExtension.log and AppWorkload.log. CMTrace or any log viewer that follows the file helps. If you included /l*v in the install line, the installer log has the rest. Where packages have gone wrong for us Script detection has to write to STDOUT and exit 0. A script that exits 0 but writes nothing counts as not detected. Write the result with Write-Output, and exit non-zero when the app is missing. This one is easy to forget. "Installed successfully but not detected" means the install worked and the detection rule is wrong. Usually it's the wrong registry view (32-bit vs 64-bit), a version string that doesn't compare the way you expect, or a path that differs on some machines. Depending on how the command is launched, a wrapper can end up running in 32-bit PowerShell, where System32 and the registry are redirected. If your script needs the 64-bit view, launch it explicitly with %windir%\Sysnative\WindowsPowerShell\v1.0\powershell.exe and test both paths. Interactive installers hang until the install timeout. Test in SYSTEM context and make sure nothing prompts. When a new version comes out, use supersedence instead of deploying two versions side by side with overlapping detection rules. When a deployment fails, I open AppWorkload.log before I change anything in the portal. It usually shows exactly what ran and what exit code came back.
Create an account or sign in to comment