ConnectWise Breach: Proving What an App Did with Microsoft Graph Activity Logs

IT security analyst tracing activity across glowing monitors in a dark operations room

The ConnectWise supply-chain attack on Microsoft 365 tenants has raised a question I keep hearing from MSPs: if an attacker’s app signed in to a tenant, how do you prove what it did, or didn’t, do?

The honest answer is that Microsoft doesn’t publish one definitive list of “Graph activity that isn’t in the UAL”. What it does document is which log records what. Put those side by side and the gaps become clear. I’ll cover what each log tells you, where the blind spots are, how to switch on Microsoft Graph activity logs, and how to scope the blast radius if you didn’t have them on.

What GCIT showed

Credit to Elliot and the team at GCIT, whose write-up of the ConnectWise Cloud Backup compromise is a model of how to be open about an incident. Their tenant had one successful service principal sign-in from the Cloud Backup app (15 Oct, 144.172.64.128, Python user agent). They proved nothing was done with that token by matching its identifier against 13,682 requests in their Microsoft Graph activity logs. The UAL on its own could never have proved that. They also note that Graph activity logs need Entra ID P1 and have to be switched on before the event.

The three logs and what each one tells you

  • Sign-in logs (service principal and managed identity sign-ins are kept separately from interactive sign-ins) tell you that a token was issued, and from where. They don’t tell you what was done with it. One sign-in can mean hundreds of API calls, or none at all, as GCIT found. Retention is 7 days on Entra ID Free and 30 days on P1/P2, so export them. https://learn.microsoft.com/en-us/entra/identity/monitoring-health/reference-reports-data-retention
  • The unified audit log records audited actions in each workload. It isn’t a record of every API request. A good example is mail: MailItemsAccessed covers all protocols, including REST/Graph and EWS, but it’s only on by default for E3/E5 users. Check your mailbox audit configuration everywhere else. Bind accesses are also aggregated and de-duplicated. https://learn.microsoft.com/en-us/purview/audit-log-investigate-accounts
  • Microsoft Graph activity logs (MicrosoftGraphActivityLogs) record every HTTP request Graph processes for your tenant: app ID, service principal, IP, request URI, method, response size, and the token and sign-in identifiers. That’s what lets you join requests to sign-ins. They need Entra ID P1 or P2 and a diagnostic setting that sends them to Log Analytics, Storage or Event Hub. They aren’t retroactive, and delivery usually takes up to 30 minutes, occasionally 2 hours. https://learn.microsoft.com/en-us/graph/microsoft-graph-activity-logs-overview

So where are the blind spots?

Anything read through Graph that the workload doesn’t audit as an action, such as directory and user reads, will only show up in Graph activity logs. And full_access_as_app over EWS isn’t Graph at all, so it won’t appear in Graph activity logs. It would only appear in mailbox auditing. If you don’t have Graph activity logs turned on, “sign-in but no UAL entries” doesn’t prove nothing happened. It means you can’t tell.

On audit retention: Audit Standard is 180 days. Audit Premium (E5) keeps Exchange, SharePoint, OneDrive and Entra records for one year, and up to 10 years with the add-on. https://learn.microsoft.com/en-us/purview/audit-log-retention-policies

What an attacker could do without Graph activity logs

The short answer is anything the app’s granted permissions allow. Without Graph activity logs, most read-only activity leaves no trace at all.

Likely to leave no trace (reads)

  • Directory reconnaissance: listing users, groups, admin role holders, devices, apps, Conditional Access policies and licences (Directory.Read.All, Policy.Read.All). Reads like these aren’t recorded in the UAL, which makes them perfect for mapping a tenant before a bigger attack.
  • Org intel: org charts, managers, phone numbers and email addresses, all useful for phishing and business email compromise.
  • Teams/chat and calendar reads, and some file reads, depending on permissions and audit coverage. SharePoint and OneDrive FileAccessed events usually do appear in the UAL, but bulk reads by an app can be patchy.

Probably visible, if auditing was on

  • Mail reads (Mail.Read): these show as MailItemsAccessed, but only if mailbox auditing records that action for the affected mailboxes. If it doesn’t, they’re invisible.
  • Writes and changes: sending mail, creating inbox rules, adding app credentials or owners, consenting to new apps, creating users or changing roles, and changing CA policies. These normally appear in the Entra audit log or the UAL, because they’re audited actions rather than reads.

What actually determines the blast radius

  1. The app’s application permissions. Check Enterprise applications > the app > Permissions. Something like Mail.Read or Files.Read.All is tenant-wide.
  2. The service principal sign-ins: times, IP addresses and how many tokens were issued.
  3. The Entra audit log: look for any new credentials, owners or consents on that or other apps, which would show persistence.

