Automating with PowerShell: Disabling anonymous reports for Office365

It’s been a while since I’ve blogged! I’ve been super busy with a secret project I am hoping to release soon. This blog is dedicated to a friend of mine.

His question was “Can we disable the anonymous report functionality in M365?” This functionality gives users a pseudo-anonymous ID in the M365 portal when reporting on Onedrive usage, but also when extracting this information via APIs. That can get annoying if you use the reports for monitoring functionality.

To change this function you can go to the portal and make the change, or you can use Evotec’s scripts here if you administer a single tenant. For multitenant situations, such as partners use, you can use the script below.

In this script, we use our Secure Application Model Exchange token to connect to the old admin portal resource API. We’re using this token because the Exchange Online application ID, and thus, the token is allowed to connect to all sorts of resources. The old admin portal API, but also the Azure AD API. All you have to change is the “Resource” ID in the request. There’s a bunch of available APIs with this so the trick to to just experiment 🙂

The script

#
$ApplicationId = 'AppID'
$ApplicationSecret = 'AppSecret'
$RefreshToken = 'RefreshTokens'
$ExchangeRefreshToken = 'YourExchangeRefreshToken'
#
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, ($ApplicationSecret | Convertto-SecureString -AsPlainText -Force))
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal

write-host "Connecting to the Graph API to get all tenants." -ForegroundColor Green
$Contractheaders = @{ "Authorization" = "Bearer $($graphToken.accesstoken)" }
$Customers = (Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/contracts?`$top=999" -Method GET -Headers $Contractheaders).value
foreach ($Customer in $Customers) {
    $uri = "https://login.microsoftonline.com/$($Customer.tenant)/oauth2/token"
    $body = "resource=https://admin.microsoft.com&grant_type=refresh_token&refresh_token=$($ExchangeRefreshToken)"
    $token = Invoke-RestMethod $uri -Body $body -ContentType "application/x-www-form-urlencoded" -ErrorAction SilentlyContinue -method post
    $sspr = Invoke-RestMethod -contenttype "application/json;charset=UTF-8" -uri 'https://admin.microsoft.com/admin/api/reports/config/SetTenantConfiguration' -body '{"PrivacyEnabled":false,"PowerBiEnabled":true}' -method POST -Headers @{
        Authorization            = "Bearer $($token.access_token)";
        "x-ms-client-request-id" = [guid]::NewGuid().ToString();
        "x-ms-client-session-id" = [guid]::NewGuid().ToString()
        'x-ms-correlation-id'    = [guid]::NewGuid()
        'X-Requested-With'       = 'XMLHttpRequest'
    }
}

And that’s it! as always, Happy PowerShelling. 🙂

Recent Articles

Automating with PowerShell: making stolen tokens useless with Global Secure Access

Last week I watched Merill Fernando talk to Alex Pavlovsky and Marilee Tuscak from the Entra team about something I’d kinda put under the “needs a GSA licence” branch and i’d check it out later, turns out that like most people, I half-assed the documentation and it turns out it doesn’t. There’s two features that come with any P1 license; Compliant network check and Source IP Restoration. So BP, P1, or even frontline worker licenses already have this.

CIPP ❤️ #IntuneForMSPs

We’re Joining #IntuneForMSPs 🎉

Being invited by Microsoft to join a global initiative is a big moment for us, and we want to be clear about why it matters. #IntuneForMSPs is Microsoft’s program to help MSPs deliver Microsoft 365, Intune, and Copilot services at scale, and CIPP is now part of it, bringing the largest MSP community in the channel directly to Microsoft.

The return of CyberDrain CTF

CyberDrain CTF returns! (and so do I!)

It’s been since september that I actually picked up a digital pen equivalent and wrote anything down. This was due to me being busy with life but also my side projects like CIPP. I’m trying to get back into the game of scripting and blogging about these scripts. There’s still so much to automate and so little time, right? ;)