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.

New scripts: Headless SharePoint and Exchange Online connections on Linux, built for agents

Cartoon of a relaxed IT professional with a coffee while a laptop and small server work on their own

I’ve just added two new scripts to my Office365 repository on GitHub. One connects PowerShell to SharePoint Online using PnP PowerShell. The other connects to Exchange Online. Both run on Linux, and both use certificate-based, app-only authentication. There’s no browser, no typed password and no MFA prompt at connection time.

Why bother building Linux versions? Mostly because of agents.

Built for machines that nobody is sitting at

More and more of my admin work now gets done by autonomous agents like Grok Bot, running on a Linux computer that no person is logged into. An agent like that can write and run PowerShell happily enough. Where it gets stuck is sign-in. A pop-up browser window, a device code that someone has to type in, or an MFA approval on a phone all stop it in its tracks. Automation that needs a human to tap “approve” isn’t really automation.

Certificate-based app-only authentication fixes that. You register an app in Entra, upload the public half of a certificate, keep the private key on the machine, and the script connects as the app. I’ve covered the Windows side before in Certificate-Based Authentication for SharePoint Online: The Bit Everyone Avoids and A Cleaner Way to Connect PowerShell to Exchange Online. These new scripts are the Linux counterparts, built so an agent’s computer can connect and get on with the job unattended.

What the scripts do

Both scripts work the same way and have two main modes:

  • -GenerateLocalCertificate creates an RSA-2048/SHA256 certificate, a public .cer file and an encrypted .pfx using .NET, so you don’t need OpenSSL.
  • -UseCertificateAuth connects with the encrypted PFX: PnP.PowerShell for SharePoint, ExchangeOnlineManagement for Exchange.
  • -ProvisionEntraApp (optional) creates or reuses an Entra app, uploads the public certificate, grants the required permissions and saves a connection profile. This setup step uses a one-off device-code sign-in by an administrator.

For true headless runs, use -noprompt (alias -Headless). Supply the PFX password through a SecureString parameter, or name an environment variable with -CertificatePasswordEnvironmentVariable. The scripts never print or save that password. Saved profiles mean that, once set up, an agent can connect with little more than -UseCertificateAuth -ProfileName Contoso -Headless.

You’ll need Linux and PowerShell 7.4 or later (7.4.6+ for the PnP script), plus PnP.PowerShell 3.0.0+ or ExchangeOnlineManagement 3.5.0+. Missing modules install for the current user, with no sudo needed. Use -noupdate to skip update checks.

A word on security

Unattended access is powerful, so treat it with respect. The SharePoint provisioning grants Sites.FullControl.All, which means full control of every site. The Exchange provisioning grants Exchange.ManageAsApp and adds the app to Organization Management, which means full Exchange administration. The scripts keep certificates and profiles in dedicated folders locked to mode 700, with files at mode 600, and they refuse symbolic links there. Even so, that .pfx is effectively an admin key. Guard it, keep its password in a vault or a protected environment variable, and only put it on machines you trust. If your scenario needs less, trim the app’s permissions.

Get the scripts

To me, this is where Microsoft 365 administration is heading. More of the routine work will be done by agents on machines that nobody watches, and the bottleneck is getting them connected securely without a human in the loop. Take the scripts, try them in a test tenant, and let me know how you go.

A Cleaner Way to Connect PowerShell to Microsoft Teams

image

If you still rely on Connect-MicrosoftTeams with an interactive sign-in every time you need to do some administration, you already know the frustration.

Scripts stop and wait for credentials. Scheduled tasks simply can’t run unattended. MFA prompts interrupt automation. And if you’re managing multiple tenants as an MSP, jumping between browser windows and authentication prompts quickly becomes tedious.

Microsoft has supported certificate-based authentication for Teams PowerShell for some time. The challenge hasn’t been the technology. The challenge has been the setup.

I’ve created a script that handles that process for me, removing most of the manual work and making certificate-based authentication something I can deploy consistently across customer tenants. The approach follows the same design philosophy I’ve been using for Exchange Online and other Microsoft 365 workloads: automate the plumbing so I can focus on the outcome. You can find it here:

https://github.com/directorcia/Office365/blob/master/o365-connect-tms-cert.ps1

and the documentation is here:

https://github.com/directorcia/Office365/wiki/Certificate-based-connection-for-Teams

