Automating Project and Visio installs with Dynamic Groups

Licensed software can be a pain, especially with manual user assignment and then deployment.

Fortunately for MS Project and MS Visio it can be automated so users can automatically receive Visio and Project upon being given a license and if you revoke the license, it can automatically uninstall.

Better still, the group creation can be scripted (and who doesn’t love a script!)

In this post I’ll run through both creating the groups via script and also deploying the apps themselves (manually, or fully scripted)

Fully Scripted Deployment

This script will create your Entra ID groups (as described below) and using the Microsoft Graph Powershell samples from Microsoft will create your Microsoft Project and Visio Applications, upload the intunewin file (again described below) and deploy to Intune with the Entra ID groups assigned.

The script is long so I’m not going to run through it line by line, but you can grab a copy here

Manual Option (app deployment)

Let’s start with the script which can be found here

As with my Autopilot script, this uses the Graph module which we need to look for and install first:

#Install MS Graph if not available
if (Get-Module -ListAvailable -Name Microsoft.Graph) {
  Write-Host "Microsoft Graph Already Installed"
} 
else {
  try {
      Install-Module -Name Microsoft.Graph -Scope CurrentUser -Repository PSGallery -Force 
  }
  catch [Exception] {
      $_.message 
      exit
  }
}

As you can see, it’s using the Current User scope to avoid any issues if you don’t have admin rights

Now we need to import the module

import-module -Name microsoft.graph

And connect to Graph

Select-MgProfile -Name Beta
Connect-MgGraph -Scopes Group.ReadWrite.All, GroupMember.ReadWrite.All, openid, profile, email, offline_access

Now we create the groups, these use the service plan IDs from Azure:

Project: fafd7243-e5c1-4a3a-9e40-495efcb1d3c3

Visio: 663a804f-1c30-4ff0-9915-9db84f0d1cea

So, to create a group of licensed Visio users we need to look for that plan and make sure it’s enabled:

New-MGGroup -DisplayName "Visio-Install" -Description "Dynamic group for Licensed Visio Users" -MailEnabled:$False -MailNickName "visiousers" -SecurityEnabled -GroupTypes "DynamicMembership" -MembershipRule "(user.assignedPlans -any (assignedPlan.servicePlanId -eq ""663a804f-1c30-4ff0-9915-9db84f0d1cea"" -and assignedPlan.capabilityStatus -eq ""Enabled""))" -MembershipRuleProcessingState "On"

For the uninstall group, we’re just looking for anyone who doesn’t have the plan:

New-MGGroup -DisplayName "Visio-Uninstall" -Description "Dynamic group for users without Visio license" -MailEnabled:$False -MailNickName "visiouninstall" -SecurityEnabled -GroupTypes "DynamicMembership" -MembershipRule "(user.assignedPlans -all (assignedPlan.servicePlanId -ne ""663a804f-1c30-4ff0-9915-9db84f0d1cea"" -and assignedPlan.capabilityStatus -ne ""Enabled""))" -MembershipRuleProcessingState "On"

Same for Project with both install and uninstall, just with the new service plan ID:

New-MGGroup -DisplayName "Project-Install" -Description "Dynamic group for Licensed Project Users" -MailEnabled:$False -MailNickName "projectinstall" -SecurityEnabled -GroupTypes "DynamicMembership" -MembershipRule "(user.assignedPlans -any (assignedPlan.servicePlanId -eq ""fafd7243-e5c1-4a3a-9e40-495efcb1d3c3"" -and assignedPlan.capabilityStatus -eq ""Enabled""))" -MembershipRuleProcessingState "On"

$projectuninstall = New-MGGroup -DisplayName "Project-Uninstall" -Description "Dynamic group for users without Project license" -MailEnabled:$False -MailNickName "projectuninstall" -SecurityEnabled -GroupTypes "DynamicMembership" -MembershipRule "(user.assignedPlans -all (assignedPlan.servicePlanId -ne ""fafd7243-e5c1-4a3a-9e40-495efcb1d3c3"" -and assignedPlan.capabilityStatus -ne ""Enabled""))" -MembershipRuleProcessingState "On"

Now onto the app deployment

Both of these need Office closed or the install will fail so I’m going to use the excellent PSADT along with ServiceUI.exe from MDT

The script for the apps are here: Visio | Project

I’ve also included the install and uninstall string, detection method, an icon and a packaged Win32 file

Both are installing the current branch latest version using the XML in the Files folder, feel free to amend for your requirements:

Project:

<Configuration ID="3c5aba9e-67dc-48d2-b1a2-c09cb4f05916">
  <Add OfficeClientEdition="64" Channel="Current" ForceUpgrade="TRUE" MigrateArch="TRUE">
    <Product ID="ProjectProRetail">
      <Language ID="MatchOS" />
    </Product>
  </Add>
  <Property Name="SharedComputerLicensing" Value="0" />
  <Property Name="PinIconsToTaskbar" Value="FALSE" />
  <Property Name="SCLCacheOverride" Value="0" />
  <Property Name="AUTOACTIVATE" Value="0" />
  <Property Name="FORCEAPPSHUTDOWN" Value="TRUE" />
  <Property Name="DeviceBasedLicensing" Value="0" />
  <Updates Enabled="FALSE" />
  <RemoveMSI />
  <Display Level="None" AcceptEULA="FALSE" />
  <Logging Level="Off" />
</Configuration>

Visio:

