MSEndpointMgr

Manage Win32 applications in Microsoft Intune with PowerShell

For Microsoft Intune, the capability to deploy applications which have more advanced setup installers such as MSI setups with multiple files and executable based installers, more commonly referred to as Win32 applications, has since it’s release been an enormous enabler for the modern management scenario. For a long time, not having this capability with Intune was considered a deal-breaker. Going forward in time, we have now had this capability for some time, and it’s being enhanced several times since it’s release with new features.

One thing that has not been touched much about since the release of this feature, is how one could automate the creation of a Win32 app-type in Intune. Some time ago now, Dave Falkus published a sample script in the official PowerShell script GitHub repository maintained by Microsoft, that touched on the subject. With the help of this sample script, I got inspired to take it to the next level and turn it into a PowerShell module that would make it as easy as possible to manage Win32 apps in Intune, which is what this blog post is all about.

Think about this, wouldn’t it be pretty cool if you could run a small, let’s call it a ‘template-script’, after each time Adobe releases a new version of Adobe Reader DC (as an example) that downloads, packages the setup as an .intunewin file and creates a new Win32 app in Intune that then get’s assigned to your users, all of this completely automated? Let’s see if we can make that happen.

Introducing IntuneWin32App PowerShell module

This module was originally created to provide means to automate every aspect of management in terms of Win32 apps in Intune, from packaging, application creation and publishing of Win32 apps in Microsoft Intune.

Let’s start with how to get your hands on the IntuneWin32App PowerShell module. From any Windows-based system that includes PowerShell with it’s built-in package management system, open an elevated PowerShell console and run the following command:

Install-Module -Name IntuneWin32App

If this is the first time you install a module or script from the official PowerShellGallery repository, you’ll be prompted to trust the repository and few other things. Along with installing the IntuneWin32App module, the following two modules will also be installed automatically, as they are dependency modules:

  • PSIntuneAuth
    • This module is required for handling the authentication pieces for all functions included in the IntuneWin32App module
  • AzureAD
    • This module is required for the PSIntuneAuth module, as it will ensure the required authentication libraries are present on the system

What can you do with the IntuneWin32App module

As of writing this blog post, a few iterations of the IntuneWin32App module have already been made available publicly, where some of  them being bug fixes but also new features introduced. The goal with the module is to bring all the supported Win32 app capabilities that’s available in the portal into it. Currently, the module includes function for the following operations:

  • Get-IntuneWin32App
  • Get-IntuneWin32AppMetaData
  • Add-IntuneWin32App
  • Add-IntuneWin32AppAssignment
  • New-IntuneWin32AppPackage
  • New-IntuneWin32AppDetectionRule
  • New-IntuneWin32AppReturnCode
  • New-IntuneWin32AppIcon
  • Expand-IntuneWin32AppPackage

This blog post will not cover each function in details and how they can be used, since it’s already available in the documentation for the IntuneWin32App module, available here:

https://github.com/MSEndpointMgr/Intune/tree/master/Modules/IntuneWin32App

Example on how to use the IntuneWin32App module

Let’s take a look at an example, like discussed earlier in this post, on how this module can be used to automate relative simple but time consuming tasks. Our example was to download and package the latest Adobe Reader DC application as an .intunewin package and then create a Win32 application in Intune. Below is a break out of the various parts of such a script that describes the various tasks involved. At the end of this post, you’ll find the whole example script for your convenience.

But before we look at any of the code in the example script, a way to determine the latest available setup installer for Adobe Reader DC is required. While writing the post, I originally had written a small function that leveraged the PSFTP module available in the PSGallery. Even though the functions in that module provided me with exactly what was needed, it for some reason broke the PowerShellGet module (really the Install-Module, Update-Module, Find-Module etc. cmdlets) and I didn’t feel that I wanted to dig deep into why that occurred. Instead I decided to borrow some of regex patterns and datetime parsing from the PSFTP module and write my own script with the sole purpose returning the latest available setup information for Adobe Reader DC.

To install this script, simply open an elevated PowerShell prompt and run the following command:

Install-Script -Name Get-LatestAdobeReaderInstaller

Download Adobe Reader DC

