Intune App Packaging – A Beginners Guide Part 1 – Win32

Intune is an excellent Application Deployment tool (amongst other things), but application packaging can be tricky at times and as with most things, there are many ways of packaging an app.

In this post, I will run through the options for packaging an application into Win32/IntuneWin format, detection methods, supersedence and filtering.

For part 2, I will look at the new MSIX packaging format.

Win32

Win32 applications are your traditional Executable/MSI apps which are then wrapped into intunewin format using the Win32AppGui tool from Microsoft (more on that below)

Folder Layout

Before we do any packaging, we need to keep our application source code neat and tidy so we can easily work out what’s what when we need to update that weird and wonderful application in 2 years time!

An IMPORTANT thing to note here is that the packaging tool will grab every file in the Source directory you point it to, so make sure that directory only has source files in it. If you point it at your Downloads folder for example, you’ll find yourself wondering why a 2Mb installer is showing as 45Gb when packaged!

This is entirely personal preference, but this folder layout works for me:

The source folder is the raw files, installer, config files etc.

Output is where we’ll store the intunewin file

The rest are pretty self-explanatory

Now for your installation options

Calling MSI/Exe Directly

If it’s a simple install, we could simply package up the MSI or Executable on it’s own and then in Intune set the install command to run the file.

msiexec.exe /i myinstaller.msi /qn
myinstaller.exe /silent

This is perfectly acceptable, but obviously doesn’t allow for any customisation pre or post install.

It’s also worth noting that if the MSI has been written to install in the User Context, Intune may force it to do the same and you’ll notice the context is greyed out. If you want one of these to install in the system context, you’ll either need to edit the MSI, or wrap it using a method below.

Batch Script

As much as I love Powershell, sometimes it’s easier to use a batch script for a simple installation. It could be you want to add/remove a reg key, stop a service or even just remove the shortcut from the application.

Simply create your installation batch script and when packaging, this is your install file.

For example:

rem Delete file
del c:\temp\myfile.txt


rem Stop Service
net stop myservice

rem Install App
my-installer.exe /verysilent /allusers /noreboot

rem Delete Shortcut
del %public%\desktop\myshortcut.lnk

A few handy hints if using a batch script:

In a command prompt type SET to get a list of variables on the machine. These can be referenced within % as I have done with the Public user environment %public%

If you want to reference the current directory, use %~dp0 but DON’T add a backslash:

%~dp0myinstaller.exe

Within Intune, simply set your install command to “install.bat” or whatever you have called your batch script.

Powershell Script

Powershell scripts take installation one step further as you have greater control over the machine (and for something complex it is just easier). You can put logic in, look at the underlying hardware, anything is available at this point.

I have a wrapped template available on Github here to get you started

As an example, for an MSI:

    $MSIArguments = @(
    "/i"
    ('"{0}"' -f $filelocation)
    "/qn"
    "/norestart"
    "/L*v"
)
Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow 

Of course, when using Powershell you can also add/remove features for apps which don’t have an MSI

Using DotNet as an example (packaged here):

Enable-WindowsOptionalFeature -Online -FeatureName 'NetFx3' -Source .\sxs\ -NoRestart -LimitAccess

The installation command within intune would be:

powershell.exe -ExecutionPolicy Bypass -file myinstaller.ps1

PSADT

PowerShell Application Deployment Toolkit (PSADT) is a very powerful tool which leverages Powershell but gives many built-in functions to take it one step further.

For example, you could check if applications are running and prompt for the user to close them, you could run a particular file in the user context and have the rest in the system context, or add pre/post install commands.

A full list of the functions are here

NOTE: If deploying via Intune and you want user interaction, you’ll need to use the ServiceUI executable from the MDT Toolkit. To save you a job, I have it here