<Configuration ID="c1230666-d756-491b-b093-2d4d64413b17">
  <Add OfficeClientEdition="64" Channel="Current" ForceUpgrade="TRUE">
    <Product ID="VisioProRetail">
      <Language ID="MatchOS" />
      <ExcludeApp ID="Groove" />
      <ExcludeApp ID="OneDrive" />
    </Product>
  </Add>
  <Property Name="SharedComputerLicensing" Value="0" />
  <Property Name="PinIconsToTaskbar" Value="FALSE" />
  <Property Name="SCLCacheOverride" Value="0" />
  <Property Name="AUTOACTIVATE" Value="0" />
  <Property Name="DeviceBasedLicensing" Value="0" />
  <Updates Enabled="TRUE" />
  <RemoveMSI />
  <Display Level="None" AcceptEULA="FALSE" />
  <Logging Level="Off" />
</Configuration>

The uninstallers are also pretty straight forward:

Project:

<Configuration>

  <Remove All="FALSE">
    <Product ID="ProjectProRetail">
      <Language ID="en-us" />
    </Product>
  </Remove>

  <Updates Enabled="TRUE" Channel="Monthly" />

  <Display Level="None" AcceptEULA="TRUE" />

  <Property Name="AUTOACTIVATE" Value="1" />

<Logging Level="Standard" Path="%temp%" /> 
</Configuration>

Visio:

<Configuration>

  <Remove All="FALSE">
    <Product ID="VisioProRetail">
      <Language ID="en-us" />
    </Product>
  </Remove>

  <Updates Enabled="TRUE" Channel="Monthly" />

  <Display Level="None" AcceptEULA="TRUE" />

  <Property Name="AUTOACTIVATE" Value="1" />

<Logging Level="Standard" Path="%temp%" /> 
</Configuration>

The actual installation is handled by the Deploy-Application.ps1 files in the root

First set some variables (Project)

	##*===============================================
	##* VARIABLE DECLARATION
	##*===============================================
	## Variables: Application
	[string]$appVendor = 'Microsoft'
	[string]$appName = 'Project'
	[string]$appVersion = 'Latest'
	[string]$appArch = 'x64'
	[string]$appLang = 'EN'
	[string]$appRevision = '01'
	[string]$appScriptVersion = '1.0.0'
	[string]$appScriptDate = '01/11/2021'
	[string]$appScriptAuthor = 'Andrew Taylor'
	##*===============================================
	## Variables: Install Titles (Only set here to override defaults set by the toolkit)
	[string]$installName = 'Project'
	[string]$installTitle = 'Installing MS Project'

Visio

	## Variables: Application
	[string]$appVendor = 'Microsoft'
	[string]$appName = 'Visio'
	[string]$appVersion = 'Latest'
	[string]$appArch = 'x86'
	[string]$appLang = 'EN'
	[string]$appRevision = '01'
	[string]$appScriptVersion = '1.0.0'
	[string]$appScriptDate = '01/11/2021'
	[string]$appScriptAuthor = 'Andrew Taylor'
	##*===============================================
	## Variables: Install Titles (Only set here to override defaults set by the toolkit)
	[string]$installName = 'Visio'
	[string]$installTitle = 'Installing MS Visio'

Now we make sure the apps are closed

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

Then install

Execute-Process -Path "$dirFiles\setup.exe" -Parameters "/CONFIGURE InstallO365withVisio.xml"

Tell them it’s done

If (-not $useDefaultMsi) { Show-InstallationPrompt -Message 'Installation has been completed. You will find Visio in the All Programs section.' -ButtonRightText 'OK' -Icon Information -NoWait }

Or uninstall

Execute-Process -Path "$dirFiles\setup.exe" -Parameters "/CONFIGURE RemoveVisio.xml"

Now we need to deploy to Intune (I’ll just use Project to demonstrate, it’s the same process for Visio)

Grab the intunewin file (or create your own) and add details about the app

Add the install and uninstall commands (included in the source files). Here we are using ServiceUI.exe to allow desktop interaction with popup messages to close apps.

It’s a 64-bit version so make sure to limit the device type, you can pick any Windows version here, I generally just select the last supported version to try and tempt the dinosaurs into upgrading

For detection you are looking for the executable which is either winproj.exe (Project) or visio.exe (Visio)

It shouldn’t have any dependencies so you can skip this section and unless you already have a version to replace, skip Supersedence as well

Now we deploy to our newly created dynamic groups. I normally do a silent uninstall because the users don’t need to know

Now you have a fully automated deployment of Project and Visio, enjoy!

14 thoughts on “Automating Project and Visio installs with Dynamic Groups”

  1. Hey Andrew,

    Brilliant tutorial and it works very well, Could you please help me with one thing, I am not sure if it is included or not, but I would like to do a silent install so that the App Deployment Toolkit does not come up on screen when a user installs Visio from the company portal.

    Your help would be much appreciated.

    Reply
  2. Is there a solution for VLSC licenses? I think I’ve played with it in the past and trying to install Visio standalone after m365 doesn’t work that great

    Reply
  3. Forgive me i’m not familiar with Visio and project licensing, why do you leave AUTOACTIVATE to 0 for the installs but 1 for the uninstalls?

    Reply
  4. Hi Andrew, amazing article. Thank you!
    How would the install/uninstall work given the group is user based and the deployments and machine based?

    Reply
      • While it’s an atypical deployment option, does this mean that on a machine used by multiple users if one user has project it will install, but if another user does not have project it will uninstall when they log in, leading to the first user re-installing it when they log back in?

        Reply
        • Yes, that’s correct. For a multi-user machine, you can either just install it at the device and those without a license just can’t use it, or if the machines are the same model etc. you could use device based filtering to exclude the installation

          Reply

Leave a Comment