How to Make Sure That You Use the Latest Microsoft 365 PowerShell Modules

Important to Update PowerShell Modules Regularly

Updated: 15 August 2023

It’s important to keep PowerShell modules updated because Microsoft introduces new cmdlets and cmdlet parameters to support new functionality, like SharePoint Online site URL rename. Or when Microsoft updates the Microsoft Graph PowerShell SDK or MicrosoftTeams modules, both of which receive updates on a monthly (or even more frequent) basis.

Scripting PowerShell Updates

Most of the important PowerShell modules used with Microsoft 365 are now available in the PowerShell Gallery and can be installed and updated from there. It seemed appropriate to write a script to:

  • Define a set of modules that I’m interested in updating, such as the Exchange Online Management module, Microsoft Teams, the Microsoft Graph PowerShell SDK, ORCA (used to check Advanced Threat Protection Settings) and so on.
  • Check the PowerShell Gallery to see if an update is available, and if so, download and install it.
  • Clean up afterwards by checking the PC for versions of a module and removing all but the latest to ensure that scripts only ever run the latest cmdlets.

Here’s the basic processing steps for the original version of the script (I update the code on an ongoing basis to cope with changes, such as the split of the Microsoft Graph PowerShell SDK into V1.0 and beta modules). The script must be run after starting PowerShell as an administrator (otherwise you won’t be able to install the updates). Make sure that all other PowerShell sessions are ended to avoid the possibility of trying to update a module that’s in use.

# Define the set of modules installed and updated from the PowerShell Gallery that we want to maintain
$O365Modules = @("MicrosoftTeams", "MicrosoftTeams", "Microsoft.Graph", "ExchangeOnlineManagement", "Microsoft.Online.Sharepoint.PowerShell", "ORCA")

# Check and update all modules to make sure that we're at the latest version
ForEach ($Module in $O365Modules) {
   Write-Host "Checking and updating module" $Module
   Update-Module $Module -Force -Scope AllUsers }

# Check and remove older versions of the modules from the PC
ForEach ($Module in $O365Modules) {
   Write-Host "Checking for older versions of" $Module
   $AllVersions = Get-InstalledModule -Name $Module -AllVersions
   $AllVersions = $AllVersions | Sort-Object PublishedDate -Descending 
   $MostRecentVersion = $AllVersions[0].Version
   Write-Host "Most recent version of" $Module "is" $MostRecentVersion "published on" (Get-Date($AllVersions[0].PublishedDate) -format g)
   If ($AllVersions.Count -gt 1 ) { # More than a single version installed
      ForEach ($Version in $AllVersions) { #Check each version and remove old versions
        If ($Version.Version -ne $MostRecentVersion)  { # Old version - remove
           Write-Host "Uninstalling version" $Version.Version "of Module" $Module -foregroundcolor Red 
           Uninstall-Module -Name $Module -RequiredVersion $Version.Version -Force
         } #End if
      } #End ForEach
  } #End If
} #End ForEach

You can download the latest version of the script from GitHub and amend it to update the modules you use. Because I use the script to keep my PCs updated with the latest PowerShell modules, the current code is more developed and comprehensive than the snippet shown above. The script isn’t perfect, but it gets the job done for me.

Figure 1 shows some typical output as the script processes the set of Microsoft 365 PowerShell modules and updates those when a new version is available in the PowerShell gallery.

Update PowerShell Modules for Microsoft 365
Figure 1: Update PowerShell Modules for Microsoft 365 workloads

The script installs and updates modules in the $env:ProgramFiles\PowerShell\Modules location to make sure that the files are on the local workstation and available to all users. From PowerShell 6 onward, the default is to install modules in $HOME\Documents\PowerShell\Modules, which might mean that they end up in OneDrive.

Monthly Updates

Given the cadence of Microsoft updates for PowerShell modules, it’s a good idea to update PowerShell modules every month or six weeks. Perhaps reflecting the ongoing growth in Graph APIs, the Microsoft Graph PowerShell SDK receives even more frequent updates. If you use the Graph SDK with Azure Automation, make sure that you update PowerShell modules for the Graph SDK in your Azure Automation accounts too.

Checking, updating, and removing PowerShell modules is not a fast process, but it does help to keep your scripting in good health.

The Office 365 for IT Pros eBook includes extensive coverage of managing Office 365 applications with PowerShell, so we pay attention to this kind of stuff – just like you should.