What the Script Actually Does

The script operates in two primary modes.

The first mode, -GenerateLocalCertificate, creates a self-signed certificate on the local machine and exports the information needed for authentication. If required, it can also provision the Entra ID application automatically. The local certificate becomes the device’s identity when connecting to Teams PowerShell.

The second mode, -UseCertificateAuth, performs the actual Teams connection using the existing certificate and application registration. No password. No browser pop-up. No MFA prompt in the middle of an automated process.

The really useful feature is combining certificate generation with application provisioning. In a single operation the script can:

  • Create the local certificate

  • Authenticate to Microsoft Graph using device code authentication

  • Create or reuse an Entra ID application registration

  • Upload the certificate to the application

  • Create the required service principal

  • Assign the necessary permissions

  • Store the configuration details for future use

Tasks that typically involve multiple portals, several copy-and-paste operations, and more than a few opportunities to make mistakes can be reduced to a single repeatable process.

Why Certificate Authentication Matters

The biggest advantage is that you’re no longer tying automation to an admin account.

Traditional approaches often depend on an account that someone logs into interactively. That works fine until MFA settings change, conditional access rules are updated, or the account password expires.

Certificate authentication shifts the trust model. Instead of trusting a username and password, Microsoft validates the certificate installed on the machine against the certificate registered in Entra ID. If they match, the connection succeeds. If they don’t, access is denied.

That makes the solution both more secure and more reliable.

For MSPs, it also provides a cleaner operational model. Each technician workstation can have its own certificate while sharing the same application registration inside the customer tenant. If a machine is retired or a staff member leaves, removing the associated certificate immediately blocks access from that device without affecting anyone else.

The MSP Advantage

This is where the approach starts to shine.

A common question is whether every machine requires a separate application registration. The answer is no.

The design I prefer is a single Teams application per tenant with multiple certificates attached to it. Each device gets its own unique certificate, but all of them authenticate through the same application registration. That keeps administration simple while still maintaining proper separation between devices.

When a new technician needs access:

  1. Run the provisioning process.

  2. Generate a new certificate.

  3. Associate it with the existing application.

  4. Start working.

When access needs to be removed:

  1. Delete the certificate association.

  2. Access from that machine immediately stops.

No password resets. No account changes. No disruption for other administrators.

Getting Started

If you’re still connecting to Teams PowerShell interactively for daily administration, I’d encourage you to investigate certificate-based authentication.

The technology isn’t new. What’s important is reducing the complexity required to deploy it.

The real benefit isn’t that you save a few clicks when connecting. The real benefit is that you create a repeatable, secure authentication framework that supports automation, improves operational consistency, and removes dependence on administrator credentials.

For MSPs managing multiple tenants, that’s a significant improvement.

The less time I spend authenticating, the more time I spend solving customer problems. And that, ultimately, is the point.

A Cleaner Way to Connect PowerShell to SharePoint Online

image

Connect-PnPOnline with a browser sign-in is fine when you’re sitting at the keyboard. It becomes a problem the moment you’re not. The script that worked beautifully on your laptop refuses to run unattended. The scheduled job that was meant to tidy up orphaned sites overnight quietly does nothing, because it’s still waiting for someone to type a password. And the moment conditional access tightens on the admin account you’ve been quietly using for automation, every script that touches SharePoint behaves like it’s been thrown out a window.

The fix has existed. The setup hasn’t.

Certificate-based app authentication for SharePoint Online has been supported by Microsoft for years. The mechanics are well documented. The trouble has always been the assembly — generate a cert, export the public key, register an app in Entra ID, paste the right GUIDs in the right boxes, find Sites.FullControl.All in the API permissions list, grant admin consent, copy the thumbprint somewhere you won’t lose it, and verify the tenant ID in three different places along the way. By the time you’ve finished, you’ve forgotten which client you were doing it for.

So I’ve written a script that does the whole sequence end to end:

  • Generates a self-signed RSA-2048 certificate in your local certificate store

  • Creates the Entra ID app registration

  • Uploads the certificate and grants Sites.FullControl.All with admin consent

  • Provisions the service principal and adds Application.Read.All on Graph so the app can read its own metadata back

  • Resolves your tenant’s SharePoint root URL automatically from the Graph verified-domains call

  • Saves tenant, app ID, site URL, and thumbprint into a JSON profile so future connections need almost no parameters

