I found this fantastic PowerShell module from jseerden that queries Microsoft Graph, and allows for cross-tenant Backup & Restore of your Intune Configuration. The Intune Configuration is backed up as JSON files in a given directory. The module allows an administrator to backup, restore and even compare different Intune backup sets.

Pre-Requisites

The module requires a total of 3 modules to be present, you can install them by running the following commands in an administrative PowerShell prompt:

AzureAD Module

AzureAD ( Install-Module -Name AzureAD )

MSGraphFunction Module

MSGraphFunction ( Install-Module -Name MSGraphFunctions )

IntuneBackupandRestore Module

The IntuneBackupandRestore PowerShell module is hosted on the PowerShell Gallery. You can install it by running the following command in an administrative PowerShell prompt:

Install-Module -Name IntuneBackupAndRestore 1 Install-Module -Name IntuneBackupAndRestore

Connect to Microsoft Graph

Next, we will connect to Microsoft Graph using the “Microsoft Intune PowerShell” application in AzureAD, so you don’t need to create your own Azure AD application and set permissions. In PowerShell import the MSGraphFunctions module by running:

Import-Module MSGraphFunctions 1 Import-Module MSGraphFunctions

Once you have the module loaded into memory, you will connect to Graph by running Connect-Graph. Connect-Graph loads a webform which supports MFA login. You will see a prompt asking for permissions, if you are a global administrator you can also consent on behalf of your organization.

Once authenticated, the shell will return to the normal prompt.

Note: The function Connect-Graph has a Credential parameter that accepts a PSCredential object if you wanted to automate the backup/restore.

Back Up Intune Configuration

To backup your tenant Intune configuration make sure you have the IntuneBackupandRestore module imported into memory. You can import it by running

Import-Module IntuneBackupandRestore 1 Import-Module IntuneBackupandRestore

The Start-IntuneBackup cmdlet will then allow you to begin backing up your entire Intune configuration. The cmdlet has one parameter of FilePath. In my example I will save my Intune backup to $env:Temp\IntuneBackup folder. If the folder is not present it will automatically create the folder for you. To accomplish this I would run the command

Start-IntuneBackup -Path $Env:Temp\IntuneBackup 1 Start-IntuneBackup -Path $Env : Temp \ IntuneBackup

If I navigate to that folder in explorer I can see the backed up items from Intune. The files are backed up as JSON files, however if you got to \Device Management Scripts\Script Content you will see your Configuration PowerShell scripts which will be PS1 source files.

Compare Intune Backup Files

In an environment where multiple engineers may be making Intune changes, it may be beneficial to view configuration changes from a known working state to a later state. In my example, my ‘co worker’ made an Intune configuration change for the Bitlocker policy from my earlier Intune backup and forgot what he changed. To see what changed I took another backup and stored it at $Env:Temp\Intune2

To now compare both configuration I can use the Compare-IntuneBackupFile cmdlet. My full scriptblock would be

Compare-IntuneBackupFile -ReferenceFilePath "$Env:temp\IntuneBackup\Device Configurations\Bitlocker Encrypt.json" -DifferenceFilePath "$Env:temp\Intune2\Device Configurations\Bitlocker Encrypt.json" 1 Compare-IntuneBackupFile -ReferenceFilePath "$Env:temp\IntuneBackup\Device Configurations\Bitlocker Encrypt.json" -DifferenceFilePath "$Env:temp\Intune2\Device Configurations\Bitlocker Encrypt.json"

In the Shell I can see that he changed the minimum pin length from 4 to 8

Compare Intune Backup Directories

This next function is something I created during this write up because I thought Compare-IntuneBackupFile would recursively list changes in two backup sets. Currently, I pushed this change to the master project on GitHub and its awaiting approval so until then you will have to load this function into memory separately. The function will recursively compare all the JSON backup files in each directory. Its able to match up the JSON files by looking for the reference JSON file in the backup directory, if there is more than 1 result (which you will see with things like assignments) it will go back to the reference file, extract its parent folder and compare it to the results.

Parameters

The function requires values for 2 parameters:

ReferenceDirectory: The directory containing the reference backup files

DifferenceDirectory: The directory containing the newest (difference) backup files

Output

Verbose messages are displayed if you use the -Verbose switch parameter. Otherwise you will just see files that are different and what is different between the two JSON files

Example

