A Manufacturing Line for Microsoft 365 Apps in Intune Utilizing PowerShell and GitHub Actions for the automated packaging of Microsoft 365 Apps, and their importation into an Intune tenant.

Deploying Microsoft 365 Apps through Microsoft Intune is as straightforward as using the built-in tools to create a package without the need for manual packaging of any binaries.

This strategy is highly efficient for new devices, especially PCs deployed via Windows Autopilot. However, there are certain difficulties associated with the built-in package solution.

The Issue

The built-in Microsoft 365 Apps package doesn’t consistently update older versions of Microsoft Office. At Insentra, we’ve encountered issues with unsuccessful deployments due to a failure in the package upgrading over existing Microsoft Office installations in several customer environments.

Additionally, the built-in Microsoft 365 Apps package cannot be used as a dependency by another Win32 application package (for example, ensuring the Microsoft 365 Apps is installed before an add-in package is installed).

If your environment experiences upgrade issues or you need to use the Dependencies feature, you’ll need to construct a custom Win32 application package to deploy the Microsoft 365 Apps.

For smaller environments, creating a custom package could be a one-off action. The package can be manually constructed. However, for larger environments where you might have to create multiple packages and possibly have a team of engineers creating packages. This could be in-house engineers, or consultant or managed services engineers working across multiple customer environments. In these environments, it’s crucial to maintain consistency across multiple packages – without packages built to a common standard, your devices could experience inconsistent deployments and you’ll spend more time troubleshooting issues.

How do we ensure standardization and a straightforward method for creating Microsoft 365 Apps packages? With automation, of course.

Deconstructing a Microsoft 365 Apps Win32 Package [Permalink] Let’s begin by exploring what should be incorporated in a custom Microsoft 365 Apps Win32 package:

  • A configuration.xml that delineates the Microsoft 365 Apps package. Generate the configuration XML files in the Office Customization Tool
  • An uninstall.xml that outlines the removal of the Microsoft 365 Apps from a target PC
  • setup.exe from the Office Deployment Tool. This will process the configuration.xml and the uninstall.xml to install or uninstall the Microsoft 365 Apps
  • A detection method for Intune to ascertain whether the application is installed. Microsoft lists the existence of the HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\O365ProPlusRetail – en-us registry key in the documentation; however, this is a very basic approach and you may want instead use registry keys or values unique to your package. The registry key HKLM\SOFTWARE\Microsoft\Office\ClickToRun\Configuration includes several values useful for detection rules.
  • For upgrade scenarios, Microsoft provides scripts that are useful for uninstalling and cleaning up older versions of Microsoft Office. These VBScripts yield a more consistent result than relying on the Office Deployment Tool to complete the uninstall and upgrade.
  • Lastly, encasing the installation package with the PSAppDeployToolkit provides additional install logic and management, especially for in-place upgrades on existing devices.

The Solution

To address this challenge, I’ve developed a PowerShell packaging assembly line for Microsoft 365 Apps and Microsoft Intune, that can be executed locally or via GitHub Actions.

The Microsoft 365 Apps packager repository is comprised of the following:

  • New-Microsoft365AppsPackage.ps1 – This is the central script that generates and imports a Microsoft 365 Apps package into Intune. The script can be run on a Windows machine in a copy of the repository or via GitHub Actions (if you clone the repository).
  • Create-Win32App.ps1 imports the intunewin package into the target Intune tenant, using App.json as the blueprint. This script employs the IntuneWin32App PowerShell module and is invoked by New-Microsoft365AppsPackage.ps1 to import the package into an Intune tenant.
  • Template Microsoft 365 Apps deployment configurations – deployment configurations are established in the Microsoft 365 Apps admin center, but every organization is going to deploy a similar configuration, so these templates should be suitable for most common deployments.
  • A GitHub workflow that employs New-Microsoft365AppsPackage.ps1 to package the Microsoft 365 Apps on a GitHub hosted runner – the workflow can import the package into an Intune tenant. It also uploads the created Microsoft 365 Apps package as a workflow artifact for manual importation into Intune.


New-Microsoft365AppsPackage.ps1 must be executed on a supported Windows version, and it has been written for PowerShell 5.1. Parameters for New-Microsoft365AppsPackage.ps1 are:

Parameter Description Required
Path Path to the top level directory of the m365apps repository on a local Windows machine. No
ConfigurationFile Complete path to the Microsoft 365 Apps package configuration file. Specify the full path to a configuration file included in the repository or the path to an external configuration file. Yes
Channel A supported Microsoft 365 Apps release channel. No. Defaults to MonthlyEnterprise
CompanyName Company name to include in the configuration.xml. No. Defaults to stealthpuppy
TenantId The tenant id (GUID) of the target Azure AD tenant. Yes
ClientId The client id (GUID) of the target Azure AD app registration. No
ClientSecret Client secret used to authenticate against the app registration. No
Import Switch parameter to specify that the package should be imported into the Microsoft Intune tenant. No


PowerShell Modules

These PowerShell modules are necessary:

If you’re running the packager locally, install the modules with:

Install-Module -Name Evergreen, MSAL.PS, IntuneWin32App -SkipPublisherCheck

Configuration Files

Microsoft 365 Apps configuration files are included in the repository – these files can be used to create packages for any target tenant as some key options will be dynamically updated by New-Microsoft365AppsPackage.ps1.

  • O365BusinessRetail.xml – Configuration file for Microsoft 365 Apps for business
  • O365BusinessRetail-VDI.xml – Configuration file for Microsoft 365 Apps for business with shared licensing enabled, and OneDrive and Teams excluded
  • O365ProPlus.xml – Configuration file for Microsoft 365 Apps for enterprise
  • O365ProPlus-VDI.xml – Configuration file for Microsoft 365 Apps for enterprise with shared licensing enabled, and OneDrive and Teams excluded
  • O365ProPlusVisioProRetailProjectProRetail.xml – Configuration file for Microsoft 365 Apps for enterprise, Visio, and Project
  • O365ProPlusVisioProRetailProjectProRetail-VDI.xml – Configuration file for Microsoft 365 Apps for enterprise, Visio, and Project with shared licensing enabled, and OneDrive and Teams excluded
  • Uninstall-Microsoft365Apps.xml – A configuration that will uninstall all Microsoft 365 Apps

When the package is generated, the following properties will be updated:

  • Company Name – this is the organization name that sets the Company property on Office documents
  • Tenant Id – the target Azure AD tenant ID
  • Channel – the Microsoft 365 Apps update channel

Using the Packager

If you’re looking to download and use the Packager locally, follow these steps:

Clone the Repository

If you’re not familiar with cloning a repository, use GitHub Desktop to clone the repository and keep your local copy up to date with changes to the source repository.

Usage via Administrator Sign-in

Use New-Microsoft365AppsPackage.ps1 by authenticating with an Intune Administrator account before running the script. Run Connect-MSIntuneGraph to authenticate with administrator credentials using a sign-in window or device login URL.

Connect-MSIntuneGraph -TenantID “lab.stealthpuppy.com” $params = @{ Path = “E:\project\m365apps” ConfigurationFile = “E:\project\m365apps\configs\O365ProPlus.xml” Channel = “Current” CompanyName = “stealthpuppy” TenantId = “6cdd8179-23e5-43d1-8517-b6276a8d3189” Import = $true } .\New-Microsoft365AppsPackage.ps1 @params

When New-Microsoft365AppsPackage.ps1 has successfully completed, the package\output folder will contain the setup.intunewin package, a copy of the configuration XML file in the package, and m365apps.json that is used by Create-Win32App.ps1 to import the package into Intune.

If -Import is specified when running New-Microsoft365AppsPackage.ps1, a standardized Microsoft 365 Apps package will be imported into the target Intune tenant.

Should the -Import not be detailed, you can manually or via running Create-Win32App.ps1, incorporate the package into Intune:

$params = @{ Json = “E:\project\m365apps\output\m365apps.json” PackageFile = “E:\project\m365apps\output\setup.intunewin” } & “E:\project\m365apps\scripts\Create-Win32App.ps1” @params

Implementing through App Registration

You can utilize New-Microsoft365AppsPackage.ps1 to generate a new package by giving credentials to an Azure AD app registration (see below) that’s authorized to integrate applications into Microsoft Intune:

$params = @{ Path = “E:\project\m365Apps” ConfigurationFile = “E:\project\m365Apps\configs\O365ProPlus.xml” Channel = “MonthlyEnterprise” CompanyName = “stealthpuppy” TenantId = “6cdd8179-23e5-43d1-8517-b6276a8d3189” ClientId = “60912c81-37e8-4c94-8cd6-b8b90a475c0e” ClientSecret = “<secret>” Import = $true } .\New-Microsoft365AppsPackage.ps1 @params

Automatization of the Packager

The Microsoft 365 Apps Packager can be automated in various ways. However, the repository includes a method based on workflows and GitHub Actions. To utilize this strategy, you’ll need to fork the repository and configure it in your own GitHub account.

To read the rest of the article, click on the banner below.

Blog Banner Aaron Parker