hostme.ie YOUR IT DEPARTMENT
Home› Blog› Microsoft 365
Microsoft 365

Entra app registration for PowerShell: when and how

Choose the right identity for your Microsoft 365 scripts, set it up deliberately and understand what changes when a report becomes a scheduled job.

Glasses reflecting code on a computer screen in a programming workspace

You have a useful PowerShell report. Now you want it to be easier to run, share with another administrator or schedule. An Entra app registration can help, but choosing the wrong sign-in method can give a small script much more access than it needs.

Start with the job: a report you run yourself usually needs interactive sign-in. A job that must run while nobody is signed in needs a workload identity. Creating an app registration and choosing unattended authentication are separate decisions.

Reviewed 23 September 2026. These examples target Microsoft Graph in the global Microsoft 365 cloud, using PowerShell 7 and the Microsoft.Graph.Authentication module. They are documentation- and syntax-checked examples, not a live-tenant deployment test.

Do you need your own app registration?

  • An occasional report, run by an administrator: start with the Microsoft Graph PowerShell sign-in already provided by the SDK. Your own registration is usually unnecessary; consent and tenant policy still apply.
  • A repeatable interactive tool for your team: a dedicated registration can give that tool a recognisable identity and separate consent record. Users still sign in. It is useful when the existing shared SDK identity is too broad for your governance needs.
  • A scheduled job on a supported Azure service: consider a managed identity first. Azure manages its credentials, but you still assign the required access. Enabling an identity does not grant Microsoft Graph permissions.
  • A scheduled job on another host: consider an application identity with a certificate, or workload identity federation where the host and authentication tooling support it. Treat the runner as part of the security boundary.

Microsoft documents both the SDK’s interactive and custom-app routes and managed identities on supported Azure resources.

Do not introduce unattended access just to avoid an MFA prompt. Do not build one all-purpose app with every permission for every script. If the task has no owner, no defined output or no maintenance plan, creating another persistent identity adds work before it removes any.

What are you actually creating?

The app registration holds the application’s definition and configuration. The related enterprise application, or service principal, represents it in a tenant and is where you inspect its local access and activity. These are related objects, not interchangeable names for the same settings screen. A managed identity is a special kind of service principal and does not need you to create a normal app registration.

The application/client ID identifies the app; the directory/tenant ID identifies the organisation. Neither is a password. A client secret, private key or access token is sensitive. See Microsoft’s application and service-principal explanation.

Delegated access means the app acts for a signed-in user; both the app’s permission and the user’s authority matter. Application access means the app acts without that user. A similarly named application permission can therefore reach far more data than its delegated counterpart. Microsoft’s permissions and consent overview explains the distinction.

1. Register a small, clearly named application

Use a test tenant first and an account authorised to register applications under your organisation’s policy. Registration rights do not automatically include permission to approve tenant-wide access.

  1. Open the Microsoft Entra admin centre. Check the selected tenant before making changes.
  2. Go to Entra ID → App registrations → New registration.
  3. Use a purpose-specific name, such as IT Reporting — Interactive — Test.
  4. For a tool used only inside this organisation, choose Accounts in this organisational directory only. Do not choose multitenant simply to make setup easier.
  5. Leave the redirect URI blank at this stage and select Register. Configure the appropriate platform in the next section.
  6. Record the Application (client) ID and Directory (tenant) ID from Overview. Record the purpose and responsible owner in your own admin inventory.

These are the core Microsoft registration steps. Keep ownership to the people who need to manage this app and review it when responsibilities change.

2. Configure interactive PowerShell first

For the custom Graph PowerShell interactive route, open Authentication and add a Mobile and desktop applications platform with http://localhost. Microsoft’s current instructions also require the broker redirect URI ms-appx-web://Microsoft.AAD.BrokerPlugin/YOUR-CLIENT-ID; replace the final part with this registration’s client ID. Save the configuration. This public-client route does not need a client secret.

Under API permissions → Add a permission → Microsoft Graph → Delegated permissions, use User.Read for the small profile test below. Review any existing permissions. This example does not need directory-wide reads or write permissions.