In my example I will compare 2 backup sets for changes. My first backup (reference) is located at $Env:Temp\IntuneBackup. My newest backup (Difference) is located at $Env:\Intune2. My example command would be

Compare-IntuneBackupDirectories -Verbose -ReferenceDirectory C:\Users\BRADWY~1\AppData\Local\Temp\IntuneBackup -DifferenceDirectory C:\Users\BRADWY~1\AppData\Local\Temp\Intune2 1 Compare-IntuneBackupDirectories -Verbose -ReferenceDirectory C : \ Users \ BRADWY ~ 1 \ AppData \ Local \ Temp \ IntuneBackup -DifferenceDirectory C : \ Users \ BRADWY ~ 1 \ AppData \ Local \ Temp \ Intune2

Function

Below is the PowerShell function. Until it becomes approved and part of the module you will have to load it into memory. I was using ISE so I just ran it in ISE (or VSCode). You could also dot source the file. It does require the IntuneBackupAndRestore module to be installed and loaded into memory.

Function Compare-IntuneBackupDirectories { <# .SYNOPSIS Compare two Intune Backup Directories for changes in each of their JSON backup files. .DESCRIPTION Compare two Intune Backup Directories for changes. .PARAMETER $ReferenceDirectory Any Intune Backup Directory. .PARAMETER $DifferenceDirectory Latest Intune Backup directory .EXAMPLE - Show verbose output Compare-IntuneBackupDirectories -Verbose -ReferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneBackup -DifferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneNewBackup Compare-IntuneBackupDirectories -ReferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneBackup -DifferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneNewBackup .NOTES Requires the IntuneBackupAndRestore Module .AUTHOR Bradley Wyatt - The Lazy Administrator #> Param ( [parameter(Mandatory = $true, Position = 0)] [String]$ReferenceDirectory, [parameter(Mandatory = $true, Position = 1)] [String]$DifferenceDirectory ) Begin { $ReferenceFiles = Get-ChildItem $ReferenceDirectory -Recurse | Where-Object { $_.Name -like "*.json*" } | Select-Object -ExpandProperty VersionInfo $DifferenceFiles = Get-ChildItem $DifferenceDirectory -Recurse | Where-Object { $_.Name -like "*.json*" } | Select-Object @{ Label = "FileName"; Expression = { (($_.VersionInfo).FileName).split("\") | Select-Object -Last 1 } }, @{ Label = "FullPath"; Expression = { (($_.VersionInfo).FileName) } } } Process { Foreach ($File in $ReferenceFiles) { $ReferenceJSONFile = ($File.Filename).split("\") | Select-Object -last 1 Write-Verbose "The reference file is '$ReferenceJSONFile'" Write-Verbose "The reference file path is $($File.FileName)" $DifFileFound = $DifferenceFiles | Where-Object { $_.FileName -eq $ReferenceJSONFile } If (($DifFileFound.FileName).count -gt 1) { $ReferenceJSONFile = ($File.Filename).split("\") | Select-Object -last 2 $ReferenceJSONFileParent = ($File.FileName).split("\") | Select-Object -Last 2 $ReferenceJSONFileParentPath = "$(($ReferenceJSONFileParent).item(0))\$(($ReferenceJSONFileParent).item(1))" Write-Verbose "Multiple difference files found that were matching the reference file" $DifFileFound = $DifferenceFiles | Where-Object { $_.FullPath -like "*$ReferenceJSONFileParentPath*" } } Write-Verbose "The difference file is located at $($DifFileFound.fullpath)" Write-Verbose "Checking for changes in the file '$ReferenceJSONFile'" $Changes = Compare-IntuneBackupFile -ReferenceFilePath $File.FileName -DifferenceFilePath $DifFileFound.FullPath -ErrorAction silentlycontinue If ($Changes) { Write-Host "There was a change in the file, '$ReferenceJSONFile' which is located at $($DifFileFound.fullpath)" $Changes | Format-Table -AutoSize } } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 Function Compare-IntuneBackupDirectories { <# .SYNOPSIS Compare two Intune Backup Directories for changes in each of their JSON backup files. .DESCRIPTION Compare two Intune Backup Directories for changes. .PARAMETER $ReferenceDirectory Any Intune Backup Directory. .PARAMETER $DifferenceDirectory Latest Intune Backup directory .EXAMPLE - Show verbose output Compare-IntuneBackupDirectories -Verbose -ReferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneBackup -DifferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneNewBackup Compare-IntuneBackupDirectories -ReferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneBackup -DifferenceDirectory C:\Users\BradleyWyatt\AppData\Local\Temp\IntuneNewBackup .NOTES Requires the IntuneBackupAndRestore Module .AUTHOR Bradley Wyatt - The Lazy Administrator #> Param ( [ parameter ( Mandatory = $true , Position = 0 ) ] [ String ] $ReferenceDirectory , [ parameter ( Mandatory = $true , Position = 1 ) ] [ String ] $DifferenceDirectory ) Begin { $ReferenceFiles = Get-ChildItem $ReferenceDirectory -Recurse | Where-Object { $_ . Name -like "*.json*" } | Select-Object -ExpandProperty VersionInfo $DifferenceFiles = Get-ChildItem $DifferenceDirectory -Recurse | Where-Object { $_ . Name -like "*.json*" } | Select-Object @ { Label = "FileName" ; Expression = { ( ( $_ . VersionInfo ) . FileName ) . split ( "\" ) | Select-Object -Last 1 } } , @ { Label = "FullPath" ; Expression = { ( ( $_ . VersionInfo ) . FileName ) } } } Process { Foreach ( $File in $ReferenceFiles ) { $ReferenceJSONFile = ( $File . Filename ) . split ( "\" ) | Select-Object -last 1 Write-Verbose "The reference file is '$ReferenceJSONFile'" Write-Verbose "The reference file path is $($File.FileName)" $DifFileFound = $DifferenceFiles | Where-Object { $_ . FileName -eq $ReferenceJSONFile } If ( ( $DifFileFound . FileName ) . count -gt 1 ) { $ReferenceJSONFile = ( $File . Filename ) . split ( "\" ) | Select-Object -last 2 $ReferenceJSONFileParent = ( $File . FileName ) . split ( "\" ) | Select-Object -Last 2 $ReferenceJSONFileParentPath = "$(($ReferenceJSONFileParent).item(0))\$(($ReferenceJSONFileParent).item(1))" Write-Verbose "Multiple difference files found that were matching the reference file" $DifFileFound = $DifferenceFiles | Where-Object { $_ . FullPath -like "*$ReferenceJSONFileParentPath*" } } Write-Verbose "The difference file is located at $($DifFileFound.fullpath)" Write-Verbose "Checking for changes in the file '$ReferenceJSONFile'" $Changes = Compare-IntuneBackupFile -ReferenceFilePath $File . FileName -DifferenceFilePath $DifFileFound . FullPath -ErrorAction silentlycontinue If ( $Changes ) { Write-Host "There was a change in the file, '$ReferenceJSONFile' which is located at $($DifFileFound.fullpath)" $Changes | Format-Table -AutoSize } } } }

Restore Intune Backup

In this next section we will go over restoring Intune configuration and assignments.

Note: Restoring configurations will NOT overwrite existing configurations, but instead create new ones. Restoring assignments may overwrite existing assignments

Restore Everything

To restore everything you would use the Start-IntuneRestoreConfig cmdlet. It will recursively parse the folder structure and restore everything from each JSON file. It requires value for the Path parameter which is the directory of the backup files.

Start-IntuneRestoreConfig -Path C:\Users\BRADWY~1\AppData\Local\Temp\IntuneBackup\ 1 Start-IntuneRestoreConfig -Path C : \ Users \ BRADWY ~ 1 \ AppData \ Local \ Temp \ IntuneBackup \

Restore Single Backup File

To restore a single backup file you would use the same command as above. It will again parse the backup folder structure and import any JSON files it finds so to only backup 1 JSON file you will need to ensure its the only JSON file in all of the directories. If you delete the directories you will see some red on your console because it cannot find a folder its looking for but the import will still work. In my example I just went through all of the folders and deleted the JSON files I didn’t want to import.

Restore Assignments

To restore Intune Assignments you will use the Start-IntuneRestoreAssignments cmdlet. It will recursively parse your assignments and check to see if it needs to be restored or hasn’t changed. In my example only Adobe Reader had an assignment change and it was successfully changed back.

My name is Bradley Wyatt; I am a Microsoft Most Valuable Professional and I am currently a Manager DevOps Cloud Automation at BDO Digital in the Chicagoland area.

Share this: Twitter

Facebook

LinkedIn

Reddit

Email