First off we set a few variables that will be used later on in the example script. These variables are pretty self-explanatory but I’ve provided some additional help text in the code in case you’re uncertain.

# Amend these variables
$TenantName = "tenantname.onmicrosoft.com"
$Publisher = "SCConfigMgr"
$SourceFolderRoot = "C:\IntuneWinAppUtil\Source\AdobeReader" # This is the root folder where Adobe Reader DC will be downloaded into a sub-folder that's named after the setup version
$OutputFolder = "C:\IntuneWinAppUtil\Output" # This is the folder where the packaged .intunewin file will be created in

Next we want to retrieve the latest Adobe Reader DC setup information, so that we can process it and pass that data to the next part where we’re going to take care of downloading the setup installer. Here we call the Get-LatestAdobeReaderInstaller.ps1 script that we installed previously and specify that we want the executable installer and not the latest patch that’s available.

# Retrieve information for latest Adobe Reader DC setup
$AdobeReaderSetup = Get-LatestAdobeReaderInstaller.ps1 -Type EXE -Language en_US

With this information at hand, we construct the download folder and the file name inside of the download folder. In case the download folder doesn’t exist, it’s automatically created. Final step in this phase is to invoke the actual download using the System.Net.WebClient class and the method of DownloadFile.

# Define download folder and file paths
$DownloadDestinationFolderPath = Join-Path -Path $SourceFolder -ChildPath $AdobeReaderSetup.SetupVersion
$DownloadDestinationFilePath = Join-Path -Path $DownloadDestinationFolderPath -ChildPath $AdobeReaderSetup.FileName

# Create version specific folder if it doesn't exist
if (-not(Test-Path -Path $DownloadDestinationFolderPath)) {
    New-Item -Path $DownloadDestinationFolderPath -ItemType Directory -Force | Out-Null
}

# Download the Adobe Reader setup file, this generally takes a while
$WebClient = New-Object -TypeName System.Net.WebClient
$WebClient.DownloadFile($AdobeReaderSetup.URL, $DownloadDestinationFilePath)

NOTE – The download speed from the Adobe FTP is somewhat sluggish and it could take some time for the setup file to be fully downloaded.

Package Adobe Reader DC as a Win32 app package

At this point the Adobe Reader DC setup installer has been downloaded. Next step would be to package it together into an .intunewin file before it can be uploaded to Intune. Usually, at this point in time the normal procedure would be to manually download the IntuneWinAppUtil.exe from the official github page (unless it’s already been downloaded previously), figure out the relatively easy parameters the utility has and then invoke it. However, the IntuneWin32App module simplifies this for you by providing a function that’s called New-IntuneWin32AppPackage. With this function it’s as easy as the code block below to package the Adobe Reader DC setup installer into the require file format:

$IntuneWinFile = New-IntuneWin32AppPackage -SourceFolder $DownloadDestinationFölderPath -SetupFile $AdobeReaderSetup.FileName -OutputFolder $OutputFolder -Verbose

As shown above, we use the destination folder path from where the Adobe Reader DC setup installer was downloaded to as the SourceFolder parameter input together with the downloaded setup file name and the output folder originally specified. This function will also automatically download the IntuneWinAppUtil.exe utility into the temp folder of the current user in case it can’t detect it, before starting the packaging process. Once packaged, the output from the function is stored into a variable as the full path to the .intunewin file will be required later on.

Construct Win32 app prerequisites

Before the main function within the IntuneWin32App module, the Add-IntuneWin32App function, is invoked a few objects needs to be created that it depends on. In this case, since the Adobe Reader DC setup installed is an .exe setup application (even though it might contain an actual MSI installer wrapped inside), the Intune Management Extension requires us to create an EXE-based Win32 app, as it would not work if we tried to use msiexec to kick of the installation on the client with an .exe installer. Therefor, to automate this, it’s required to figure out all the prerequisite information that should be passed to the Add-IntuneWin32App function.

First, let’s format a desired name for the Win32 application, as shown below.

# Create custom display name like 'Name' and 'Version'
$DisplayName = "Adobe Reader DC" + " " + $AdobeReaderSetup.SetupVersion