To limit who may use the custom interactive app, follow the custom-app instructions: find it under Enterprise applications, set Assignment required? to Yes and assign the intended users. Confirm the resulting sign-in behaviour in your tenant.

Install the module from your approved package source if needed. In a fresh PowerShell 7 session, replace the two placeholders below with your IDs. The example refuses an existing Graph connection and checks the new connection before making one read request.

Import-Module Microsoft.Graph.Authentication -ErrorAction Stop
$tenantId = 'YOUR-TENANT-GUID'
$clientId = 'YOUR-CLIENT-GUID'
if (Get-MgContext) { throw 'Use a fresh PowerShell session.' }

try {
    $connection = @{
        TenantId = $tenantId
        ClientId = $clientId
        Scopes = 'User.Read'
        ContextScope = 'Process'
        Environment = 'Global'
        ErrorAction = 'Stop'
    }
    Connect-MgGraph @connection
    $context = Get-MgContext
    if ($context.TenantId -ne $tenantId -or
        $context.ClientId -ne $clientId -or
        $context.AuthType -ne 'Delegated') {
        throw 'Unexpected tenant, application or sign-in type.'
    }
    Invoke-MgGraphRequest -Method GET -ErrorAction Stop -Uri `
        'https://graph.microsoft.com/v1.0/me?$select=id,displayName'
}
finally {
    if (Get-MgContext) { Disconnect-MgGraph | Out-Null }
}

The Connect-MgGraph parameters select the app, tenant and connection method. The /me request reads the signed-in user’s selected profile fields. Signing in successfully does not prove that a later report has all its required permissions. Disconnecting ends this connection; it does not undo consent.

3. Use a separate identity for an unattended job

A nightly task has different operational needs from a person running a report. We recommend a separate app for a separate unattended workload, with its own owner, permissions and retirement date. Do not quietly turn the interactive example above into a general-purpose automation account.

On a supported Azure host, a configured managed identity can connect using Connect-MgGraph -Identity. That command does not provision the identity or assign its Graph roles. Off Azure, federation may avoid a stored credential when your runner supports it. Otherwise, a certificate is preferable to embedding a shared secret in a script. See Microsoft’s client-credentials guidance.

  1. Create a separate single-tenant registration for the scheduled job. Certificate-based app-only authentication does not need the interactive redirect URIs.
  2. Find each Graph endpoint the job calls and check its Application permissions. Do not copy the delegated permission list and assume it is equivalent.
  3. Under API permissions, add only the application permissions justified by those endpoints. Remove unused defaults and have an authorised administrator review and grant consent.
  4. Provision an appropriate certificate for the runner. Upload only its public certificate under Certificates & secrets → Certificates. Keep the private key on the protected runner or in its approved key service; never upload a private-key PFX to the registration or commit it to source.
  5. Verify that the exact account running the scheduled task can use the private key. Test under that account, not only under your own desktop login. Record expiry and replacement ownership.

Microsoft’s Graph PowerShell app-only setup covers certificates and checking the resulting identity.

For a deliberately limited connection test, the following reads at most five users’ IDs and display names. The documented least-privileged application permission for the list-users endpoint is User.Read.All. That permission can read profiles across the tenant: $top and $select limit this request’s output, not the app’s authority. Do not grant it unless your approved job needs it.

This Windows runner example assumes the certificate and private key are already in the run account’s Cert:\CurrentUser\My store. Replace all three placeholders. It is a connection test, not a complete user export.

Import-Module Microsoft.Graph.Authentication -ErrorAction Stop
$tenantId = 'YOUR-TENANT-GUID'
$clientId = 'YOUR-APP-ONLY-CLIENT-GUID'
$thumbprint = 'YOUR-CERTIFICATE-THUMBPRINT'
if (Get-MgContext) { throw 'Use a fresh PowerShell session.' }

try {
    $connection = @{
        TenantId = $tenantId
        ClientId = $clientId
        CertificateThumbprint = $thumbprint
        ContextScope = 'Process'
        Environment = 'Global'
        ErrorAction = 'Stop'
    }
    Connect-MgGraph @connection
    $context = Get-MgContext
    if ($context.TenantId -ne $tenantId -or
        $context.ClientId -ne $clientId -or
        $context.AuthType -ne 'AppOnly') {
        throw 'Unexpected tenant, application or sign-in type.'
    }
    Invoke-MgGraphRequest -Method GET -ErrorAction Stop -Uri `
        'https://graph.microsoft.com/v1.0/users?$top=5&$select=id,displayName'
}
finally {
    if (Get-MgContext) { Disconnect-MgGraph | Out-Null }
}

