The commands
Published
All seven carry that label: the Engine's reference lists them and records no validation state for them, so this page claims none beyond their being published. They stay at the top level, outside the groups, because signing in comes before choosing a service. connect was already in earlier releases; the other six arrived in 1.0.0b10, and without login every command still signs in for itself.
| Command | What the Engine's reference says it does |
|---|---|
m365g login | sign in and keep the session for later commands. The only command that keeps one |
m365g status | which connection later commands will use. Reaches no tenant |
m365g connection list | every stored connection. Reaches no tenant |
m365g connection use | make a stored connection the active one. Reaches no tenant |
m365g connection remove | remove a stored session and its record, as logout --name |
m365g logout | remove a stored session and its record |
m365g connect | reach a tenant and say what was established. Collects nothing |
login, connect and a logout that has a kept sign-in to clear reach a tenant. status, connection list and connection use read the local record and reach nothing.
Installing it
Published
One package installs both names. Version 1.0.0b10 of m365-governance-as-code installs m365g and m365-governance, and the manual's installation page says how, platform by platform.
pipx install m365-governance-as-code==1.0.0b10
m365g --versionThe two names are one command line. Whatever is typed after m365-governance in the manual can be typed after m365g, and the earlier command names behave as they did. The Engine's release notes record what was measured before the release: an installation of the previous version was upgraded, both names were run from outside any checkout, the packaged fixtures, rules and schemas were found, and uninstalling left no command and no package file behind.
The version is pinned because it is a pre-release. Without == an installer does not select a pre-release.
Once it is installed, the order is the one this page follows.
| Step | Command | Reaches a tenant |
|---|---|---|
| Register the application the command line signs in through | m365g engine setup | Only with --register, as an administrator |
| Sign in and keep the session | m365g login | Yes |
| See which connection later commands will use | m365g status | No |
| List or choose a kept connection | m365g connection list, m365g connection use NAME | No |
| End a session, or remove one by name | m365g logout, m365g connection remove NAME | Only to clear a kept sign-in |
m365g engine setup is m365g setup under its grouped name, and m365-governance setup under the earlier one. Minimum permissions says what each read then asks for.
Signing in
m365g login --client-id <application id> --tenant-url https://contoso-admin.sharepoint.comlogin first prints the report connect prints, with authentication and authorization as two separate answers: a session that opened is not a statement about what the identity may read. It then records the connection and prints it. The identifiers are replaced by placeholders here.
Logged in. Later commands for contoso.sharepoint.com use this connection.
contoso (active)
tenant contoso.sharepoint.com (https://contoso-admin.sharepoint.com)
directory <directory id>
application <application id>
signs in as delegated, by interactive; who: not reported by the session
session kept in the operating system's protected storage
recorded 2026-11-10T09:10:44Z
stored in the macOS KeychainThe line who: not reported by the session is the engine's own. The record holds the kind of identity and the method; no collection path for the person's name is established, so none is written.
Where the sign-in is kept
The token is written by the sign-in library into the operating system's protected storage, and never by the engine: the macOS Keychain, Windows data protection, or the Linux keyring. The engine holds no token, prints none and writes none into evidence.
Where protected storage cannot be established, the login is refused. On Linux the library falls back to an unprotected file when no keyring answers. login refuses to keep a session there, before anybody signs in, and checks what is on disk after the sign-in as well: a token cache it can read is cleared and the login fails.
What the engine records is a description, in connections.json under the user's configuration directory: the connection's name, the tenant address, the directory, the application registration, the sign-in method, the kind of identity the session reported, and when. It refuses to hold a secret. M365G_HOME moves the file.
What is on record
m365g statuscontoso (active)
tenant contoso.sharepoint.com (https://contoso-admin.sharepoint.com)
directory <directory id>
application <application id>
signs in as delegated, by interactive; who: not reported by the session
session kept in the operating system's protected storage
recorded 2026-11-10T09:10:44Z
This is the local record, not a check: `m365g connect` asks the tenant whether the session still signs in and what it may read.status reads the local record and reaches no tenant, so it says what was recorded at login and not whether the session still works. connect is the command that asks the tenant. With nothing recorded, status prints Logged out: no active connection. and exits 1.
connection list prints the same block for every stored connection. connection use NAME answers in one line:
contoso is the active connection, for contoso.sharepoint.com.There is one identity per tenant and application registration. A second login for the same pair replaces the first, and says which connection it replaced.
One sign-in, for SharePoint and for Microsoft Graph
The SharePoint collections sign in through PnP.PowerShell and reuse a kept session: every command in the spo group reports Signs in as the active connection (login), or with --client-id in its own help. After one login, m365g spo site list, m365g spo hub list and m365g spo sharing list run without asking again.
The Microsoft Graph reads sign in as the same person, through the same application registration, so the same kept session answers them too. Their help says Signs in as the active connection (login) for the scope above, or with a certificate, or with a token the operator supplies.
That covers m365g entra ca list, m365g entra tenant governance get, m365g entra guest list, m365g entra app list, m365g entra serviceprincipal list and m365g entra group list.
A certificate, or a token placed in the environment, still takes precedence over the kept session when either is given.
A session is used only for its own tenant. A command aimed at another tenant, by an option or a project file, ignores the active connection and says so. For the application registration and the tenant address the order is: an option on the command line, then a project file, then the active connection.
Each Graph read asks for its own scope, and no other
A Microsoft Graph read asks only for the scopes its collector declares. They are the ones recorded beside the collector, and the command reference prints them under Permissions. No wider set is asked for once and kept for convenience, so reading guests does not ask for what reading applications needs.
A scope nobody has consented to is asked for at the sign-in, and it is the person's to grant. The directory shows its own consent prompt there. The engine grants nothing and consents to nothing: no read has a step that accepts a prompt. Whether a given person may accept a given scope is the directory's rule, not the engine's.
Consent can be given for oneself alone. The directory's prompt lets an administrator consent for their own account without consenting on behalf of the organisation, and the engine asks for nothing more than that: no read on these pages needs a grant made for everybody.
The token a sign-in returns is spent at once. It is not written, kept by the engine or placed in an argument.
The reads that sign in for themselves
| Command | How it signs in |
|---|---|
m365g entra license list | for itself on every delegated run: a kept session is not reused |
m365g exo forwarding get | for itself on every delegated run: a kept session is not reused |
The licensing read signs in through the Microsoft Graph PowerShell SDK, whose kept context is shared with everything else an operator does with that SDK. The collector confines its sign-in to its own process, so it neither leaves that context behind nor uses one that was already there. The forwarding read signs in through Exchange Online PowerShell, which keeps no session between processes.
Logging out
m365g logoutcontoso: logged out, stored sign-in removed.A logout that cannot clear the stored sign-in keeps the record and exits 1, so that it is not mistaken for a logout. With nothing to remove it prints Already logged out: no active connection.
The one write the engine makes
m365g engine setup --register registers the application the command line signs in through. It is the only write the engine makes to a tenant. It needs an administrator, who signs in and consents in a browser, and it is made only by setup and only on explicit agreement. No other command on these pages changes anything in a tenant: login opens a session, and every read reads.
A person who is not an administrator runs setup without --register and receives the request an administrator acts on. The manual describes that journey under setup.