Secondly, the Win32 app needs to have a detection rule. Different from the what’s stated earlier regarding the Adobe Reader DC setup installer being an .exe setup application, it’s actually an MSI installed wrapped into the .exe. Therefor, it would make sense to make use of the built-in logic of detecting MSI based installed applications using the ProductCode and ProductVersion properties. As it turns out from a quick research, it seems that the ProductCode for Adobe Reader DC stays the same after each new release (it may be different between 2015, 2017 versions and so on, something I’ve not verified though), so we can leave that static and focus on dynamically adding the ProductVersion property instead as shown below in the code snippet. To create the required output object for the Add-IntuneWin32App function, we make use of the New-IntuneWin32AppDetectionRule function

# Create detection rule using the en-US MSI product code (1033 in the GUID below correlates to the lcid)
$DetectionRule = New-IntuneWin32AppDetectionRule -MSI -MSIProductCode "{AC76BA86-7AD7-1033-7B44-AC0F074E4100}" -MSIProductVersionOperator greaterThanOrEqual -MSIProductVersion $AdobeReaderSetup.SetupVersion

Next, a default requirement rule object that allows the Win32 app to be installed on any architecture (x64 and x86) on a Windows 10 device that’s running a minimum version of 1607 is constructed using the New-IntuneWin32AppDetectionRule function.

# Create custom requirement rule
$RequirementRule = New-IntuneWin32AppRequirementRule -Architecture All -MinimumSupportedOperatingSystem 1607

Finally, before the Win32 app can be created, why not add a good looking icon to the app as well. In this example I’ve retrieved an icon for Adobe Reader online and stored it locally. Using the New-IntuneWin32AppIcon function, the image-file can be Base64 encoded easily which is required for the Add-IntuneWin32App function.

# Convert image file to icon
$ImageFile = "C:\IntuneWinAppUtil\Icons\AdobeReader.png"
$Icon = New-IntuneWin32AppIcon -FilePath $ImageFile

Create Adobe Reader DC Win32 app

All we’ve done up until this point have been to prepare for using the Add-IntuneWin32App function. Before the function is called though, two additional variables are required, the $InstallCommandLine and $UninstallCommandLine ones. Since the Add-IntuneWin32App function will be called in an EXE-based (the same context for a PowerShell script based installer) parameter set context, InstallCommandLine and UninstallCommandLine parameters are required additionally from the other context of being MSI-based. A part from these parameters, everything is at this point coming together, the display name of the Win32 app, the tenant name used for authentication the operating that’s going to take place and especially all the objects created by the other functions.

# Add new EXE Win32 app
$InstallCommandLine = "$($AdobeReaderSetup.FileName) /sAll /rs /rps /l"
$UninstallCommandLine = "msiexec.exe /x {AC76BA86-7AD7-1033-7B44-AC0F074E4100} /qn"
Add-IntuneWin32App -TenantName $TenantName -FilePath $IntuneWinFile.Path -DisplayName $DisplayName -Description "Adobe Reader DC" -Publisher $Publisher -InstallExperience system -RestartBehavior suppress -DetectionRule $DetectionRule -RequirementRule $RequirementRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine -Icon $Icon -Verbose

When this function is invoked, depending on your current logged on credentials and what permissions that user has in Intune, it could be that you’d require to specify a different user account that has the necessary permissions required. If that’s the case, to the above function, add the PromptBehavior parameter with the value of Always. This will always force the authentication process to prompt for credentials.

Assign Adobe Reader DC Win32 app

Now that the Win32 app for Adobe Reader DC has been created in Intune, the last thing to do is to assign it somehow. In the example code below we’re creating an available assignment for the app in question to All Users.

# Create an available assignment for all users
Add-IntuneWin32AppAssignment -TenantName $TenantName -DisplayName $DisplayName -Target "AllUsers" -Intent "available" -Verbose

As an end result, in the Intune portal you’ll end up with a Win32 app that looks similar to this:

Summary

