Entra / Microsoft 365 · Users & guests
Update Office 365 PowerShell modules
Checks for updates to common Office 365 management modules and installs newer versions, pruning older module builds.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
# Review required modules and connection steps before running.# Connect to Microsoft Graph or Exchange Online as needed for this script.
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
$IsAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)If (!$IsAdmin) {Write-Host "You must be signed in as an administrator to update modules" -ForegroundColor RedBreak}If ($Host.Version.Major -lt 7) {Write-Host ("Current version is {0}. This script requires PowerShell 7" -f $Host.Version) -ForegroundColor RedBreak}# Define the set of modules installed and updated from the PowerShell Gallery that we want to maintain - edit this set of modules to include the modules# you want to process.[int]$InstalledModules = 0; [int]$UpdatedModules = 0; [int]$RemovedModules = 0$O365Modules = @("Az.Accounts", "Az.Automation", "AIPService", "Az.Keyvault", "MicrosoftTeams", "Microsoft.Graph", "Microsoft.Graph.Beta", "ExchangeOnlineManagement", "Microsoft.Online.Sharepoint.PowerShell", "ORCA", "Pnp.PowerShell", "MSCommerce", "Microsoft365DSC", "MSAL.PS", "WhiteboardAdmin", "ImportExcel", "Maester", "Microsoft.Entra", "Microsoft.Entra.Beta", "MSIdentityTools")$O365Modules = $O365ModulesWrite-Host ("Starting up and preparing to process these modules: {0}" -f ($O365Modules -join ", ")) -foregroundcolor Yellow[int]$UpdatedModules = 0; [int]$RemovedModules = 0; [int]$InstalledModules = 0# We're installing from the PowerShell Gallery so make sure that it's trustedSet-PSRepository -Name PsGallery -InstallationPolicy Trusted# Check and update all modules to make sure that we're at the latest versionForEach ($Module in $O365Modules) {Write-Host "Checking and updating module" $Module$CurrentModule = Find-Module -Name $ModuleIf ($CurrentModule) {$CurrentVersion = $CurrentModule.VersionIf ($CurrentVersion -isnot [string]) {$CurrentVersion = $CurrentVersion.Major.toString() + "." + $CurrentVersion.Minor.toString() + "." + $CurrentVersion.Build.toString()}[datetime]$CurrentModuleDate = $CurrentModule.PublishedDateWrite-Host ("Current version of the {0} module in the PowerShell Gallery is {1}" -f $Module, $CurrentVersion)}$PCModule = Get-InstalledModule -Name $Module -ErrorAction SilentlyContinueIf (!($PCModule)) {# No version of the module found. It's in our list, so we install it.Write-Host ("No module found on this PC for {0}" -f $Module)Write-Host ("Installing module {0}..." -f $Module) -foregroundcolor YellowInstall-Module $Module -Scope AllUsers -Confirm:$False -AllowClobber -Force$InstalledModules++}If ($PCModule) {$PCVersion = $PCModule.VersionIf ($PCVersion -isnot [string]) {$PCVersion = $PCVersion.Major.toString() + "." + $PCVersion.Minor.toString() + "." + $PCVersion.Build.toString()}[datetime]$PCModuleDate = $PCModule.PublishedDateIf ($PCModuleDate -eq $CurrentModuleDate) {Write-Host ("Latest version of {0} is installed on this PC - no need to update" -f $Module)} Else {Write-Host ("Updating {0} module to version {1}" -f $Module, $CurrentVersion) -foregroundcolor YellowRemove-Module $Module -ErrorAction SilentlyContinueIf ($Module -eq "Maester") { # see https://maester.dev/blog/the-end-of-code-signing/ for Maester issue, so skip the publisher checkUninstall-Module $ModuleUpdate-Module $Module -Force -Confirm:$False -Scope AllUsers -AllowPreRelease} Else {Update-Module $Module -Force -Confirm:$False -Scope AllUsers}$UpdatedModules++} # End if}} # End ForEach Module# Check and remove older versions of the modules from the PCWrite-Host "Beginning clean-up phase..."[array]$SetofInstalledModules = Get-InstalledModule[array]$GraphModules = $SetOfInstalledModules | Where-Object {$_.Name -Like "*Microsoft.Graph*"} | Select-Object -ExpandProperty Name$ModulesToProcess = $O365Modules + $GraphModules | Sort-Object -UniqueForEach ($Module in $ModulesToProcess) {Write-Host "Checking for older versions of" $Module[array]$AllVersions = Get-InstalledModule -Name $Module -AllVersions -ErrorAction SilentlyContinueIf ($AllVersions) {$AllVersions = $AllVersions | Sort-Object PublishedDate -Descending$MostRecentVersion = $AllVersions[0].VersionIf ($MostRecentVersion -isnot [string]) { # Handle PowerShell 5 - PowerShell 7 returns a string$MostRecentVersion = $MostRecentVersion.Major.toString() + "." + $MostRecentVersion.Minor.toString() + "." + $MostRecentVersion.Build.toString()}[datetime]$MostRecentVersionDate = $AllVersions[0].PublishedDate$PublishedDate = (Get-Date($MostRecentVersionDate) -format g)Write-Host ("Most recent version of {0} is {1} published on {2}" -f $Module, $MostRecentVersion, $PublishedDate)If ($AllVersions.Count -gt 1 ) { # More than a single version installedForEach ($Version in $AllVersions) { #Check each version and remove old versions[datetime]$VersionDate = $Version.PublishedDateIf ($VersionDate -lt $MostRecentVersionDate) { # Old version - removeWrite-Host ("Uninstalling version {0} of module {1}" -f $Version.Version, $Module) -foregroundcolor RedUninstall-Module -Name $Module -RequiredVersion $Version.Version -Force$RemovedModules++} #End if version check} # End ForEach versions} Else {Write-Host ("No earlier versions of {0} module to remove" -f $Module)} # End check for more than one version} #End If} #End ForEachWrite-Host ("Installed modules: {0} Updated modules: {1} Removed old versions of modules: {2}" -f $InstalledModules, $UpdatedModules, $RemovedModules)
Attribution
Author
Office365itpros