I often use PSADT for deploying office applications and updates as it gives the option to prompt the users to close any apps they may have open. For example, MS Project (just the key parts, the whole ps1 can be found here):

    Show-InstallationWelcome -CloseApps 'excel,groove,onenote,outlook,mspub,powerpnt,winword,iexplore,teams,visio,winproj' -CheckDiskSpace -PersistPrompt		

		## Show Progress Message (with the default message)
		Show-InstallationProgress
		
		## <Perform Pre-Installation tasks here>
		
		
		##*===============================================
		##* INSTALLATION 
		##*===============================================
		[string]$installPhase = 'Installation'
		
		## Handle Zero-Config MSI Installations
		If ($useDefaultMsi) {
			[hashtable]$ExecuteDefaultMSISplat =  @{ Action = 'Install'; Path = $defaultMsiFile }; If ($defaultMstFile) { $ExecuteDefaultMSISplat.Add('Transform', $defaultMstFile) }
			Execute-MSI @ExecuteDefaultMSISplat; If ($defaultMspFiles) { $defaultMspFiles | ForEach-Object { Execute-MSI -Action 'Patch' -Path $_ } }
		}
		
		## <Perform Installation tasks here>
		Execute-Process -Path "$dirFiles\setup.exe" -Parameters "/CONFIGURE InstallO365withProject.xml"
		
		##*===============================================
		##* POST-INSTALLATION
		##*===============================================
		[string]$installPhase = 'Post-Installation'
		
		## <Perform Post-Installation tasks here>
		
		## Display a message at the end of the install
		If (-not $useDefaultMsi) { Show-InstallationPrompt -Message 'Installation has been completed. You will find Project in the All Programs section.' -ButtonRightText 'OK' -Icon Information -NoWait }
	}

Deploying a PSADT packaged application, for user interaction, the install command would be:

.\ServiceUI.exe -Process:explorer.exe Deploy-Application.exe

Uninstall

We will of course need an uninstall command as well.

You can use any of the options above, but just make sure to include it when packaging the application or you’ll have problems if you need to remove it in the future.

Packaging the app

Now we have our source files and installer, we need to package it using the IntuneWinAppUtil from Microsoft.

This takes the source files, encrypts and compresses them and gives us our intunewinfile

First we load the application (for ease, I’m just using 7-Zip) and we’ll be presented with this screen:

Point it to the source folder:

Point it to the Installer (msi, batch, PS1 or PSADT)

And finally, tell it where to put the intunewin

Detection

Before adding to Intune, it is worth grabbing the detection type so it knows the install has completed correctly. I usually install into a Sandbox and then have a look around, but if it’s an MSI, you can quickly grab the product code using this powershell script:

$path = "PATH TO MSI"

$comObjWI = New-Object -ComObject WindowsInstaller.Installer
$MSIDatabase = $comObjWI.GetType().InvokeMember("OpenDatabase","InvokeMethod",$Null,$comObjWI,@($Path,0))
$Query = "SELECT Value FROM Property WHERE Property = 'ProductCode'"
$View = $MSIDatabase.GetType().InvokeMember("OpenView","InvokeMethod",$null,$MSIDatabase,($Query))
$View.GetType().InvokeMember("Execute", "InvokeMethod", $null, $View, $null)
$Record = $View.GetType().InvokeMember("Fetch","InvokeMethod",$null,$View,$null)
$Value = $Record.GetType().InvokeMember("StringData","GetProperty",$null,$Record,1)


write-host "Your MSI code is $Value" -ForegroundColor Green

This will output the MSI code you can use for both detection and uninstall

Adding to Intune

Now we have our application package, we need to add it to Intune:

Navigate to https://endpoint.microsoft.com and then select Apps – Windows

Click Add and Select Win32:

Select your IntuneWin and populate any fields on this page. You can also add your icon at the bottom to appear in Company Portal

Click Next

Enter your install and uninstall commands established earlier, whether that is a script, or calling directly:

Here you can select the install context (unless it is a hard-coded MSI as discussed earlier)

Click Next

Add any app requirements (64-bit for example). I also usually add the earliest supported Windows OS version here, we don’t want unsupported versions so it’s another reason for them to call for help

You can also add a requirement rule to check if the app exists (for updates). Read about those here

If you want to try a Requirements Script, read about those here

Click Next

Here you add your detection rule from earlier (or a custom script, read about those here)

Click Next

If the application requires something else to be installed first, add that here. You can also specify whether to force an install if it is missing. This is useful if you have a plugin for office, or an application which needs both System and User context sections so can be split into two apps:

Click Next

The next screen gives Supersedence options. If this is an updated application, select the previous version and you can tell it whether to in-place upgrade or remove and re-install. Whilst in preview, it works well and I would definitely recommend using it

Click Next

Add any scope tags as needed (read about those here)

Click Next

Now assign the application (read more about the different intents here)

It’s also worth looking at filtering at this point, you can read about that here

Finally Click Next

And then Create

Congratulations! You have now packaged and deployed your first Intune application!

Posted in Intune