Wednesday, June 21, 2023

Issue Migrating to ExchangeOnlineManagement Module 3.0.1

Hello, Friends.

If you use the ExchangeOnlineManagement module for unattended scripts, you may have recently seen this message in your logs or your console when troubleshooting:

"Attention!

You are currently using an older version of the Exchange Online PowerShell module which uses RPS. RPS deprecation has been announced and you will need to move to the latest V3 module by June 2023. Read more here: https://aka.ms/RPSDeprecation 
Please install our new REST-based PS V3 module downloadable from https://www.powershellgallery.com/packages/ExchangeOnlineManagement/, which is more secure and reliable.
Please note that you will no longer be able to use -UseRPSSession after June 2023."

...or this message:

"Today, we are announcing that starting June 1, 2023, we will start blocking RPS connections to Exchange Online and will block RPS for all tenants by July 1, 2023. After July 1, customers will not be able to use RPS when connecting to Exchange Online and will have to use the v3 module with REST cmdlets instead."

So, like a good engineer, I tried to resolve this quickly because I hate to watch my automation break and/or have to figure this out on the fly on an incident call.

What did I do? Why, I opened up PowerShell and installed the V3 module (3.1.0, specifically) as is suggested in the banner, of course.

Install-Module -Name ExchangeOnlineManagement -RequiredVersion 3.1.0

I uninstalled the original version I was running...

Uninstall-Module -Name ExchangeOnlineManagement -RequiredVersion 2.0.5

I restarted my PowerShell ISE and moved forward massaging my original scripts to use inputs I thought would trigger use of the REST cmdlets. However, it seemed to me no matter what I would do, it never would get to a point to try and connect to Exchange Online. I was getting the following error:

PS C:\{redacted}> $TLS12Protocol = [System.Net.SecurityProtocolType] 'Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $TLS12Protocol
#Connect to Exchange Online
$connectSplat = @{
    AccessToken = '{redacted}'
    AppId = '{redacted}'
    Organization = '{redacted}'
    Verbose = $true
    Debug = $true
}
Connect-ExchangeOnline @connectSplat
VERBOSE: Computed version info: 3.1.0
VERBOSE: ModuleVersion: 3.1.0
VERBOSE: ConnectionContext Removed
Could not load file or assembly 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find 
the file specified.
At C:\Program Files\WindowsPowerShell\Modules\ExchangeOnlineManagement\3.1.0\netFramework\ExchangeOnlineManagement.psm1:729 char:21
+                     throw $_.Exception.InnerException;
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (:) [], FileNotFoundException
    + FullyQualifiedErrorId : Could not load file or assembly 'System.Net.Http, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

I'll cut to the chase...I was able to resolve the issue. Here's what I was able to determine:

If you go here, to review the module and expand Package Details, you'll see under Dependencies it states, "This module has no dependencies." FALSE!

After digging into this, my hypothesis is this new module has a dependency that the .NET Framework your machine is running must be at least 4.7.2.

To find out what version you are running, use this command in PowerShell:

(Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full' -Name Release).Release

If you cannot run this command, chances are your .NET Framework is a version before 4.5 (ref).

If the command runs successfully, you'll get a release number, which can be translated here.

I happened to be running .NET Framework 4.6.2. The latest recommended release at the time of this blog post was 4.8. So, I installed .NET Framework 4.8 and the "Could not load file or assembly..." error went bye-bye!


The struggle...

I went far down the rabbit hole on this one and lost a good amount of hours. I cracked open DLLs, and considered repackaging the ExchangeOnlineManagement module to work around this error. I modified ExchangeOnlineManagement.psm1 to get better logging for this.

I was able determine that the error was occurring on lines 528 to 536 of ExchangeOnlineManagement.psm1 where it is calling Get-ConnectionContext.

Naturally these things had me searching in all corners of the internet for a little nugget of information to help me.

Why do I think your machine must be running 4.7.2 of .NET Framework? I cracked open Microsoft.Exchange.Management.ExoPowershellGalleryModule.dll. In that DLL, is a csproj file. In the csproj file it notes a TargetFramework of 'net472'. Additionally, in my flailing to try and figure this out, I tried installing the 3.1.0 module on a different host... and it worked fine! This other host was running PowerShell 5.1.19041.2673 and .NET Framework 4.8. The original host was running PowerShell 5.1.14393.5582 and .NET Framework 4.6.2. This caused me to consider the framework version as a likely culprit. It's just too bad I didn't get to that point sooner.



Hope this helps someone. Good luck out there!

No comments:

Post a Comment

Issue Migrating to ExchangeOnlineManagement Module 3.0.1

Hello, Friends. If you use the ExchangeOnlineManagement module for unattended scripts, you may have recently seen this message in your logs ...