The honest bottom line is that without Graph activity logs, a sign-in followed by no UAL entries means you can’t prove what was read. Treat anything that app could read as potentially exposed, rotate its secrets, and remove or scope down its permissions. Then turn on Graph activity logs so next time you can prove it either way.

How to turn on Microsoft Graph activity logs

It takes about 10 minutes per tenant.

Before you start

  • Licensing: Microsoft Entra ID P1 or P2 in the tenant (Business Premium includes P1).
  • Role: Security Administrator is the least privileged Entra role Microsoft supports for creating diagnostic settings. You also need Azure rights on the destination.
  • An Azure subscription with a destination that already exists: a Log Analytics workspace (best for querying), a storage account (cheap long-term archive) or an Event Hub (to stream to a third-party SIEM).
  • Cost: P1 doesn’t cover the Azure side, so you pay for what you ingest and store. Microsoft’s rough guide is about 15 GiB a month into Log Analytics per 1,000 users, but it varies a lot with the apps in the tenant. Check the Azure Monitor pricing page and consider a workspace transformation or the Basic table plan to cut costs.
  • The logs are NOT retroactive. You only see activity from the moment you switch them on, so do it before you need them.

Step 1: Create a Log Analytics workspace

  1. In the Azure portal, go to Log Analytics workspaces > Create.
  2. Pick the subscription, a resource group, a name and a region, then Review + Create.

Step 2: Turn on the diagnostic setting (GUI)

  1. Sign in to the Microsoft Entra admin centre as at least a Security Administrator.
  2. Browse to Entra ID > Monitoring & health > Diagnostic settings.
  3. Select Add diagnostic setting and give it a name.
  4. Tick MicrosoftGraphActivityLogs. While you’re there, also tick ServicePrincipalSignInLogs, SignInLogs and AuditLogs, so you can correlate them.
  5. Tick Send to Log Analytics workspace and choose your subscription and workspace.
  6. Save.

Step 2 (alternative): PowerShell

There’s no dedicated Entra cmdlet for this. New-AzDiagnosticSetting targets Azure resources, not the tenant. Instead, you PUT to the Azure Resource Manager endpoint for microsoft.aadiam/diagnosticSettings with Invoke-AzRestMethod:

Connect-AzAccount
$ws = "/subscriptions/<SUB-ID>/resourceGroups/<RG>/providers/Microsoft.OperationalInsights/workspaces/<WORKSPACE>"
$body = @{
properties = @{
workspaceId = $ws
logs = @(
@{ category = "MicrosoftGraphActivityLogs"; enabled = $true },
@{ category = "ServicePrincipalSignInLogs"; enabled = $true }
)
}
} | ConvertTo-Json -Depth 5
Invoke-AzRestMethod -Method PUT -Payload $body `
-Uri "https://management.azure.com/providers/microsoft.aadiam/diagnosticSettings/GraphActivity?api-version=2017-04-01"

The Azure CLI equivalent is az rest --method put --url "<same URL>" --body @body.json.

Step 3: Check it’s working

Microsoft says delivery is usually within 30 minutes, but allow time for the table to first appear (Entra’s docs allow up to three days). Then run:

MicrosoftGraphActivityLogs
| where TimeGenerated > ago(1d)
| summarize Requests = count() by AppId, ServicePrincipalId
| sort by Requests desc

To tie Graph calls back to a service principal sign-in, which is exactly the GCIT approach:

MicrosoftGraphActivityLogs
| where TimeGenerated > ago(7d)
| join kind=leftouter (AADServicePrincipalSignInLogs | where TimeGenerated > ago(7d))
on $left.SignInActivityId == $right.UniqueTokenIdentifier
| project TimeGenerated, AppId, ServicePrincipalName, IPAddress, RequestMethod, RequestUri, ResponseStatusCode

Tips

  • Set retention on the workspace (or per table) to suit your incident response needs. If you need it for years, also archive to storage.
  • Do this per customer tenant. A Graph activity log only covers the resource tenant, so you won’t see a multitenant app’s activity in other tenants.
  • Diagnostic settings can’t filter Graph logs. Use a workspace transformation if volume is an issue.

References: Graph activity logs overview and Configure Entra diagnostic settings.

What I’d do today, with the tools we have

  1. Turn on Graph activity logs now in every tenant with P1 (Business Premium has it). It’s cheap insurance.
  2. Export sign-in logs, including service principal sign-ins, beyond 30 days.
  3. Confirm MailItemsAccessed is being audited on every mailbox.
  4. Cut app permissions down. Use Exchange RBAC for Applications and Sites.Selected instead of tenant-wide Mail.* and Sites.* grants. https://learn.microsoft.com/en-us/exchange/permissions-exo/application-rbac
  5. Use Defender for Cloud Apps app governance where you have it, so you get alerts on unusual app behaviour. https://learn.microsoft.com/en-us/defender-cloud-apps/app-governance-manage-app-governance

Shared responsibility

This is the shared responsibility point again. The vendor protects its credential, Microsoft provides the logs, and we as MSPs own the decision to let that app in, which means having the logging on before we need it. My cw-skykick-exposure-check.ps1 script will help you with the exposure side. Graph activity logs are what answer “what did it actually touch?”

New script: Check your Microsoft 365 tenants for ConnectWise SkyKick exposure

Security analyst reviewing a Microsoft 365 tenant exposure report in a dark operations room

I’ve just added a new script to my Office365 repository on GitHub: cw-skykick-exposure-check.ps1. It does a read-only check of Microsoft 365 and Entra tenants for signs of exposure to the ConnectWise Cloud Backup (formerly SkyKick) vendor-credential incident, and produces a report you can act on.

If you’re an MSP with ConnectWise or SkyKick apps consented in customer tenants, you want answers quickly and across every tenant, not one portal click at a time. That’s what this is for.

What happened

According to Huntress’s advisory, a Microsoft 365 credential belonging to ConnectWise Cloud Backup was compromised and used on 15 October 2026 (UTC) to obtain Microsoft Graph tokens in customer tenants. Huntress also reports that in at least one tenant a ConnectWise Cloud Management app granted itself Global Administrator and added new secrets to other applications to keep a foothold. ConnectWise has acknowledged the incident. Huntress’s guidance is to disable (not delete) the affected apps, review the credentials on all your applications, and check service principal sign-ins and audit logs.

That review is exactly what the script automates.

What the script checks

For each tenant it runs four checks, then gives a verdict:

  • ConnectWise/SkyKick service principals: matched by seven known app IDs, display name or the ConnectWise owner tenant, with enabled state, directory roles, OAuth2 grants and app role assignments. A match holding a highly privileged role is flagged.
  • Service principal sign-ins since 1 October 2026 for those apps and the published indicator IP addresses, flagging indicator IPs and Python or curl user agents. This needs Entra ID P1 or P2.
  • Directory audit events since 13 October 2026 (role additions, application updates and new service principal credentials), plus a scan of every app registration and service principal for secrets or certificates whose validity starts in that window.
  • Conditional Access exclusions that cover the ConnectWise apps.
  • Verdict: Suspicious, Present-no-activity, Not present, Unknown or Error, with recommended actions.

It is strictly read-only. Every Graph call goes through a wrapper that only issues GET requests, so it never creates, changes, disables or deletes anything. If a check can’t run because of licensing or permissions, it’s reported as Unavailable rather than crashing, and one tenant failing never stops the rest.

How to run it

You’ll need PowerShell 7.4 or later and the Microsoft.Graph.Authentication module, plus read permissions: Application.Read.All, Directory.Read.All, AuditLog.Read.All, RoleManagement.Read.Directory and Policy.Read.All. For a single tenant with an interactive sign-in:

./cw-skykick-exposure-check.ps1 -TenantId contoso.onmicrosoft.com -UseDeviceCode

For many tenants unattended, supply a CSV of TenantId, ClientId and a certificate thumbprint or PFX path, with the PFX password injected through an environment variable. It’s the same certificate-based, app-only approach I described in my recent post on headless connections.

./cw-skykick-exposure-check.ps1 -TenantCsv ./tenants.csv -OutputPath ./reports

Each run writes three reports: a CSV with one summary row per tenant, a detailed JSON file, and a readable HTML report with times in Sydney time.

Read the results carefully

This is an investigation aid, not a forensic verdict. Not present means the checks found none of the configured matches; it doesn’t prove a tenant was never touched. Graph doesn’t expose when a credential was actually created, only when it becomes valid, so confirm every flagged secret or certificate was added by your team. And review the indicators and date windows against the latest advisories before you rely on them.

Get the script

Run it against a test tenant first, then across your customers. If you find a bug, a missed indicator or a way to make it better, let me know. Feedback from people running it in the real world is what makes these scripts better for everyone.

One macOS login that finally uses Entra

image

Most MSPs treat the Macs in a client tenant like orphans. Enrol them in Intune, push a couple of profiles, tick the box, move on.

But the user still signs into that Mac with a local password. One nobody rotates, nobody recovers, and nobody can tie back to a real person. The Entra identity you spent all that effort hardening — MFA, Conditional Access, the lot — stops dead at the macOS login window.

That’s not managed. That’s two identities wearing the same hoodie.

Platform SSO closes the gap. And here’s the part that annoys me: it’s been sitting in your Intune licence the entire time.

What is Platform SSO, really?

It’s the thing that finally makes a Mac sign in with Entra ID the same way a Windows device does with Windows Hello for Business.

When you turn it on, the Mac gets joined to your Entra tenant and a hardware-bound certificate is locked to the device. From then on, the user’s Entra account is their login. Touch ID unlocks the machine. Apps and browsers get single sign-on off the back of it. No more re-typing the work password into every prompt.

You pick one of three flavours — Secure Enclave, smart card, or password. Microsoft recommends Secure Enclave, and so do I. It’s passwordless, phishing-resistant, and conceptually identical to Windows Hello for Business. The other two exist for edge cases.

Here’s the real win: it’s included with every Intune licensing plan. No add-on, no separate SKU. If you’ve got Business Premium, you already own this.

Step-by-Step: turning it on

Portal only. No scripts.

Check the prereqs first

Devices need macOS 13 or newer — push for macOS 14 Sonoma(opens in new window) for the cleanest experience. The Company Portal app must be version 5.2404.0 or later, because that’s what carries the SSO plug-in. And the user has to be allowed to join devices to Entra. Miss any of these and registration silently never happens.

Build the profile

In the Intune admin center, go to Devices > Manage devices > Configuration > Create > New policy. Platform: macOS. Profile type: Settings catalog.

Drop in the values

In the settings picker, expand Platform SSO and add the core settings:

Authentication Method   UserSecureEnclaveKey
Extension Identifier     com.microsoft.CompanyPortalMac.ssoextension
Team Identifier          UBF8T346G9
Registration token       {{DEVICEREGISTRATION}}

Notice what’s missing? No password field. No certificate to mint. No on-prem ADFS box wheezing in a cupboard. The Mac proves who it is with a key baked into its own silicon.

Deploy Company Portal, then assign

Push the latest Company Portal as a required app — that’s what installs the plug-in. Then assign the policy. One catch that bites people: for devices with user affinity, assign to users, not device groups or filters. Get that wrong and Conditional Access can lock the user out of the very resources you were protecting.

Why this actually changes behaviour

The first time the policy lands, the user sees a “Registration required” notification. They click it, sign in with their Entra account, do MFA once, and it’s done.

That prompt trips up every first-timer. It looks like something broke. It didn’t. That’s the moment the device gets Entra-joined and the certificate binds. Tell your clients it’s coming and the support ticket never gets raised.

“Why does it still ask for my old Mac password after a reboot?”

Because FileVault uses the local password as the disk unlock key. So after a cold boot you enter it once — then Touch ID takes over for the rest of the session. That’s by design, not a half-finished feature. Worth saying out loud before a client assumes it’s flaky.

And if there’s still an on-prem domain in the picture, you can layer Kerberos SSO to on-premises Active Directory onto the same policy. The Mac quietly handles both worlds.

Get this in place and a client’s Mac stops being the weak identity in the room. Same MFA. Same Conditional Access. Same audit trail as every Windows device. One login, one identity, one set of rules.

If you’re rolling out Macs and not showing clients this, you’re handing them a managed device with an unmanaged front door.

Platform SSO isn’t there to make Mac logins prettier. It’s there to make the local password irrelevant.

Entra ID Password Protection + Smart Lockout

image


People still obsess over password complexity.

Twelve characters. Special symbols. Rotation every 90 days.

And yet accounts still get compromised.

That’s because attackers don’t guess random passwords anymore. They guess human passwords.

That’s not a complexity problem. That’s a behaviour problem.

So instead of arguing about password rules, I push clients to focus on two things they already have in Microsoft 365:

Password Protection and Smart Lockout.

Quietly running. Often ignored. Rarely tuned.

Here’s what actually matters.


What is Entra ID Password Protection + Smart Lockout, really?

It’s not a password policy.

It’s a filter and a shield.

Password Protection stops users from choosing bad passwords in the first place.

It uses a global banned password list driven by Microsoft telemetry and blocks weak or common passwords automatically—no configuration required. [learn.microsoft.com]

On top of that, you can add your own banned terms. Company names. Locations. Products. The obvious stuff attackers try first.

Then there’s Smart Lockout.

This is what most people misunderstand.

It’s not “lock the account after X attempts”.

That’s old thinking.

Smart Lockout can distinguish between a real user fat-fingering a password and an attacker trying thousands of guesses. [learn.microsoft.com]

Same identity. Different treatment.

Attackers get blocked quickly.

Real users keep working.

That’s not a nicer lockout policy.

That’s a signal-driven control.

“But we already have account lockout on-prem.”

Exactly.

And that’s the problem.


Step-by-Step: Tune Password Protection and Smart Lockout

Portal only. No scripts. No excuses.

1. Open Password Protection settings

Go to:

Entra admin centre
→ Protection
→ Authentication methods
→ Password protection

This is the only place you need.

2. Add a custom banned password list

Add terms like:

  • Company name variations

  • Internal product names

  • Common abbreviations

  • Location names

These get evaluated alongside the global list and block weak variants automatically. [learn.microsoft.com]

Not just exact matches.

Variants.

That’s the key.

3. Review Smart Lockout threshold

Default is:

Most SMBs never touch this.

My recommendation?

Lower it slightly only if you understand user behaviour.

Too low and you create support tickets.

Too high and you give attackers room to work.

You’re not tuning numbers.

You’re tuning friction.

4. Set lockout duration

Default starts short (around a minute) and increases with repeated attempts. [learn.microsoft.com]

That’s deliberate.

Short for users.

Painful for attackers.

If you override this, be careful.

Long lockouts punish users.

Short lockouts reward attackers.

5. Leave Smart Lockout on (always)

Important:

Smart Lockout is already enabled.

There’s nothing to “turn on”.

There’s only:

  • Leaving it alone

  • Or breaking it
6. Pair it with MFA (properly)

Password protection is not enough.

Microsoft is very clear on that.

Use it alongside MFA and Conditional Access. [learn.microsoft.com]

Otherwise you’re just slowing attackers down.

Not stopping them.


Why this actually changes behaviour

This is the part most MSPs miss.

These features don’t just block attacks.

They retrain users.

Bad password?

Rejected.

Repeated guessing?

Blocked.

Users learn quickly what works and what doesn’t.

No training session required.

No PDF sent out.

No awareness campaign.

The system corrects behaviour in real time.

“We’ll just educate users instead.”

You can.

Or you can enforce it once and let the platform do it forever.

Ask once. Enforce always.

Here’s the real win:

  • Fewer compromised accounts

  • Fewer lockout tickets

  • Fewer “why is this happening?” calls

And importantly:

  • Better outcomes with less effort

That’s the bit most people overlook.


Notice what’s missing?

No password complexity discussion.

No rotation debates.

No “special characters required”.

Because those don’t solve the real problem.

Attackers aren’t brute-forcing randomly anymore.

They’re spraying expected passwords across thousands of accounts.

Password Protection removes the obvious targets.

Smart Lockout kills the attack path.

Different layers.

Same outcome.


Passwords aren’t going away.

But weak passwords should.

And repeated guessing definitely should.

Password Protection isn’t there to make passwords stronger.

It’s there to make bad passwords impossible.

Most SMB tenants have a guest graveyard

image

Most SMB tenants I look at have a “Guest Users” list that’s basically a graveyard. People invited for a project that finished in 2022. A contractor whose engagement ended last March. Somebody’s external accountant who hasn’t signed in since the BAS that prompted the invite.

Nobody removes them. Nobody can remember why they were added. Nobody’s even sure who should remember.

That’s not a guest problem. That’s a governance problem.

Now do the same exercise with Global Administrator. Or Privileged Role Administrator. Or that mystery security group somebody pinned to a SharePoint site three years ago and called “Finance – All”. Same pattern. Stale access. No owner. No expiry.

This is exactly what Access Reviews in Entra ID Governance is built to fix — and most MSPs I talk to either don’t know they’re licensed for it or have never actually run one.

Time to fix that.

What is Access Reviews, really?

Access Reviews is a recurring “are you sure?” loop. You point it at a group, an application, a privileged role, or every guest in your tenant. On a schedule you pick, it emails a reviewer — you, the group owner, or the user themselves — and asks them to confirm whether each person still needs the access they’ve got.

If the reviewer says no, or doesn’t reply and you’ve configured “no response = deny”, the access gets removed automatically when the review ends. No tickets. No spreadsheet. No “I’ll get to it next quarter”.

It’s the same job your auditor wants you to do at a desktop level. Just done in the portal, on a timer, with an audit trail attached.

What you need to run one

Licensing trips most people up here. Access Reviews is an Entra ID P2 or Entra ID Governance feature, and licensing is per user, not per tenant. Every user whose access you’re reviewing needs to be covered. Guest accounts don’t need a license to be reviewed, which is the one bit of good news.

Business Premium customers don’t have P2 in the box. If they want this, they need Microsoft 365 E5 or the Entra ID Governance add-on. Tell the client up front — don’t promise the feature and discover the gap at invoice time.

You’ll want Identity Governance Administrator or Global Administrator to set the first review up. Group owners can run reviews on their own groups once an admin enables the toggle in the Access Reviews settings.

Step-by-Step: a recurring guest review

Start here on every tenant. It’s the easiest win.

Open the portal

Sign in to entra.microsoft.com as Identity Governance Administrator. Go to ID Governance > Access Reviews > New access review.

Pick what to review

In Select what to review, choose Teams + Groups, then All Microsoft 365 groups with guest users. This is the magic option. It creates one recurring review that sweeps every M365 group containing guests, across the whole tenant, automatically, forever.

Set Scope to Guest users only.

Pick your reviewers

Pick Group owners with a fallback. Group owners actually know whether Alice from the partner agency still needs Teams access. You don’t. You also don’t want to be reviewer-of-last-resort for fifty groups.

Set the schedule

Recurrence: Quarterly. Duration: 5 days. Long enough that nobody can claim they were on leave. Short enough that the next quarter doesn’t lap it.

Set the settings that actually matter

This is where most people skim and lose the whole value of the feature. Slow down.

  • Auto-apply results to resource: On. Without this, denied users stay in the group until somebody manually clicks apply. They never do.

  • If reviewers don’t respond: Remove access. Yes, really. If the owner can’t spend two minutes confirming a guest, the guest goes.

  • Justification required: On. Forces reviewers to type a reason for “keep”. Stops the rubber-stamp click-through.

  • Mail notifications + reminders: On.

Name it Quarterly Guest Review - All M365 Groups, hit Create, done.

Step-by-Step: privileged groups and admin roles

Same engine, different doorway. PIM for Entra roles and PIM for Groups each have their own access review entry point — not the one above.

For Entra admin roles

Open PIM > Microsoft Entra roles > Access reviews > New. Review every role with active or eligible assignments. Reviewer = the user themselves, because self-attestation forces them to type a justification. Add a second-stage approver if you want belt-and-braces. Recurrence: every 90 days for admin roles. No exceptions.

For privileged groups

If you’re using PIM for Groups to gate access to sensitive things, you can review the eligible members on the same cadence. Same wizard, hosted under PIM. Same settings. Same auto-apply.

Notice what’s missing? PowerShell. None of this needs it. Portal only.

One artefact you can paste into every client runbook
Guest access:     quarterly, 5-day window, owner-reviewed,
                  no response = remove, auto-apply on.
Admin roles:      every 90 days, self-attest + 2nd stage,
                  no response = remove, auto-apply on.
PIM for Groups:   every 90 days, owner-reviewed,
                  no response = remove, auto-apply on.

Notice what’s not in there? Anything called “annual”. Annual reviews don’t do anything except let stale access fester for eleven and a half months. If the cadence isn’t quarterly or better, you don’t have a control — you have a calendar reminder.

Why this actually changes behaviour

Before: “I’ll clean up guests when I get a chance.” After: “The system already did it last Tuesday.”

That’s the shift. Access Reviews moves access cleanup from a thing humans intend to do into a thing that happens whether they intend to or not.

For an MSP the win is bigger. Every client tenant you manage produces a quarterly evidence trail — who reviewed what, what got removed, who signed off. Exactly the evidence the cyber insurer asks for at renewal. Exactly the evidence an SMB1001 or Essential Eight auditor wants on the table. According to the Access Reviews FAQ, reviewers and decisions are captured against each instance, so the audit trail is already there — you just have to turn the reviews on.

You’re not selling “we’ll clean up your guests” anymore. You’re selling governance with a paper trail.

Access Reviews isn’t there to help you remember to remove stale access. It’s there to remove it whether you remember or not.

If you’re not turning this on for your clients, you’re leaving the easiest governance win in Microsoft 365 on the table.

Privileged Identity Management (PIM) for Entra roles

image

Walk into most SMB tenants and check who holds Global Administrator. You’ll find at least one. Often three. Sometimes more. All permanent. All active. All the time.

That’s standing privilege. And it’s the biggest gift you can hand a token thief.

Most MSPs I talk to know about Privileged Identity Management. They’ve seen it in the Entra admin centre. They just don’t switch it on for clients, because they assume it’s an enterprise thing — too expensive, too complicated, too overkill for a 25-seat business.

Wrong on all three.

What is PIM, really?

PIM is just-in-time admin access. You stop being a Global Administrator all day every day, and start being eligible for it. When you need the role, you put yourself in for a fixed window, with a justification and a record. A few hours later it drops off. You’re back to a normal user.

That’s not least privilege as a slogan. That’s least privilege as a clock.

You can layer MFA on activation, approval workflows where one admin signs off on another’s elevation, and access reviews that quietly remind you each quarter that someone’s eligibility hasn’t been used in 90 days. All portal-driven. No scripts. Microsoft’s overview of PIM is worth a read, but the licensing point is the one that trips everyone up.

PIM needs Entra ID P2 or Entra ID Governance. That’s not in Business Premium. But — and this is the part MSPs miss — you only need to licence the admins, not every seat. Three admin accounts is your premium. Compare that to one incident.

Step-by-step: switching on PIM for Global Administrator

Run through this in the Entra admin centre. Sign in as a Global Administrator and licence the admin accounts you want under PIM first.

Park a break-glass account

Before touching a role, create a dedicated break-glass admin. Permanent active Global Administrator. Long random password in your password manager. Excluded from every Conditional Access policy. Document it somewhere you can find at 2am.

This is the one account PIM doesn’t touch. Skip this step and you’ll lock yourself out the first time MFA goes sideways.

Open ID Governance

ID Governance → Privileged Identity Management → Microsoft Entra roles → Roles.

Configure role settings for Global Administrator

Select Global Administrator → Role settings → Edit. Microsoft documents every option here; the ones that earn their keep look like this:

Activation maximum duration:   4 hours
Require MFA on activation:     Yes
Require justification:         Yes
Require approval to activate:  Yes (2 approvers, not self)
Permanent eligible assignment: Disallowed
Notification on activation:    All Global Admins

Notice what’s missing? PowerShell. None of this needs it.

Move existing GAs from active to eligible

Assignments → find each Global Administrator → use the assign roles flow to make them eligible instead. Same permissions — only when they ask for them.

Schedule an access review

Under Access reviews, set up a quarterly review of all eligible Global Administrators. Configure it to auto-remove on no response. The clients who think this is overkill are the clients who’ll have an ex-staffer with admin rights twelve months from now.

Why this actually changes behaviour

PIM isn’t a tool. It’s a posture. The second a Global Admin has to type a reason and wait for approval, two things happen — they stop using GA for the trivial stuff, and someone else sees every elevation.

“But our admins will hate this.”

They’ll hate it for a week. Then they’ll forget it’s there, because activation is two clicks. And the first time you can prove with an audit log that no privileged account was active during an incident, you’ll wonder how you ran tenants any other way.

A standing Global Admin is a key under the doormat. PIM is the locksmith.

If you’re not setting this up for your clients, you’re leaving the front door open and calling it security.

Named locations + Conditional Access location-based policies

image

Most MSPs I talk to have a Conditional Access policy that blocks “high-risk countries”. They built it once, switched it on, and never looked at it again.

Then they sleep well at night.

That’s the problem.

A country block on its own is theatre. The attacker is on a VPN egress inside a country you allow, or a residential proxy, or a mailbox client that already has a refresh token. Named locations are useful — but only if you understand what they actually do, and where they fall down.

What is a named location, really?

A named location is a label. That’s it.

You’re telling Entra ID, “this IP range is my office”, or “these countries are where my staff actually work”. The location doesn’t enforce anything on its own. It’s a building block you then reference inside a Conditional Access policy.

The policy does the work. You decide whether to block, require MFA, or skip a control. The location is just the where.

And here’s the bit that bites people. Location is evaluated after first-factor authentication. The password’s already gone. Conditional Access then decides what happens next. Treat named locations as a layer, not a perimeter.

Step-by-Step: Setting up a country block that actually earns its keep

Portal path only. Report-only first — non-negotiable.

Open Named locations

Sign in to the Microsoft Entra admin centre as a Conditional Access Administrator. Go to Protection > Conditional Access > Named locations.

Create a Countries location

Click + Countries location. Name it something obvious — “Allowed countries — AU only” beats “Country Block 1”. Pick the country (or countries) where your staff actually sign in. Tick Include unknown areas if you want the location to also catch IPs the geo-database can’t classify. I leave that off for allow-lists and on for block-lists. Save.

Create the policy

Go to Policies > New policy. Name it. Under Users, pick All users — then exclude your break-glass accounts. Always. Under Target resources, pick All resources.

Set the network condition

Under Network, set Configure to Yes. Include Any network or location, then under Exclude select Selected networks and locations and pick your “Allowed countries” entry. That gives you “block everything outside my country”.

Grant

Under Access controls > Grant, choose Block access.

Switch to Report-only and review

Set Enable policy to Report-only. Create. Then watch the sign-in logs for at least 48 hours. The report-only results tell you exactly which users would have been blocked. Anyone surprising in there? Investigate. Then flip the policy on.

Why this actually changes behaviour

Here’s the real win. Once you’ve got clean named locations, every other CA policy gets sharper.

The “skip MFA from a trusted location” pattern — careful with that. Marking your office public IP as trusted feels like a productivity gift to users. It’s also the exact thing an attacker on your guest Wi-Fi or a compromised contractor on your VPN will piggyback. My recommendation? Don’t mark anything as trusted unless you have a strong reason and you’ve documented it. Use sign-in frequency and authentication strength to soften MFA friction instead.

“But our staff hate MFA prompts in the office.” Then fix the prompts. Don’t punch a hole in the wall.

The other classic trap is the corporate VPN. If everyone egresses through one public IP in a country you’ve blocked, you’ve just locked your own staff out. Map your VPN exits before you write the policy. Read the network assignment conditions before you write the policy, not after.

Notice what’s missing from all of this? PowerShell. You don’t need it. The portal does the job, and the audit trail is clearer.

A country block doesn’t stop attackers. It thins the noise so the rest of your stack can do real work. If you’re not showing your clients this — and explaining why “trusted location” is a loaded word — you’re leaving security maturity on the table.

That’s the job. Use named locations for that, and not for the warm feeling a checkbox gave you.

Entra ID backup just turned up in your Business Premium tenant

image

A few weeks ago I logged into a Business Premium tenant to do something completely unrelated and noticed a new node in the Entra portal: Backup and Recovery. No upsell banner, no add-on prompt, no “contact your reseller”. Just there. Sitting under Identity governance like it had always been part of the furniture.

That’s the bit worth pausing on. Microsoft has quietly turned identity backup into table stakes for every BP tenant. Notice what’s missing? An invoice.

For years the conversation around protecting your directory has been someone else’s product pitch. Third-party backup vendors built entire businesses on the fact that Microsoft wouldn’t restore a Conditional Access policy you nuked at 4pm on a Friday. Now Microsoft is restoring it for you.

What is Entra Backup and Recovery, really?

It’s a daily snapshot of the configuration that runs your tenant’s identity. Users, groups, applications, service principals, Conditional Access policies, named locations, the authentication methods policy — the things that, when they go missing, take down sign-in for your whole client base.

Five days of retention. Tamper-resistant. No global admin can switch it off, no compromised account can wipe the safety net before the bad thing happens. That’s not a feature. That’s governance.

Important caveats so you don’t sell something that isn’t there. Hard-deleted objects are gone — the recycle bin still does its 30-day job for users and groups, but Backup is for configuration recovery, not undeleting things. Hybrid identity synced from on-premises AD has limitations. Workforce tenants only — not B2C or External ID. And it’s currently in Public Preview, so treat it like one. The official overview is worth a read before you stand in front of a client.

A daily snapshot you can’t disable is more honest than a backup product you forget to renew.

Step-by-Step: turning it on for a Business Premium tenant
1. Sign into the Entra admin centre

Use a Global Administrator account. Navigate to Identity governance → Backup and Recovery. If the node isn’t there yet, give the tenant a day — rollout is staged.

2. Enable the service

It’s a single switch. Once enabled, the first snapshot is captured within 24 hours. There’s nothing to license — Business Premium already includes Entra ID P1, which is the bar.

3. Assign the right roles

There are two purpose-built ones: Microsoft Entra Backup Reader and Microsoft Entra Backup Administrator. Don’t hand recovery rights to every Global Admin out of habit. Restoring a Conditional Access policy from a five-day-old snapshot is exactly the sort of move you want logged against a named, scoped role.

4. Run a Difference Report before you restore anything

This is the part that earns its keep. Before recovering an object, the portal shows you what will change — what’s in the snapshot, what’s live, and where they disagree. You see the diff before you click. The supported objects and limitations(opens in new window) page tells you exactly what’s in scope.

Why this actually changes behaviour

Here’s the real win. The reason MSPs have been selling backup-for-Entra add-ons is fear — what if? That conversation gets harder when Microsoft has put a tamper-resistant safety net in the box.

My recommendation? Stop selling fear. Start showing governance. Walk your BP clients through their backup status, the role separation, and the recovery flow for applications and service principals. It takes ten minutes and it positions you as the person who knew this was already there, not the person trying to bolt something on top.

That’s not a product conversation. That’s an advisor conversation.

The relief, when you find it, isn’t the relief of buying a safety net. It’s the relief of finding one you didn’t have to install.