Although that this blog post cover basically every aspect there is to dynamically create the latest version of Adobe Reader DC as a Win32 app in Microsoft Intune, this should not be considered a complete application life-cycle management script that’s production ready straight as it is. You’d need to consider adding in cleaning up of older versions, removing downloaded files and other tasks that’s not covered in this post, not to mention custom MST files for a customized setup and end user experience of the application after it has been installed.

I hope this has given you an idea of what can be accomplished with the new IntuneWin32App module.

Below you’ll find the complete example script code for your convenience:

# Install required script
Install-Script -Name Get-LatestAdobeReaderInstaller

# Amend these variables
$TenantName = "tenantname.onmicrosoft.com"
$Publisher = "SCConfigMgr"
$SourceFolderRoot = "C:\IntuneWinAppUtil\Source\AdobeReader" # This is the root folder where Adobe Reader DC will be downloaded into a sub-folder that's named after the setup version
$OutputFolder = "C:\IntuneWinAppUtil\Output" # This is the folder where the packaged .intunewin file will be created in

# Retrieve information for latest Adobe Reader DC setup
$AdobeReaderSetup = Get-LatestAdobeReaderInstaller.ps1 -Type EXE -Language en_US

# Define download folder and file paths
$DownloadDestinationFolderPath = Join-Path -Path $SourceFolderRoot -ChildPath $AdobeReaderSetup.SetupVersion
$DownloadDestinationFilePath = Join-Path -Path $DownloadDestinationFolderPath -ChildPath $AdobeReaderSetup.FileName

# Create version specific folder if it doesn't exist
if (-not(Test-Path -Path $DownloadDestinationFolderPath)) {
    New-Item -Path $DownloadDestinationFolderPath -ItemType Directory -Force | Out-Null
}

# Download the Adobe Reader setup file, this generally takes a while
$WebClient = New-Object -TypeName System.Net.WebClient
$WebClient.DownloadFile($AdobeReaderSetup.URL, $DownloadDestinationFilePath)

# Create .intunewin package file
$IntuneWinFile = New-IntuneWin32AppPackage -SourceFolder $DownloadDestinationFolderPath -SetupFile $AdobeReaderSetup.FileName -OutputFolder $OutputFolder -Verbose 

# Create custom display name like 'Name' and 'Version'
$DisplayName = "Adobe Reader DC" + " " + $AdobeReaderSetup.SetupVersion

# Create detection rule using the en-US MSI product code (1033 in the GUID below correlates to the lcid)
$DetectionRule = New-IntuneWin32AppDetectionRule -MSI -MSIProductCode "{AC76BA86-7AD7-1033-7B44-AC0F074E4100}" -MSIProductVersionOperator greaterThanOrEqual -MSIProductVersion $AdobeReaderSetup.SetupVersion

# Create custom requirement rule
$RequirementRule = New-IntuneWin32AppRequirementRule -Architecture All -MinimumSupportedOperatingSystem 1607

# Convert image file to icon
$ImageFile = "C:\IntuneWinAppUtil\Icons\AdobeReader.png"
$Icon = New-IntuneWin32AppIcon -FilePath $ImageFile

# Add new EXE Win32 app
$InstallCommandLine = "$($AdobeReaderSetup.FileName) /sAll /rs /rps /l"
$UninstallCommandLine = "msiexec.exe /x {AC76BA86-7AD7-1033-7B44-AC0F074E4100} /qn"
Add-IntuneWin32App -TenantName $TenantName -FilePath $IntuneWinFile.Path -DisplayName $DisplayName -Description "Adobe Reader DC" -Publisher $Publisher -InstallExperience system -RestartBehavior suppress -DetectionRule $DetectionRule -RequirementRule $RequirementRule -InstallCommandLine $InstallCommandLine -UninstallCommandLine $UninstallCommandLine -Icon $Icon -Verbose

# Create an available assignment for all users
Add-IntuneWin32AppAssignment -TenantName $TenantName -DisplayName $DisplayName -Target "AllUsers" -Intent "available" -Verbose

Nickolaj Andersen

Chief Technical Architect and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences such as Microsoft Ignite, NIC Conference and IT/Dev Connections including nordic user groups.

Add comment

Sponsors

Categories

MSEndpointMgr.com use cookies to ensure that we give you the best experience on our website.