4. Treat permission approval as a separate decision

Configured is not the same as granted. Check the permission type and consent status. Microsoft Graph application permissions require an appropriately authorised administrator; Application Administrator and Cloud Application Administrator cannot grant Microsoft Graph app roles. Privileged Role Administrator can, as can an appropriately authorised custom role. Use your organisation’s approval process. Microsoft’s admin-consent documentation sets out the roles.

A custom registration separates a tool’s identity and consent history, but its configured delegated permission list is not by itself an unchangeable ceiling. Additional scopes may be requested and granted under tenant consent policy. Review actual grants as well as the script. An app capable of changing the directory is still powerful even if today’s code happens to issue only GET requests.

Apply Microsoft’s least-privilege and ownership guidance: choose the narrowest access that supports the task, remove what is no longer needed, and keep owners accountable. Avoid write permissions for a reporting-only job.

5. Troubleshoot without widening access blindly

  • Wrong tenant or app: compare Get-MgContext with the registration’s Overview. Start a fresh session; do not reuse an unrelated connection.
  • Redirect or broker error: compare Authentication settings with the current custom Graph PowerShell instructions, including the client ID in the broker URI. Do not disable security controls to hide a configuration error.
  • Consent or 403 error: check delegated versus application permission, actual consent, the endpoint’s requirements and, for delegated access, the user’s role. Check the app’s sign-in restrictions too.
  • Certificate works manually but the task fails: check the task account, certificate store, private-key access and expiry. A thumbprint alone is not a credential.
  • A script using /me fails app-only: there is no signed-in user. Choose the appropriate explicit resource endpoint and review its application permissions.

Before enabling a schedule, agree where reports go, who can read them, what happens on a failed run and who receives an alert. Log completion and errors without tokens or secrets. Test a permission failure as well as success; a blank file must not be mistaken for a clean report.

Keep a short handover record: purpose, owner, tenant and app IDs, approved permissions, runner, certificate expiry, review date and retirement steps. When retiring it, stop the job, revoke the relevant access and credentials, check dependencies and verify it can no longer connect. Removing a permission from the configured request list alone is not proof that an existing grant has been revoked.

How this applies to the hostme.ie toolkit

Our free Microsoft 365 admin toolkit v0.2.0 preview uses interactive delegated Graph sign-in. It opens its own connection, checks the tenant and requested read scopes, and refuses an existing connection. It does not accept a custom client ID, certificate or managed identity. You do not need to create a new app registration to use this version, subject to your tenant’s consent policies.

Do not pre-connect with the examples above and then run those scripts, or remove their authentication checks to force unattended use. Adapting a report for app-only access needs a deliberate code and permission review, followed by tests. The toolkit’s 46 offline checks are not live-tenant validation.

The library includes licence, guest, group membership, group owner and app credential-expiry reports. The credential-expiry report can help build a review list; it does not rotate credentials or guarantee a complete identity inventory.

When adapting or sharing a script, include its exact authentication mode, permissions and limitations alongside the setup instructions. Microsoft Graph access also does not automatically authorise every Exchange Online or SharePoint PowerShell command; each module’s supported authentication and authorisation must be checked separately.

Need help turning a manual report into an owned, maintainable IT process? Talk to hostme.ie about Microsoft 365 support.

Cover photograph: Kevin Ku / Pexels, used under the Pexels Licence. Illustrative programming workspace, not an Entra portal screenshot.

Got a question about this?
Message me and I'll talk it through — no charge, no jargon.
Message me