PartnerCenterLW and MSOnlineLW: Light Weight replacements to supercharge you M365 Scripts with PSCore / PS7 compatibility.

Recently I have been doing a lot of work converting all our scripts to work in PSCore and as Azure functions with PowerShell 7. One problem I have run into is an issue where different MS modules are unhappy loading different versions of the Microsoft.Identity.Client at the same time. The PartnerCenter and MSOnline modules are the primary ones which conflict with several others.

You will get errors such as:

<span class="has-inline-color has-vivid-red-color">One or more errors occurred. (Could not load type 'System.Security.Cryptography.SHA256Cng' from assembly 'System.Core, Version=4.0.0.0, Culture=neutral</span>

and:

<span class="has-inline-color has-vivid-red-color">Could not load file or assembly 'Microsoft.Identity.Client, Version=4.23.0.0, Culture=neutral, PublicKeyToken=0a613f4dd989e8ae'. The system cannot find the file specified.</span>

When looking through my scripts and trying to figure out ways to solve this issue I realised that for MSPs the only thing we really need from the PartnerCenter module was New-PartnerAccessToken with some specific switches. For MSOnline the main reason it is still required over some of the more modern modules is that there are a few parts that haven’t been moved over to Graph yet with delegated permissions, such as viewing MFA devices for a user.

After some poking graph and reverse engineering with fiddler I have created two new light weight modules called PartnerCentreLW and MSOnlineLW. For MSOnline I have only implemented the methods used in my Hudu documentation scripts and Kelvin’s IT Glue Scripts for MSOnline and only the New-PartnerAccessToken method from PartnerCenter.

For MSOnline I would still highly recommend rewriting your functions to use the newer modules like AzureAd.Preview and AzureAD.Standard.Preview as the endpoints it uses are going to be depreciated soon. MSOnline is already an end of life module. If you find something you can only do in MSOnline that I have not yet implemented in my module please let me know and I will get it added.

These modules can either be used by editing your import-module and install-module commands to add LW to the end or as the functions are pure PowerShell you can paste them into your scripts and run them directly with no need to import. I have designed them to be drop in replacements for scripts where the implemented commands are used.

Install-Module PartnerCenterLW
Import-Module PartnerCenterLW
Install-Module MSOnlineLW
Import-Module MSOnlineLW

This is an example version of New-PartnerAccessToken you can paste into a script.

function New-PartnerAccessToken {
    param (
        [String]$ApplicationId,
        [PSCredential]$Credential,
        [String]$RefreshToken,
        [String]$Scopes,
        [string]$Tenant
    )
	 
    if ($Credential) {
		$bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credential.password)
		$AppPassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($bstr)
        $AuthBody = @{
            client_id     = $ApplicationId
            scope         = $Scopes
            refresh_token = $RefreshToken
            grant_type    = "refresh_token"
            client_secret = $AppPassword
        }
    }
    else {
        $AuthBody = @{
            client_id     = $ApplicationId
            scope         = $Scopes
            refresh_token = $RefreshToken
            grant_type    = "refresh_token"
        }
    }

    if ($tenant) {
        $Uri = "https://login.microsoftonline.com/$Tenant/oauth2/v2.0/token"
    }
    else {
        $Uri = "https://login.microsoftonline.com/common/oauth2/v2.0/token"  
    }


    try {
        $ReturnCred = (Invoke-WebRequest -uri $Uri -ContentType "application/x-www-form-urlencoded" -Method POST -Body $AuthBody -ea stop).content | convertfrom-json
    }
    catch {
        Write-Error "Authentication Error Occured $_"
    }

    $ParsedCred = @{
        AccessToken = $ReturnCred.Access_Token
    }

    Return $ParsedCred

}

The modules can be found on GitHub here:

https://github.com/lwhitelock/PartnerCenterLW

https://github.com/lwhitelock/MSOnlineLW

And PowerShell Gallery here:

https://www.powershellgallery.com/packages/PartnerCenterLW/

https://www.powershellgallery.com/packages/MSOnlineLW/

Speed gains

To show what can be done when removing the dependencies on the legacy modules I made a tweaked version of Kelvin from Cyberdrain’s AZValidate module using the pure PowerShell PartnerCenter function above and direct Graph commands instead of MSOnline.

The original version can be found here: https://github.com/KelvinTegelaar/AzValidate

My modified version can be found here: https://github.com/lwhitelock/AzValidate-1/

To test this I deployed both to Consumption (Serverless) Plans in Azure. I then restarted the apps after each attempt to simulate a cold load, like would happen on most occasions when using the Consumption plan:

OriginalUpdated
45.6624.59
51.5425.16
54.5326.21

From the results removing the dependencies on the modules reduces the execution time by roughly half. On loaded executions my function is slightly slower, as rather than reusing the generated password, it generates a password for each request that is only valid for 5 minutes, so you are reducing the risk of a breach.

You may also like...