What’s normally half an hour of clicking between Entra, the SharePoint admin centre, and a Notepad full of half-remembered GUIDs runs in about ninety seconds.

I’ve been written a new script — https://github.com/directorcia/Office365/blob/master/o365-connect-pnp-cert.ps1

with full documentation here – https://github.com/directorcia/Office365/wiki/Connect-to-SharePoint-Online-with-Certificates

What the Script Actually Does

There are two modes, controlled by switches.

-GenerateLocalCertificate creates a self-signed RSA-2048 certificate in your current user’s certificate store, exports the public key as a .cer file, and optionally exports a password-protected .pfx. By default it’s valid for two years. That’s the local side of the handshake.

-UseCertificateAuth is the everyday mode. You tell it which tenant to connect to — or let it look up the details in a profile map file — and it signs into Exchange Online using that certificate. No password. No browser. No MFA dialog.

The clever bit is the third option: combining -GenerateLocalCertificate with -ProvisionEntraApp -Tenant 'contoso.onmicrosoft.com'. In a single run, the script will generate the local certificate, authenticate to Microsoft Graph via a device-code flow, create the Entra ID app registration if it doesn’t exist, upload the certificate, grant Exchange.ManageAsApp and Application.Read.All with admin consent, create the matching service principal, sign you into Exchange Online to add the app to the Organization Management role group, and save the tenant, app ID, and certificate thumbprint to a JSON profile file so future connections don’t need any of those parameters.

Getting Started

If you’re new to certificate auth, the first run is the one that matters. Drop the script onto an admin machine, open PowerShell, and run:

.\o365-connect-pnp-cert.ps1 -GenerateLocalCertificate -ProvisionEntraApp -Tenant 'yourtenant.onmicrosoft.com'

You’ll be prompted to sign in — via device code for the Graph permissions (which if you use the –copydevicecodetoclipboard, option will put the required device code straight into the clipboard to paste into the request). You need a Global Admin account.

Where this earns its keep across a client base

After that first run, connecting to a tenant looks like this:

.\o365-connect-pnp-cert.ps1 -UseCertificateAuth -Tenant ‘contoso.onmicrosoft.com’

No password. No browser. No MFA prompt. The profile file is the bit that pays you back across an MSP book. One script lives in your tooling folder, each client has its own certificate and entry in the JSON map, and Task Scheduler can finally drive things like site collection audits, sharing reports, lifecycle cleanup on Teams-connected sites, and external-user reviews without anyone watching it run. Filter by tenant or site URL on the command line and the same script services twenty different customers without you ever editing it.

One honest caveat

When you’ve just provisioned a brand-new app, give Entra fifteen to thirty minutes for the role grants to replicate before your first cert-based connect. It’s the single most common reason a fresh setup looks broken when it isn’t. The script flags this on the way out, but it’s worth saying twice.

Why Certificates Beat Passwords

The security argument is the easy one. A certificate’s private key never leaves the machine that generated it. Nothing crosses the wire that an attacker could intercept and replay. There’s no shared secret to rotate across a team, no admin password sitting in a vault that someone might extract, and no MFA bypass to engineer because the flow doesn’t involve a user account at all.

If the certificate is ever compromised, you remove the key credential from the app registration and the access is gone — no password reset required, no impact on any human admin account.

The script enforces TLS 1.2, refuses to assign RBAC if the PnP session has landed in the wrong tenant, warns when the certificate is within thirty days of expiry, and keeps the device-code value off the clipboard by default to avoid leaks on RDP or shared sessions.

The change is a quiet one. You stop thinking about who is signing in and start thinking about which certificate is presenting itself. Once your SharePoint automation is no longer at the mercy of someone else’s MFA settings or a password rotation policy, the kind of work you’re willing to schedule expands. That’s the real win — not the ninety seconds saved on setup, but the chores you finally get around to doing.

New Publication – Achieving SMB1001:2026, M365 PowerShell Automation Guide

blog

https://directorcia.gumroad.com/l/smb1001-2006-ps

Achieving SMB1001:2026. Microsoft 365 PowerShell Automation Guide

Unlock the highest level of security, compliance, and operational efficiency with the definitive PowerShell automation guide for SMBs, MSPs, and IT professionals.

