Open-source project · v1.0.0

ARGUS

The governance debt of your Microsoft 365 tenant, made visible.

A free PowerShell module that runs 73 read-only checks, computes a Governance Score and produces an HTML report that explains every finding and how to fix it.

Install-Module ARGUS
  • 73 checks
  • 7 areas
  • Read-only
  • PowerShell 7.2+
  • Windows · macOS · Linux
  • MIT licence

Nobody checks the tenant’s hygiene.

In Microsoft 365 tenant assessments I keep finding the same things: guests invited for projects that closed long ago, Teams without owners, licences paid for on disabled accounts, secrets expiring without anyone noticing. None of them is a security incident. Together they are governance debt: costs, access and data that nobody governs any more.

The tools I knew check security posture; operational hygiene needed scattered scripts and a lot of manual work. Copilot made it urgent: Copilot answers from everything a user can access, so forgotten oversharing ends up in its answers. ARGUS puts those checks into one repeatable command, with a report you can hand over.

What it is

  • A governance and hygiene assessment across 7 areas: Entra ID, app registrations, licensing, groups and Teams, SharePoint and OneDrive, Exchange Online, Copilot and agents.
  • Strictly read-only: it never writes, changes or deletes anything in the tenant.
  • Lightweight: Microsoft.Graph.Authentication is enough. When an optional module is missing, the checks that need it are Skipped with the reason, never errors.
  • One HTML file with no external dependencies, in light and dark mode, printable as PDF.

What it is not

  • Not a security baseline: no CIS, CISA, MFA, Conditional Access or Defender checks. Dedicated tools such as Maester cover those.
  • Not a remediation tool: it tells you what to change; you decide and apply it. The sample code in the report is never executed.

One command, one report.

  1. 01

    Connect

    Connect-Argus

    Interactive sign-in or app-only with a certificate. Microsoft Graph is enough to start; Exchange Online and SharePoint are added when needed.

  2. 02

    Run

    Invoke-Argus

    73 read-only checks, in one or two minutes on a tenant with a few hundred users.

  3. 03

    Read the report

    HTML · JSON · CSV

    Governance Score, results by area and, for every check, what was found, why it matters and how to fix it.

From the command to the report in just over a minute. In the parts recorded on my lab tenant identifiers are blurred; the report explored is the one of the fictitious tenant.

The report, live on this page.

It is a real report, generated by ARGUS on a fictitious tenant. Filter, search, open the checks and their findings: it works just like on your PC.

Open full screen

One number, explained.

Each check weighs according to its severity. The score says how much of the evaluated weight is in order, for the whole tenant and for each area.

Weight by severity

  • Critical10
  • High5
  • Medium3
  • Low1
  • Info0

Credit by result

  • Passed100%
  • To review50%
  • Failed0
  • Skippedleft out

Score = 100 × Σ(weight × credit) / Σ(evaluated weight)

  1. A≥ 90
  2. B≥ 75
  3. C≥ 60
  4. D≥ 40
  5. F< 40

When less than 70% of the selected weight can be evaluated (missing licences or permissions), the score is labelled as partial.

73 checks, one by one.

What each check looks at and why it matters. Permissions, parameters and remediation code are in the documentation on GitHub.

