Intune allows to automatically have software installed on target devices. I found a nice write-up on using this in conjunction with Chocolatey, but realized it could be made much easier. First we’ll prepare the files locally which needs to be done only once, instead of for each application.

Prepare Chocolatey

The following steps depend on Chocolatey, so first follow the previously mentioned write-up on how to install that through Intune.

The one .intunewin to install them all

Save the script below as install.ps1 in an empty directory, and download IntuneWinAppUtil.exe into that directory as well.

    [string]$package = "",
    [switch]$uninstall = $false

if ($uninstall) {
    choco uninstall $package -y
} else {
    choco upgrade $package -y

upgrade will install the package if it isn’t yet installed. Two fish.

You can use this script directly by running ./install.ps1 <package name> [-uninstall]. We’ll use Intune to automate installation of packages.

Now let’s create a generic .intunewin file for all our Chocolatey apps. In the directory run the following in Powershell:

.\IntuneWinAppUtil.exe -c .\ -s install.ps1 -o .\

This creates an .intunewin file which we can re-use in Intune for each application we wish to install using Chocolatey.

Creating an Intune app

When creating an Intune app, set it as a Windows app (Win32) and during the wizard set the install command to

powershell.exe -executionpolicy bypass .\install.ps1 <package name>

And the uninstall command to

powershell.exe -executionpolicy bypass .\install.ps1 <package name> -uninstall


We can also use Chocolatey to detect our package. For this we just check using choco.exe if the app exists locally. For that, create the following script and save it as <package-name>.ps1.

choco feature enable --name="'useEnhancedExitCodes'" -y
$ScriptFilename = $MyInvocation.MyCommand.Name
$PackageName = $ScriptFilename -replace ".ps1"
choco list -e $PackageName --local-only

Set the detection rules format to Use a custom detection script, and upload the just created script. Make sure Enforce script signature check and run script silently is set to No.

The above script does some fancy things:

  1. It enables the useEnhancedExitCodes feature, which ensures the exit code is 2 when the package doesn’t exist. Else it will return 0 because it had no issues checking that the package didn’t exist. This setting just needs to be set once, but we place it here to always be sure it is enabled.
  2. It retrieves the filename without the extension. This way you don’t need to modify the script, but can see using the filename which package it will check for. Less prone to mistakes. You can replace the second and third line with $PackageName = <package-name> if you do want to place the name in the script.
  3. --local-only ensures it uses the local index of apps, else it will always return true because the package exists in the Chocolatey repository.


Finally, make sure to set Chocolatey as a dependency.