Why Choose This Guide?
  • Production-Ready Automation: Deploy fully-scripted, repeatable, and auditable solutions for every major security and compliance control in Microsoft 365 Business Premium—no more guesswork or manual errors.

  • Comprehensive Coverage: Includes 12 essential technology management controls (firewall, antivirus, patching, BitLocker, application allow-listing, EDR, and more) and 18 access management controls (account lifecycle, MFA, privileged access, email security, etc.), all mapped to the SMB1001:2026 standard.

  • Built for Professionals: Perfect for Managed Service Providers (MSPs), IT administrators, and security teams managing multiple tenants or seeking to implement infrastructure-as-code and configuration-as-code best practices.

  • Audit-Ready Evidence: Every script is designed to generate compliance evidence, validation reports, and audit artifacts—making regulatory audits and client reporting effortless.

  • Idempotent & Safe: All automation is designed to be safely re-run, ensuring consistent results and minimizing risk in live environments.

  • Best Practice Guidance: Each control includes not just scripts, but also implementation notes, validation steps, and operational best practices—so you’re never left wondering “what’s next?”

  • Legal & Licensing Clarity: Single-user, non-commercial license with clear terms; organizational and commercial use available by arrangement.

Key Benefits
  • Achieve and Maintain Compliance: Streamline your journey to SMB1001:2026 Level 5 (Diamond) compliance with proven, field-tested automation.

  • Reduce Risk: Enforce least-privilege, automate patching and security baselines, and block legacy threats—dramatically lowering your attack surface.

  • Save Time and Resources: Replace hours of manual configuration with one-click, script-driven deployments and validations.

  • Centralize and Standardize: Manage all tenants, devices, and users from a single, consistent playbook—ideal for MSPs and multi-tenant environments.

  • Stay Audit-Ready: Generate and maintain all the evidence you need for regulatory, insurance, or client audits—automatically.

Who Should Buy This Guide?
  • MSPs managing Microsoft 365 environments for multiple clients.

  • IT Administrators seeking robust, repeatable, and documented security/compliance deployments.

  • Security Teams needing automated compliance validation and evidence collection.

  • Organizations implementing infrastructure-as-code and aiming for best-in-class security posture.

What’s Inside?
  • Step-by-step PowerShell scripts for every control, with validation and compliance checks.

  • Modular structure for easy adoption—implement what you need, when you need it.

  • Quick reference tables, evidence checklists, and compliance calendars.

  • Guidance for integrating with HR, ITSM, Azure Key Vault, and Microsoft Graph APIs.

  • Best practices for onboarding, offboarding, privileged access, password management, backup, recovery, and more.


Don’t just meet compliance—automate it, prove it, and stay ahead of evolving threats.
Purchase the SMB1001:2026 PowerShell Automation Guide and transform your Microsoft 365 security and compliance operations today!

See all the titles available at – https://directorcia.gumroad.com/

PowerShell script to extract Exchange Online data for your own AI analysis

A while ago I wrote a script that reads Microsoft 365 security information and exports it to a JSON data file. The idea is that you can take this data file and use it with your AI of choice. I have now developed a similar script but for Exchange Online information.

Screenshot 2026-02-01 213211

When you run the script it will connect to Exchange online and extract the information from a variety of locations

Screenshot 2026-02-01 213303

It will produce 2 output JSON files in the parent directory. The standard data file can be quite large, in the case above it is around 15MB. The other file produced is more ‘compact’ around 100 – 200KB

Screenshot 2026-02-01 213701

You can then take either of these JSON files and feed them into you AI system of choice. The above shows you the result when I fed it into Copilot Researcher.,

Screenshot 2026-02-01 214046

and I even got a nice Word document when I fed it into Claude online.

You can download the script here:

https://github.com/directorcia/Office365/blob/master/Analysis/Exchange/exo-extract.ps1

and find the documentation here:

https://github.com/directorcia/Office365/wiki/Extract-Exchange-Online-information

as well as a long prompt you can use with your Ai of choice here:

https://github.com/directorcia/Office365/blob/master/Analysis/Exchange/prompt-long.txt

Given that email systems are typically at the highest security risk, this script shoudl allow you to quickly and easily evaluate its posture as well as giving you a range of improvement suggestions.