private/Assert-MsecExoCmdlet.ps1

function Assert-MsecExoCmdlet {
    <#
    .SYNOPSIS
        Throws a clear error when a Security & Compliance cmdlet is not exposed to this session.

    .DESCRIPTION
        THE COMPLIANCE ENDPOINT EXPOSES A DIFFERENT SET OF CMDLETS PER IDENTITY, not per tenant.
        It imports what the connecting identity's ROLE GROUPS allow, on top of what the tenant is
        licensed for - so a cmdlet that exists in the documentation can be absent for this app
        while a human administrator uses the same feature in the portal all day.

        THAT DISTINCTION IS EASY TO GET BACKWARDS, and getting it backwards writes "we do not
        have eDiscovery" into a compliance report about a tenant that does. Measured on one
        tenant: Get-ComplianceSearch, Get-InsiderRiskPolicy and Get-SupervisoryReviewPolicyV2 were
        all missing from an app-only session, while the eDiscoveryManager, InsiderRiskManagement
        and CommunicationCompliance role groups each had three members and the features were in
        active use. The absence said nothing about the tenant; it said the app was not in those
        role groups.

        Calling one anyway raises CommandNotFoundException - 'The term X is not recognized' -
        which surfacing from a Get-Msec* command reads as a broken module rather than as a
        tenant that does not have the feature.

        SO IT THROWS RATHER THAN RETURNING NOTHING. An empty result would say "this tenant has no
        DLP policies" when the truth is "this identity cannot ask", and on a compliance report
        those are opposite conclusions. Not measurable is not the same as measured zero - and it
        is not the same as not present, either.

    .PARAMETER Name
        The cmdlet the caller is about to use.

    .PARAMETER Feature
        Human name of what it reads, for the message.

    .PARAMETER Hint
        Optional extra sentence, e.g. a narrower parameter that would still work.
    #>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [string] $Name,

        [Parameter(Mandatory)]
        [string] $Feature,

        [Parameter()]
        [string] $Hint
    )

    if (Get-Command $Name -ErrorAction SilentlyContinue) { return }

    $message = "'$Name' is not available to THIS session, so $Feature cannot be read by the identity you are " +
               'connected as. The compliance endpoint imports cmdlets per identity, based on its Purview ROLE ' +
               'GROUPS - so this is very often an app that is not in the right role group rather than a tenant ' +
               'that lacks the feature, and someone may well be using it in the portal right now. It is not an ' +
               'API permission and granting one will not help. To let this identity read it, add it to the ' +
               'matching (view-only) Purview role group. IMPORTANT: this is not evidence that the feature is ' +
               'absent or unconfigured - treat it as not measurable from here.'
    if ($Hint) { $message += " $Hint" }
    throw $message
}