18 Replies to “How to Make Sure That You Use the Latest Microsoft 365 PowerShell Modules”

  1. I receive a number of scope errors when attempting to run this script. Can you provide any guidance to remedy?

    Error message syntax:

    Update-Module : A parameter cannot be found that matches parameter name ‘Scope’.

    + Update-Module $Module -Force -Scope AllUsers }
    + ~~~~~~
    + CategoryInfo : InvalidArgument: (:) [Update-Module], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Update-Module

    1. From

      Specifies the installation scope of the module. The acceptable values for this parameter are AllUsers and CurrentUser. If Scope isn’t specified, the update is installed in the CurrentUser scope.

      The AllUsers scope requires elevated permissions and installs modules in a location that is accessible to all users of the computer:

      You’re not running PowerShell in an administrator session.

      1. Thank you for the response, Tony. I am launching Windows PowerShell ISE as administrator and have local admin rights on my PC. Any other thought? Should I try changing the value to CurrentUser if I’m only concerned with it updating for my profile?

      2. You could certainly do that… But before you do, try opening a simple PowerShell session as an admin (not ISE) to see if that works.

  2. One step ahead. I did to no avail. Also tried swapping out AllUsers for CurrentUser. with no luck. Same error complaining that “A parameter cannot be found that matches the parameter name ‘Scope’.”

  3. Sorry to reply so late. Updating Powershellget to version 2.2.3 should resolve this issue as it adds the -scope parameter to the Update-Module command.
    Hoping @Paul ticked the ‘Notify me of new comments via email’ checkbox ;p)

    1. Thanks, Matt. I did have it checked, fortunately. 🙂 Update-Module did improve the script run some but I still have a number of lines returning


      Checking and updating module MicrosoftTeams
      Update-Module : A parameter cannot be found that matches parameter name ‘Scope’.
      At C:\Users\aaa0013.BUILD\OneDrive – BMC\Documents\WindowsPowerShell\Scripts\Office 365\UpdateOffice365PowerShellModulesCurrentUser.ps1:15 char:33
      + Update-Module $Module -Force -Scope CurrentUser }
      + ~~~~~~
      + CategoryInfo : InvalidArgument: (:) [Update-Module], ParameterBindingException
      + FullyQualifiedErrorId : NamedParameterNotFound,Update-Module


      But then later in the script it returns:


      Checking for older versions of MicrosoftTeams
      Most recent version of MicrosoftTeams is 1.1.6 published on 9/14/2020 10:22 PM
      Uninstalling version 1.0.2 of Module MicrosoftTeams


      So I think it worked?

  4. Any thoughts on this error:
    $CurrentVersion = $CurrentVersion.Major.toString() + “.” + $CurrentVersion.Minor.toString() + “.” + $CurrentVersion.Build.toString()
    You cannot call a method on a null-valued expression.
    At line:1 char:1
    + $CurrentVersion = $CurrentVersion.Major.toString() + “.” + $CurrentVe …
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo : InvalidOperation: (:) [], RuntimeException
    + FullyQualifiedErrorId : InvokeMethodOnNull

    Is this a Powershell version thing?

    1. There’s some issue with the $CurrentVersion variable. What is its value?

      This code might be better:

      $CurrentVersion = (Find-Module -Name $Module | Select-Object -ExpandProperty Version)
      If ($CurrentVersion) {
      $CurrentVersion = $CurrentVersion.Major.toString() + “.” + $CurrentVersion.Minor.toString() + “.” + $CurrentVersion.Build.toString()
      Write-Host (“Current version of the {0} module in the PowerShell Gallery is {1}” -f $Module, $CurrentVersion)
      } Else {
      $CurrentVersion = “0.0.0”
      Write-Host (“No module found for {0}” -f $Module) }

      1. Here’s where I ran those two lines from the script manually. The $currentversion variable does get populated, but the error seems to be generated by the $currentversion.major.tostring() part. Maybe I’m missing something obvious.

        $CurrentVersion = (Find-Module -Name MicrosoftTeams | Select-Object -ExpandProperty Version)
        $CurrentVersion = $CurrentVersion.Major.toString() + “.” + $CurrentVersion.Minor.toString() + “.” + $CurrentVersion.Build.toString()
        You cannot call a method on a null-valued expression.
        At line:1 char:1
        + $CurrentVersion = $CurrentVersion.Major.toString() + “.” + $CurrentVe …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : InvalidOperation: (:) [], RuntimeException
        + FullyQualifiedErrorId : InvokeMethodOnNull

      2. Did you try the altered code that I posted? The change I made checks to see if a current version is on the PC (it might not be) and returns a version of 9.0.0 if a module is not present.

      3. Yes, I did try that. Same error. Like I said, when I run that line by itself, it doesn’t seem to recognize the “Major” keyword as valid. I’m getting the version number in $currentversion, but it doesn’t like the line where the script breaks it up into Major, Minor, & Build. Are those variables version specific, are they defined in a function elsewhere?

      4. The version information should come from the PowerShell module that’s registered on your PC. Can you run a Get-Module for the module that it’s failing for and examine what comes back?

      5. I get the same error for each module that it checks. If it’s working for you and not for me, it must be something on my side. I’m researching the source of “major”,”minor” and “build” to see where they come from. That is what’s failing, not the overall script itself.

      6. Apparently the issue was that the $currentversion variable was not cast as [version]. Once I added that, I got no errors. Thanks so much for your script and your assistance.

      7. I also added some code to check if any of the [version] numbers came back as negative (no value). Otherwise, you get this error:
        $orcaVersion = $orcaVersion.Major.toString() + “.” + $orcaVersion.Minor.toString() + “.” + $orcaVersion.Build.toString()
        Cannot convert value “2.1.-1” to type “System.Version”. Error: “Version’s parameters must be greater than or equal to zero.
        Parameter name: build”
        At line:1 char:1
        + $orcaVersion = $orcaVersion.Major.toString() + “.” + $orcaVersion.Min …
        + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException
        + FullyQualifiedErrorId : RuntimeException

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.