73 checks

  • ARG.ENT.001 Enabled members inactive for more than 90 days Entra ID Medium

    What is checked

    Enabled member accounts whose last successful sign-in (interactive or non-interactive) is older than 90 days, including accounts that never signed in and were created more than 90 days ago. Uses signInActivity.lastSuccessfulSignInDateTime, falling back to the last sign-in attempt for activity before December 2023.

    Why it matters

    Accounts nobody uses keep their group memberships, app access and licences. Reviewing them regularly is the basis of identity lifecycle governance.

    Technical details and remediation on GitHub
  • ARG.ENT.002 Licensed users without manager or department Entra ID Low

    What is checked

    Enabled member users with at least one licence whose manager or department is empty in Microsoft Entra ID (GET /users?$expand=manager). Accounts without licences (service, shared and emergency accounts) are not evaluated; use the global exclusions for licensed accounts that are not people.

    Why it matters

    Manager and department drive access reviews, approval workflows, dynamic groups, the organisation chart and the people Copilot considers relevant. Missing values usually mean the HR provisioning or the joiner process skipped a step, and they make every later governance step manual.

    Technical details and remediation on GitHub
  • ARG.ENT.003 Guest invitations are restricted Entra ID Medium

    What is checked

    Reads who can invite guests (authorizationPolicy.allowInvitesFrom): none or adminsAndGuestInviters pass; adminsGuestInvitersAndAllMembers (all members can invite) needs review; everyone (guests can invite other guests too) fails.

    Why it matters

    Who can bring external people into the tenant is a governance decision. Letting guests invite other guests removes the organisation from that decision.

    Technical details and remediation on GitHub
  • ARG.ENT.004 Guests that never accepted the invitation (more than 30 days) Entra ID Medium

    What is checked

    Guest accounts whose externalUserState is still PendingAcceptance more than 30 days after they were invited (externalUserStateChangeDateTime, or createdDateTime when not set).

    Why it matters

    Unredeemed invitations clutter the directory, are often typos or abandoned collaborations, and can be redeemed later by whoever controls the mailbox.

    Technical details and remediation on GitHub
  • ARG.ENT.005 Guests inactive for more than 90 days Entra ID Medium

    What is checked

    Enabled guest accounts that accepted their invitation but have not signed in for 90 days, including guests that never signed in and were added more than 90 days ago. Guests still pending acceptance are covered by ARG.ENT.004.

    Why it matters

    Guests keep access to Teams, sites and files after the collaboration has ended. Removing inactive guests limits what external people can still reach.

    Technical details and remediation on GitHub
  • ARG.ENT.006 Guests without a sponsor Entra ID Medium

    What is checked

    Enabled guest users with no sponsor (GET /users?$expand=sponsors). Sponsors are the users or groups responsible for the guest's access and information; Microsoft Entra sets the inviter as sponsor for new invitations, so guests without one were usually invited before sponsors existed, lost a sponsor that left, or were invited by sharing a SharePoint file (a known case where no sponsor is set). Skipped when the account cannot read sponsors.

    Why it matters

    Without a sponsor nobody is accountable for the guest: access reviews have no reviewer, and the guest stays after the collaboration ends. A sponsor (a person or, better, a group) makes guest lifecycle decisions possible.

    Technical details and remediation on GitHub
  • ARG.ENT.007 At least 2 emergency access (break-glass) accounts Entra ID High

    What is checked

    Looks for emergency access accounts: the accounts listed in the Accounts parameter (UPNs or object ids) or, when the list is empty, users whose UPN or display name matches NamePatterns. An account is compliant when it follows the configuration requirements Microsoft documents: enabled, member, cloud-only (not synchronised), UPN on a *.onmicrosoft.com domain, and an active Global Administrator assignment made directly to the account (not only eligible in PIM, not through a group). Fails when fewer than 2 compliant accounts exist. Authentication methods, Conditional Access exclusions and sign-in alerting are part of the same guidance but are security controls outside the scope of ARGUS: verify them separately. Global exclusions are not applied.

    Why it matters

    Emergency access accounts prevent the organisation from being locked out of its tenant when federation, MFA or the usual administrators are unavailable. Microsoft recommends two or more, cloud-only, with a permanent active Global Administrator assignment.

    Technical details and remediation on GitHub
  • ARG.ENT.008 Global Administrator count outside 2 to 4 Entra ID High

    What is checked

    Counts the distinct holders of the Global Administrator role: active assignments and, with Entra ID P2, eligible (PIM) assignments. Members of role-assignable groups that hold the role are counted individually. Fails when the count is below 2 or above 4. Global exclusions are not applied: emergency-access accounts must be counted.

    Why it matters

    Too few Global Administrators risks losing control of the tenant; too many makes the most powerful role hard to govern. Keep two emergency-access accounts plus a small number of named administrators, and delegate the rest to least-privileged roles.

    Technical details and remediation on GitHub
  • ARG.ENT.009 Directory roles assigned to guests Entra ID High

    What is checked

    Any Microsoft Entra directory role (active, or eligible with Entra ID P2) held by a guest account, directly or through a role-assignable group.

    Why it matters

    Administrative roles should be held by accounts the organisation controls. A guest account follows the lifecycle of another tenant: when the person leaves their company, nobody here is notified.

    Technical details and remediation on GitHub
  • ARG.ENT.010 Users can register applications Entra ID Medium

    What is checked

    Reads authorizationPolicy.defaultUserRolePermissions.allowedToCreateApps ("Users can register applications" in User settings). Fails when every user can create app registrations.

    Why it matters

    App registrations created by anyone end up without an owner, a purpose or a credential policy. Restricting creation to the Application Developer role keeps the application estate governable.

    Technical details and remediation on GitHub
  • ARG.ENT.011 Users can create tenants Entra ID Low

    What is checked

    Reads authorizationPolicy.defaultUserRolePermissions.allowedToCreateTenants ("Restrict non-admin users from creating tenants" in User settings). Fails when non-admin users can create Microsoft Entra tenants.

    Why it matters

    A tenant created by a user becomes a separate directory where that user is Global Administrator, outside the organisation's governance and visibility.

    Technical details and remediation on GitHub
  • ARG.ENT.012 LinkedIn account connections disabled Entra ID Low

    What is checked

    The LinkedIn account connections setting (Microsoft Entra admin center > Users > User settings) lets users connect their work account to LinkedIn in Microsoft apps. It is enabled by default, except for organisations provisioned in Germany or France. Microsoft Graph has no documented API to read this setting, so ARGUS cannot evaluate it: the result is always Investigate and the setting must be checked manually. Expected value: No (or Selected group, if a business need was approved).

    Why it matters

    Once a user consents, Microsoft apps exchange profile and connection data between the work account and LinkedIn. Whether to allow it is an organisation decision about data sharing with a third-party service, and it should be explicit rather than left at the default.

    Technical details and remediation on GitHub
  • ARG.ENT.013 Security groups without owners Entra ID Low

    What is checked

    Cloud security groups with assigned membership and no owner. Dynamic groups, role-assignable groups, mail-enabled security groups (managed in Exchange) and groups synchronised from on-premises Active Directory are not evaluated.

    Why it matters

    Without an owner, nobody is accountable for who is in the group and what the group grants access to.

    Technical details and remediation on GitHub
  • ARG.ENT.014 Stale devices (no sign-in for more than 180 days) Entra ID Low

    What is checked

    Devices whose approximateLastSignInDateTime is older than 180 days (or that never signed in and were registered more than 180 days ago). Both enabled and disabled devices are listed; disabled ones are usually ready to be deleted.

    Why it matters

    Stale devices make device inventories, Conditional Access reporting and licence counts unreliable.

    Technical details and remediation on GitHub
  • ARG.ENT.015 Directory synchronisation is up to date Entra ID Medium

    What is checked

    For hybrid tenants (organization.onPremisesSyncEnabled = true), fails when the last directory synchronisation (onPremisesLastSyncDateTime) is older than 24 hours. Cloud-only tenants are skipped.

    Why it matters

    When synchronisation stops, changes made on-premises (leavers disabled, group changes) no longer reach Microsoft 365, and governance decisions are based on stale data.

    Technical details and remediation on GitHub
  • ARG.APP.001 App registrations without owners Applications Medium

    What is checked

    App registrations with no owner. The findings show how many secrets and certificates each app holds: an ownerless app with credentials is the first to review.

    Why it matters

    Without an owner nobody is accountable for the app's permissions, credentials and lifecycle, and nobody notices when it is no longer needed.

    Technical details and remediation on GitHub
  • ARG.APP.002 Client secrets expiring within 30 days Applications Medium

    What is checked

    Client secrets (passwordCredentials) of app registrations that expire within the next 30 days. A secret counts as replaced when the same app already has another secret valid beyond that window; the check fails only for secrets without a replacement.

    Why it matters

    An expired secret stops the integration that uses it. Planned rotation, owned by someone, avoids outages discovered by users.

    Technical details and remediation on GitHub
  • ARG.APP.003 Expired client secrets still present Applications Low

    What is checked

    Client secrets (passwordCredentials) whose endDateTime is in the past but that are still attached to the app registration.

    Why it matters

    Expired secrets are clutter that hides which credentials are really in use and makes credential reviews harder.

    Technical details and remediation on GitHub
  • ARG.APP.004 Client secrets with a lifetime above 24 months Applications Low

    What is checked

    Valid client secrets whose lifetime (endDateTime minus startDateTime) exceeds 24 months. The admin center limits new secrets to 24 months, but secrets created through the API or before that limit can last much longer. Expired secrets are covered by ARG.APP.003.

    Why it matters

    Long-lived secrets are rarely rotated and outlive the people and documentation that explain them. Microsoft recommends less than 12 months, or certificates and managed identities instead.

    Technical details and remediation on GitHub
  • ARG.APP.005 Certificates expiring within 30 days Applications Medium

    What is checked

    Certificates (keyCredentials with usage Verify, used by the app to authenticate) that expire within the next 30 days. A certificate counts as replaced when the same app already has another certificate valid beyond that window; the check fails only for certificates without a replacement.

    Why it matters

    An expired certificate stops app-only integrations (automation, connectors, scripts). Planned renewal avoids outages.

    Technical details and remediation on GitHub
  • ARG.APP.006 Expired certificates still present Applications Low

    What is checked

    Certificates (keyCredentials, any usage) whose endDateTime is in the past but that are still attached to the app registration.

    Why it matters

    Expired certificates are clutter that hides which credentials are really in use and makes credential reviews harder.

    Technical details and remediation on GitHub
  • ARG.APP.007 Certificates with a lifetime above 180 days Applications Low

    What is checked

    Valid authentication certificates (keyCredentials with usage Verify) whose lifetime (endDateTime minus startDateTime) exceeds 180 days. Expired certificates are covered by ARG.APP.006.

    Why it matters

    Microsoft recommends limiting application certificate lifetime to 180 days and automating renewal. Long-lived certificates are rarely rotated and stay valid long after the people who deployed them have moved on.

    Technical details and remediation on GitHub
  • ARG.LIC.001 Disabled users that still have licences Licensing High

    What is checked

    Disabled accounts (accountEnabled = false) with at least one licence. Shared, room and equipment mailboxes are excluded using Exchange Online (they are disabled by design and may legitimately need a licence). When Exchange Online is not connected they cannot be told apart, so the result is Investigate.

    Why it matters

    A licence on a disabled account is paid for but cannot be used. Leavers are the most common cause.

    Technical details and remediation on GitHub
  • ARG.LIC.002 Enabled licensed users inactive for more than 90 days Licensing High

    What is checked

    Enabled member accounts with at least one licence that have not signed in for 90 days (same inactivity logic as ARG.ENT.001: last successful sign-in, accounts that never signed in count from their creation date). The findings list the licences assigned to each account.

    Why it matters

    Licences assigned to people who no longer use them are recurring cost with no business value, and the accounts keep access nobody reviews.

    Technical details and remediation on GitHub
  • ARG.LIC.003 Paid licences assigned to guest users Licensing Medium

    What is checked

    Guest users (userType = Guest) with at least one paid licence. Free, viral and trial SKUs are ignored (IgnoredSkus, trial subscriptions from /directory/subscriptions), as in ARG.LIC.006. Guests normally work with the licences of their home organisation or with the B2B allowance; a paid seat on a guest is usually a mistake or a leftover.

    Why it matters

    Licences assigned to guests cost a full seat, are rarely reviewed and often stay after the collaboration ends. When a guest really needs a licence, it should be a documented decision with a sponsor, not the side effect of a group-based assignment.

    Technical details and remediation on GitHub
  • ARG.LIC.004 Users with overlapping licences Licensing Medium

    What is checked

    Users with two paid SKUs where every service plan of one SKU is also in the other (from subscribedSkus.servicePlans), typically a standalone product or an older suite next to the suite that includes it. The contained SKU is redundant. The comparison uses service plan IDs, so it needs no list of SKU names; free, viral and trial SKUs are ignored as in ARG.LIC.006.

    Why it matters

    Overlapping licences usually come from upgrades where the old SKU was never removed, or from two licensing groups that both include the user. The contained seat is paid twice and blocks a seat that could go to someone else.

    Technical details and remediation on GitHub
  • ARG.LIC.005 Licence assignment errors Licensing Medium

    What is checked

    Users whose licenseAssignmentStates contain an entry in state Error (the licence is not assigned) or ActiveWithError (assigned, but part of it failed). The error column shows the reason reported by Microsoft Entra ID, for example CountViolation (not enough seats), MutuallyExclusiveViolation or ProhibitedInUsageLocationViolation. Group names are shown when groups could be read.

    Why it matters

    Assignment errors leave users without the services they are expected to have, and usually go unnoticed when licences are assigned through groups.

    Technical details and remediation on GitHub
  • ARG.LIC.006 Unused licences per SKU Licensing Medium

    What is checked

    Compares purchased seats (prepaidUnits.enabled) with assigned seats (consumedUnits) for every active, user-assignable SKU (capabilityStatus = Enabled, appliesTo = User). A SKU fails when more than 10% or more than 5 seats are unused. Free, viral and developer SKUs (the IgnoredSkus list), SKUs with 10,000 or more seats (free offers are provisioned with very large quantities) and trial SKUs (isTrial in /directory/subscriptions) are ignored.

    Why it matters

    Unused seats are a recurring cost with no business value. Reviewing them before each renewal is the simplest licence saving.

    Technical details and remediation on GitHub
  • ARG.LIC.007 Shared mailboxes with a licence Licensing Low

    What is checked

    Shared mailboxes (Exchange Online) whose user object has licences assigned. A shared mailbox needs a licence only when it is larger than 50 GB, has an online archive, or is on litigation hold or an in-place hold. Mailboxes that meet one of these conditions (size of 50 GB or more, archive active, LitigationHoldEnabled, non-empty InPlaceHolds) are not listed; the others are returned for review (Investigate), because organisation-wide retention policies and other needs are not visible to this check.

    Why it matters

    Shared mailboxes are often licensed when a user mailbox is converted and the licence is never removed: a recurring cost with no benefit.

    Technical details and remediation on GitHub
  • ARG.LIC.008 Paid licences assigned directly to users Licensing Low

    What is checked

    Users with at least one paid licence assigned directly (licenseAssignmentStates entry without assignedByGroup) instead of through group-based licensing. Free, viral and developer SKUs (the IgnoredSkus list), SKUs with 10,000 or more seats and trial SKUs (isTrial in /directory/subscriptions) are not counted: they are usually self-service sign-ups. AlsoFromGroup lists the direct licences the user also receives from a group, where the direct assignment is redundant.

    Why it matters

    Direct assignments are not driven by group membership: they are not removed when a person changes role or leaves, and they are hard to audit at scale. Group-based licensing keeps paid licences consistent with joiner/mover/leaver processes.

    Technical details and remediation on GitHub
  • ARG.GRP.001 Microsoft 365 group creation is restricted Groups & Teams Medium

    What is checked

    Reads EnableGroupCreation and GroupCreationAllowedGroupId in the tenant-wide Group.Unified directory setting. When the setting was never created every user can create Microsoft 365 groups and Teams (default). Unrestricted creation is Investigate: it is a valid choice for some organisations, provided ownership and expiration are governed.

    Why it matters

    Every new Team or Planner plan creates a Microsoft 365 group with a mailbox and a SharePoint site. Without a creation policy, sprawl and duplicates grow quickly; restricting creation to trained users or adding a request process keeps it governed.

    Technical details and remediation on GitHub
  • ARG.GRP.002 Group naming policy configured Groups & Teams Low

    What is checked

    Reads PrefixSuffixNamingRequirement and CustomBlockedWordsList in the tenant-wide Group.Unified directory setting. Passes when a prefix/suffix rule or a blocked-words list is configured. The naming policy requires Microsoft Entra ID P1 for the users it applies to.

    Why it matters

    A naming convention (for example a GRP- prefix or a department attribute) makes groups and Teams easy to recognise in the address book, in Teams and in SharePoint; blocked words prevent misleading names.

    Technical details and remediation on GitHub
  • ARG.GRP.003 Group expiration policy configured Groups & Teams Medium

    What is checked

    Reads groupLifecyclePolicies. Fails when no expiration policy exists or when it applies to no group (managedGroupTypes = None); a policy that applies only to selected groups is Investigate. Groups with recent activity are renewed automatically, so active owners are not disturbed.

    Why it matters

    Without an expiration policy, Microsoft 365 groups and Teams that are no longer used stay forever with their content, guests and permissions. Expiration asks owners to confirm that the group is still needed.

    Technical details and remediation on GitHub
  • ARG.GRP.004 Microsoft 365 groups and Teams without owners Groups & Teams High

    What is checked

    Microsoft 365 (Unified) groups, including the ones connected to Teams, with no owner.

    Why it matters

    Nobody manages membership, guests or content of an ownerless group, nobody receives its expiration notices, and nobody can approve access requests. Microsoft recommends at least two owners per group.

    Technical details and remediation on GitHub
  • ARG.GRP.005 Microsoft 365 groups and Teams with a single owner Groups & Teams Low

    What is checked

    Microsoft 365 (Unified) groups, including Teams, with exactly one owner. The Owner column shows who it is and OwnerEnabled whether that account is still enabled; groups whose only owner is disabled are listed first.

    Why it matters

    A single owner is a single point of failure: when that person leaves or changes role the group becomes ownerless. Microsoft recommends at least two owners.

    Technical details and remediation on GitHub
  • ARG.GRP.006 Teams with guests and no owner Groups & Teams High

    What is checked

    Teams (Microsoft 365 groups with a team) that have no owner and at least one guest member. Members of the ownerless Teams are read with JSON batching (GET /groups/<id>/members/microsoft.graph.user, first 999 members).

    Why it matters

    Guests in a team without owners keep access to its chats, files and site, and nobody reviews or removes them. These Teams are the first to fix among ownerless groups (ARG.GRP.004).

    Technical details and remediation on GitHub
  • ARG.GRP.007 Public Microsoft 365 groups Groups & Teams Medium

    What is checked

    Microsoft 365 (Unified) groups with visibility = Public. Anyone in the organisation can join a public group, or its team, and read its conversations, files and site without approval. The Team column shows whether a team is connected.

    Why it matters

    Public groups are fine for organisation-wide communities, but projects, departments and customer work usually hold content that should be limited to members. Reviewing them keeps visibility a deliberate choice.

    Technical details and remediation on GitHub
  • ARG.GRP.008 Inactive Teams (more than 180 days) Groups & Teams Low

    What is checked

    Teams whose Last Activity Date in the Teams team activity report (getTeamsTeamActivityDetail, period D180) is older than 180 days, or empty (no activity recorded in the report period). Teams created less than 180 days ago and teams that no longer exist are ignored when groups can be read. With concealed report names, or when the report returns no rows, the result is Investigate.

    Why it matters

    Inactive Teams keep content, guests and permissions that nobody curates. Archiving or deleting them keeps search, storage and access reviews meaningful.

    Technical details and remediation on GitHub
  • ARG.SPO.001 SharePoint site creation is restricted SharePoint & OneDrive Medium

    What is checked

    Reads admin/sharepoint/settings.isSiteCreationEnabled ("Users can create SharePoint sites" in the SharePoint admin center) and isSiteCreationUIEnabled. When users can create sites, communication sites and team sites without a group can be created by anyone, even if Microsoft 365 group creation is restricted (ARG.GRP.001): Investigate, as it is a valid choice for some organisations.

    Why it matters

    Self-service sites multiply quickly, often without a clear owner, classification or lifecycle. Restricting creation, or routing it through a request process with a template, keeps the site estate governable and the Copilot index clean.

    Technical details and remediation on GitHub
  • ARG.SPO.002 Tenant external sharing level SharePoint & OneDrive Medium

    What is checked

    Reads the organisation-level sharing setting for SharePoint and OneDrive (admin/sharepoint/settings.sharingCapability). Anyone (externalUserAndGuestSharing: links that do not require sign-in) is reported as Investigate; New and existing guests, Existing guests only and Only people in your organisation pass. The findings also show the domain restriction mode and whether guests can reshare. Individual sites can only be more restrictive than this setting.

    Why it matters

    Anyone links can be forwarded to people outside the organisation without any record of who opened them. Many organisations allow them on purpose for a few sites; the tenant-wide level should be a conscious decision with site-level restrictions where needed.

    Technical details and remediation on GitHub
  • ARG.SPO.003 Default sharing link is limited to specific people SharePoint & OneDrive Medium

    What is checked

    Reads the default link type of the sharing dialog with PnP.PowerShell (Get-PnPTenant): CoreDefaultShareLinkScope for SharePoint and OneDriveDefaultShareLinkScope for OneDrive, falling back to DefaultSharingLinkType when they are Uninitialized. Anyone as default fails; People in your organisation (or the widest allowed link) is Investigate; Specific people passes. Needs Connect-Argus -Service SharePoint; otherwise the check is Skipped.

    Why it matters

    Most people accept the default link. A default of Anyone or of the whole organisation turns every quick share into broad access, which is the main source of oversharing that Copilot later surfaces in answers. Specific people as default keeps sharing intentional.

    Technical details and remediation on GitHub
  • ARG.SPO.004 Anyone links expire within 30 days SharePoint & OneDrive Medium

    What is checked

    When the organisation allows Anyone links (sharingCapability = externalUserAndGuestSharing), reads RequireAnonymousLinksExpireInDays with PnP.PowerShell (Get-PnPTenant). Fails when Anyone links never expire (0 or not set) or expire after more than 30 days. Passes without evaluation when Anyone links are not allowed. Needs Connect-Argus -Service SharePoint; otherwise the check is Skipped.

    Why it matters

    An Anyone link works for whoever has it, for as long as it exists. An expiration limit bounds how long a forwarded or leaked link stays usable, without forbidding Anyone links where the business needs them.

    Technical details and remediation on GitHub
  • ARG.SPO.005 Guest access to sites and files expires SharePoint & OneDrive Medium

    What is checked

    Reads ExternalUserExpirationRequired and ExternalUserExpireInDays with PnP.PowerShell (Get-PnPTenant): whether guests lose access to sites and files after a number of days unless a site owner renews it. Fails when the policy is off. Passes without evaluation when external sharing is disabled (sharingCapability = disabled). Needs Connect-Argus -Service SharePoint; otherwise the check is Skipped.

    Why it matters

    Guests invited for a project keep access long after it ends. An expiration policy makes site owners confirm, periodically, who still needs access; it complements guest reviews in Entra ID (ARG.ENT.005).

    Technical details and remediation on GitHub
  • ARG.SPO.006 Sites that allow Anyone links SharePoint & OneDrive Low

    What is checked

    Site collections (PnP.PowerShell Get-PnPTenantSite, OneDrive excluded) whose own sharing setting is ExternalUserAndGuestSharing (Anyone). Listed as Investigate: Anyone links may be intended on some sites, but each one should be known. Passes without evaluation when the organisation does not allow Anyone links. Needs Connect-Argus -Service SharePoint; otherwise the check is Skipped.

    Why it matters

    The organisation level sets the maximum; each site inherits it unless an administrator restricts it. Knowing which sites can create Anyone links lets you keep that capability only where it has a business owner and a reason.

    Technical details and remediation on GitHub
  • ARG.SPO.007 Sites without a sensitivity label SharePoint & OneDrive Low

    What is checked

    Site collections (PnP.PowerShell Get-PnPTenantSite, OneDrive and system sites excluded) without a sensitivity label (SensitivityLabel empty). When no site has a label at all, sensitivity labels are probably not used for sites and groups: the result is To review instead of Failed. Needs Connect-Argus -Service SharePoint; otherwise the check is Skipped.

    Why it matters

    A container label sets the privacy, external sharing and guest access of a site in one place and tells users and Copilot how sensitive its content is. Once labels are in use, unlabelled sites are the ones that escape those controls and the classification.

    Technical details and remediation on GitHub
  • ARG.SPO.008 Orphaned SharePoint sites SharePoint & OneDrive High

    What is checked

    Group-connected sites whose Microsoft 365 group has no owner (site URL read with JSON batching, GET /groups/<id>/sites/root). When SharePoint is connected through PnP.PowerShell, sites without a Microsoft 365 group (classic team sites, communication sites) are also evaluated: a site is orphaned when its primary site collection administrator (Owner in Get-PnPTenantSite) is empty, disabled or no longer exists. Without PnP those sites are not evaluated and the summary says so.

    Why it matters

    Nobody manages permissions, sharing or content of a site without a responsible owner, and access requests go unanswered. Orphaned sites are also the hardest to clean up later.

    Technical details and remediation on GitHub
  • ARG.SPO.009 Inactive SharePoint sites (more than 180 days) SharePoint & OneDrive Low

    What is checked

    SharePoint sites whose Last Activity Date in the site usage report (getSharePointSiteUsageDetail, period D180) is older than 180 days or empty (no activity in the report period). Deleted sites and system sites (ExcludedTemplates: search center, compliance policy center, tenant fundamental site, app catalog) are ignored; OneDrive accounts are not part of this report. When the report leaves Site URL empty (a known issue of the usage reports), the URL is read from the Site Id: first from the PnP tenant site list when SharePoint is connected (it includes private group and channel sites), then with GET /sites/<id>, which in delegated mode only reads the sites the account can access; the owner falls back to Owner Display Name and is "Not reported" when the report has none. With concealed report names, or when the report returns no rows, the result is Investigate.

    Why it matters

    Inactive sites hold content and permissions that nobody curates, use storage and appear in search. Reviewing them regularly keeps the information architecture clean.

    Technical details and remediation on GitHub
  • ARG.SPO.010 Sites near their storage quota (more than 90%) SharePoint & OneDrive Low

    What is checked

    SharePoint sites whose used storage is more than 90% of the allocated storage, from the site usage report (Storage Used (Byte) / Storage Allocated (Byte), period D180). Deleted sites and sites without an allocation are ignored. With concealed report names, or when the report returns no rows, the result is Investigate. When the report leaves Site URL empty (a known issue of the usage reports), the URL is read from the Site Id: first from the PnP tenant site list when SharePoint is connected (it includes private group and channel sites), then with GET /sites/<id>, which in delegated mode only reads the sites the account can access.

    Why it matters

    A site that reaches its quota becomes read-only for new content, which interrupts work. Planning quota increases or clean-up in advance avoids that.

    Technical details and remediation on GitHub
  • ARG.SPO.011 OneDrive retention for deleted users is at least 90 days SharePoint & OneDrive Low

    What is checked

    Reads admin/sharepoint/settings.deletedUserPersonalSiteRetentionPeriodInDays: how long the OneDrive of a deleted user is kept before it is deleted (30 days by default, up to 3650). Fails when it is shorter than 90 days.

    Why it matters

    After a user is deleted, the manager has only this period to find and move business files from the OneDrive. Thirty days is often shorter than the time it takes to notice that something is missing, especially when the leaver process runs late.

    Technical details and remediation on GitHub
  • ARG.SPO.012 OneDrive of deleted or disabled users with content SharePoint & OneDrive Low

    What is checked

    OneDrive accounts from the OneDrive usage report (getOneDriveUsageAccountDetail, period D180) that still hold content (Storage Used (Byte) > 0, not deleted) while their owner is disabled or no longer exists in Microsoft Entra ID. The OneDrive of a deleted user is kept for the retention period set in the SharePoint admin center (30 days by default) and then deleted. With concealed report names, or when the report returns no rows, the result is Investigate. When the report leaves Site URL empty (a known issue of the usage reports; this report has no Site Id), the URL comes from the mySite property of the user, or is derived from the UPN with the OneDrive naming convention when the user no longer exists (UrlSource column).

    Why it matters

    Files of people who left stay in OneDrives that nobody looks after, with their sharing links still active. Deciding what to keep and transferring it to a manager or a site is part of the leaver process.

    Technical details and remediation on GitHub
  • ARG.SPO.013 OneDrives near their storage quota (more than 90%) SharePoint & OneDrive Low

    What is checked

    OneDrive accounts from the OneDrive usage report (getOneDriveUsageAccountDetail, period D180) whose Storage Used (Byte) is more than 90% of Storage Allocated (Byte). Deleted accounts and accounts without an allocation are ignored. With concealed report names, or when the report returns no rows, the result is Investigate. When the report leaves Site URL empty (a known issue of the usage reports; this report has no Site Id), the URL comes from the mySite property of the user, or is derived from the UPN with the OneDrive naming convention when the user no longer exists (UrlSource column).

    Why it matters

    A full OneDrive stops syncing and saving, and users start keeping files on local disks or personal storage. Accounts close to the limit need a cleanup, a move of team content to SharePoint, or a higher quota.

    Technical details and remediation on GitHub
  • ARG.EXO.001 Shared mailboxes with sign-in enabled Exchange Online Medium

    What is checked

    Shared mailboxes (Exchange Online) whose user account in Microsoft Entra ID is enabled (accountEnabled = true). People access shared mailboxes through their own accounts and mailbox permissions; the account of the shared mailbox itself does not need to sign in.

    Why it matters

    An enabled shared mailbox account has a password that nobody owns, is often excluded from reviews, and lets anyone who knows the password sign in directly instead of through audited delegate access.

    Technical details and remediation on GitHub
  • ARG.EXO.002 Shared mailboxes without delegates Exchange Online Low

    What is checked

    Shared mailboxes with no explicit FullAccess permission (Get-EXOMailboxPermission: not inherited, not denied, NT AUTHORITY\SELF ignored). Send As and Send on Behalf permissions are not considered: without FullAccess nobody can open the mailbox. One Exchange call per shared mailbox.

    Why it matters

    A shared mailbox nobody can open still receives mail that nobody reads, often from customers or suppliers. Every shared mailbox should have named people responsible for it.

    Technical details and remediation on GitHub
  • ARG.EXO.003 Inactive shared mailboxes (more than 90 days) Exchange Online Low

    What is checked

    Shared mailboxes (Exchange Online) whose Last Activity Date in the mailbox usage report (getMailboxUsageDetail, period D180) is older than 90 days, or empty for mailboxes created before that. The report has no recipient type, so shared mailboxes are identified through Exchange Online. With concealed report names, or when the report returns no rows, the result is Investigate.

    Why it matters

    Shared mailboxes created for projects, events or old processes outlive their purpose. Unused ones keep permissions, addresses and sometimes licences that nobody reviews.

    Technical details and remediation on GitHub
  • ARG.EXO.004 Inactive user mailboxes (more than 90 days) Exchange Online Low

    What is checked

    Mailboxes whose Last Activity Date in the mailbox usage report (getMailboxUsageDetail, period D180) is older than 90 days, or empty for mailboxes created before that. When Exchange Online is connected only user mailboxes are evaluated; otherwise the report also contains shared mailboxes, which is noted in the summary. With concealed report names, or when the report returns no rows, the result is Investigate.

    Why it matters

    A user mailbox nobody uses usually belongs to a leaver or a forgotten test account: it keeps a licence, mail and permissions without a reason.

    Technical details and remediation on GitHub
  • ARG.EXO.005 User mailboxes of disabled accounts Exchange Online Low

    What is checked

    User mailboxes (RecipientTypeDetails = UserMailbox) whose Microsoft Entra account is disabled (accountEnabled = false). Mailboxes on litigation hold or with in-place holds are counted as kept on purpose and not listed. Shared, room and equipment mailboxes are out of scope (their accounts are meant to be disabled).

    Why it matters

    A disabled user with a live user mailbox is a leaver process that stopped halfway: mail keeps arriving, nobody reads it, and the mailbox usually keeps a licence. Converting it to a shared mailbox, delegating it or deleting it closes the process.

    Technical details and remediation on GitHub
  • ARG.EXO.006 Mailboxes near their quota (more than 90% of the warning quota) Exchange Online Low

    What is checked

    User and shared mailboxes from the mailbox usage report (getMailboxUsageDetail, period D180) whose Storage Used (Byte) is more than 90% of Issue Warning Quota (Byte) (the size at which the owner starts receiving warnings; Prohibit Send Quota is used when no warning quota is set). The findings also show how close the mailbox is to Prohibit Send. When Exchange Online is connected the mailbox type (user, shared, room, equipment) is shown. Deleted mailboxes and mailboxes without a quota are ignored. With concealed report names, or when the report returns no rows, the result is Investigate.

    Why it matters

    Users can react to quota warnings, shared mailboxes cannot: nobody receives their warnings, and they stop accepting mail without notice once they reach the limit. Mailboxes past or near the warning quota need an archive, a retention policy, a cleanup or, for shared mailboxes above 50 GB, a licence.

    Technical details and remediation on GitHub
  • ARG.EXO.007 Mailboxes with forwarding configured (inventory) Exchange Online Low

    What is checked

    Inventory of mailboxes with mailbox-level forwarding (ForwardingSmtpAddress or ForwardingAddress in Get-EXOMailbox). A forwarding SMTP address whose domain is not a verified domain of the tenant is marked External; ForwardingAddress points to a recipient in the directory (it can be a mail contact outside the organisation). Inbox rules are not evaluated. Listed as To review: forwarding is often legitimate, but each one should have an owner and a reason, and forwarding left on leaver mailboxes should be removed.

    Why it matters

    Forwarding set years ago keeps copying mail to addresses nobody reviews, sometimes outside the organisation and after the owner left. Knowing where mail is forwarded, and why, is part of mailbox lifecycle governance; blocking automatic external forwarding is a security control outside the scope of ARGUS.

    Technical details and remediation on GitHub
  • ARG.EXO.008 User mailboxes without a mailbox hold (informational) Exchange Online Info

    What is checked

    Counts user mailboxes with Litigation Hold (LitigationHoldEnabled) or an in-place, eDiscovery or retention hold listed in InPlaceHolds, and lists the ones with neither. Organisation-wide Microsoft Purview retention policies are not visible to ARGUS (they need the Security & Compliance PowerShell), so a mailbox without a mailbox hold may still be retained: this check is always To review when such mailboxes exist. Info severity: it does not change the score.

    Why it matters

    Whether mail must be preserved, for how long and for whom, is a records-management decision. Holds set mailbox by mailbox drift over time; knowing which mailboxes have one, and confirming that a retention policy covers the others, keeps the retention strategy consistent with legal requirements.

    Technical details and remediation on GitHub
  • ARG.EXO.009 Distribution groups without owner Exchange Online Low

    What is checked

    Distribution groups and mail-enabled security groups (Exchange Online, Get-DistributionGroup) with an empty ManagedBy list, so only Exchange administrators can manage them.

    Why it matters

    Without an owner, membership and delivery restrictions of a distribution list are not maintained, nobody can approve join requests, and the list keeps sending mail to people who left or changed role.

    Technical details and remediation on GitHub
  • ARG.EXO.010 Empty distribution groups Exchange Online Low

    What is checked

    Distribution groups and mail-enabled security groups (Get-DistributionGroup) without members, read through Microsoft Graph (GET /groups/<id>/members?$top=1, sent in $batch). Groups whose members could not be read are left out of the evaluation. Dynamic distribution groups are not included.

    Why it matters

    An empty distribution group still accepts mail, which then reaches nobody, and clutters the address book. Empty groups are usually left over from projects or reorganisations and can be removed.

    Technical details and remediation on GitHub
  • ARG.COP.001 Self-service purchase and trials of Copilot products are disabled Copilot & agents Medium

    What is checked

    Reads the AllowSelfServicePurchase policy of every product whose name contains "Copilot" with the MSCommerce module (Get-MSCommerceProductPolicies). Fails when a Copilot product is Enabled (users can buy it and start trials) or OnlyTrialsWithoutPaymentMethod (users can start trials). MSCommerce needs Connect-Argus -Service Commerce, interactive sign-in and Windows; otherwise the check is Skipped.

    Why it matters

    Self-service purchases create licences, invoices and data-processing commitments outside the IT and procurement process. Copilot licences bought by individuals are not covered by the organisation's rollout plan, readiness work (oversharing, sensitivity labels) or budget.

    Technical details and remediation on GitHub
  • ARG.COP.002 Users cannot sign up for self-service trials (Copilot Studio, Power Platform) Copilot & agents Medium

    What is checked

    Reads authorizationPolicy.allowedToSignUpEmailBasedSubscriptions. When it is true, users can sign themselves up for email-based ("viral") subscriptions such as the Copilot Studio and Power Apps trials, and start building agents and apps without an assigned licence. allowEmailVerifiedUsersToJoinOrganization is shown for context.

    Why it matters

    Self-service sign-ups put agent and app creation outside any licence, environment or data policy decision. Agents built on trial licences are hard to inventory and often stop working, or keep running, after the trial ends.

    Technical details and remediation on GitHub
  • ARG.COP.003 Copilot licences unused for more than 30 days Copilot & agents Medium

    What is checked

    Users from the Microsoft 365 Copilot usage report (copilot/reports/getMicrosoft365CopilotUsageUserDetail, period D180), which lists only users with a Microsoft 365 Copilot licence, whose Last Activity Date is older than 30 days or empty (no Copilot use in the last 180 days). With concealed report names, or when the report returns no rows, the result is To review. Skipped when no Microsoft 365 Copilot licence is detected.

    Why it matters

    Copilot licences are among the most expensive seats in Microsoft 365. Seats that are not used should go to people on the waiting list, or the user needs adoption support; either way the licence decision should be revisited.

    Technical details and remediation on GitHub
  • ARG.COP.004 Anthropic models as a Microsoft subprocessor (manual review) Copilot & agents Info

    What is checked

    The "AI providers operating as Microsoft subprocessors" setting (Microsoft 365 admin center > Copilot > Settings) controls whether Anthropic models can be used in Copilot, Researcher, Copilot Studio, Power Platform and Copilot in Microsoft 365 apps. No Microsoft API exposes it, so this check is always To review: it reads the tenant country (organization.countryLetterCode) and states the default that applies. Anthropic is on by default in the commercial cloud and off by default in the EU, EFTA and the UK. Info severity: it does not change the score.

    Why it matters

    As a Microsoft subprocessor Anthropic is covered by the Microsoft Product Terms and DPA, but Anthropic models are excluded from the EU Data Boundary and from in-country processing commitments. For organisations subject to the GDPR this is a data-transfer decision that should be documented (records of processing, DPIA where required) and limited to approved users.

    Technical details and remediation on GitHub
  • ARG.COP.005 Anthropic models with Data Retention, independent processor (manual review) Copilot & agents Info

    What is checked

    "Anthropic models with Data Retention" (for example some Fable- and Mythos-class models) are offered under Anthropic's own Commercial Terms and Data Processing Addendum: Anthropic acts as an independent processor, outside the Microsoft Product Terms and DPA, and retains inputs and outputs. They are off by default in every region and must be enabled explicitly in the Microsoft 365 admin center. No Microsoft API exposes the setting, so this check is always To review. Info severity: it does not change the score.

    Why it matters

    With these models prompts, files and responses are stored by Anthropic (most data up to 30 days, flagged content longer) under terms the organisation signs directly with Anthropic. That is a separate data-processing relationship and, for EU organisations, an international transfer that needs its own legal assessment.

    Technical details and remediation on GitHub
  • ARG.COP.006 Web search in Copilot is a deliberate choice Copilot & agents Low

    What is checked

    Reads the tenant-level "Allow web search in Copilot" Cloud Policy setting (GET /beta/copilot/admin/policySettings/microsoft.copilot.allowwebsearch, delegated sign-in only). When the policy is not configured, web search is available in Copilot and Copilot Chat (unless optional connected experiences are disabled): To review. The meaning of each configured value is not documented, so a configured value is To review unless it is listed in the DisabledValues parameter after you verified it in the Cloud Policy service. A group-scoped policy cannot be read by this API and is also To review.

    Why it matters

    With web search on, Copilot sends search queries derived from prompts (and sometimes from open documents) to Bing. Microsoft acts as data controller for those queries: the DPA, HIPAA and the EU Data Boundary do not apply to them. Whether that is acceptable is a privacy decision the organisation should take explicitly.

    Technical details and remediation on GitHub
  • ARG.COP.007 Copilot enhanced personalization (memory) is a deliberate choice Copilot & agents Low

    What is checked

    Reads the enhanced personalization control (GET /beta/copilot/settings/people/enhancedpersonalization). When isEnabledInOrganization is true and no disabledForGroup is set, Copilot memory and personalized recommendations are on for everybody: To review. Passed when the control is off, or on with a group excluded.

    Why it matters

    Enhanced personalization lets Copilot use each user's Teams chats, emails, meeting transcripts, usage signals and profile to remember preferences across conversations. The data stays within the user's scope, but it is a new processing purpose that privacy notices and works-council agreements may need to cover.

    Technical details and remediation on GitHub
  • ARG.COP.008 Agent creation and access are controlled (manual review) Copilot & agents Info

    What is checked

    Who can use and install agents (Agents > Settings > User access, and Agent and plugin access) is set in the Microsoft 365 admin center, and who can build agents in Copilot Studio is set per Power Platform environment. No Microsoft API exposes these settings to read-only tools, so this check is always To review and lists what to verify. ARG.COP.002 covers self-service trial sign-up. Info severity: it does not change the score.

    Why it matters

    When every user can build and run agents, agents connect to data, connectors and external services faster than they can be inventoried. A governed path (approved makers, approved agent types, a managed environment) keeps agents owned, reviewed and retired.

    Technical details and remediation on GitHub
  • ARG.COP.009 Users can register agent identity blueprints Copilot & agents Medium

    What is checked

    Reads authorizationPolicy.defaultUserRolePermissions.allowedToCreateAgentIdentityBlueprints ("Users can register agent identity blueprints" in Entra ID > Users > User settings) from the beta endpoint (GET /beta/policies/authorizationPolicy); v1.0 does not return it and Learn does not document it yet. Fails when every user without an admin role can create agent identity blueprints, the default from the November 2026 rollout. The setting is independent of "Users can register applications" (ARG.ENT.010). Skipped when the tenant does not return the property yet.

    Why it matters

    An agent identity blueprint is the template and credential holder for the agent identities created from it. Blueprints created by any user have no reviewed owner, purpose or permission scope, and every agent built on them inherits that gap. Restricting creation to administrators keeps agent identities inventoried and governed.

    Technical details and remediation on GitHub
  • ARG.COP.010 Org-wide agent sharing is restricted (manual review) Copilot & agents Info

    What is checked

    The Sharing setting (Microsoft 365 admin center > Agents > Settings > Sharing) decides who can share agents built with Copilot Agent Builder (Copilot Studio lite) with the whole organisation: All users (default), No users, or Specific users. Sharing with named people stays possible in every case. No Microsoft API exposes the setting, so this check is always To review. Info severity: it does not change the score.

    Why it matters

    An agent shared with everyone answers from the knowledge sources its creator chose, for every user who opens it. Restricting org-wide sharing to a few publishers keeps the agent catalogue curated and avoids duplicate or unreviewed agents reaching the whole company.

    Technical details and remediation on GitHub
  • ARG.COP.011 Agents from external publishers available to all users Copilot & agents Low

    What is checked

    Packages of the agent catalogue (GET /copilot/admin/catalog/packages) with type = external (built by partners), not blocked, and availableTo = all users. Each one is To review: external agents process data under the publisher's own terms. Requires a Microsoft Agent 365 licence; otherwise the check is Skipped.

    Why it matters

    Data processed by non-Microsoft agents and plugins is not covered by Microsoft agreements. Making them available to everybody should follow a review of the publisher's data handling, ideally with access limited to the teams that need them.

    Technical details and remediation on GitHub
  • ARG.COP.012 Agent requests pending for more than 7 days Copilot & agents Low

    What is checked

    Packages with an open user request (GET /copilot/admin/catalog/packages?$filter=requestStatus eq 'pending': publish, activate, access or update) whose lastModifiedDateTime is older than 7 days. The API exposes the package's last change, not the request date, so the age is approximate. Requires a Microsoft Agent 365 licence; otherwise the check is Skipped.

    Why it matters

    An approval process only works when requests are answered. Requests left open push users to workarounds (personal agents, shadow tools) and leave the catalogue out of date.

    Technical details and remediation on GitHub

Three commands.

Without parameters ARGUS connects to Microsoft Graph only: the Exchange Online and SharePoint checks are Skipped. For every area, app-only and least privilege follow the guide on GitHub.

PowerShell 7
# Once
Install-Module ARGUS -Scope CurrentUser

# Sign in and run
Connect-Argus
Invoke-Argus

Questions, ideas or a check to suggest? Discussions · Issues. If it helps you, a star on GitHub helps others find it.