Skip to main content

Scenario: AVD — Privileged Admin Workstation

The Problem This Solves

Several Microsoft PowerShell admin modules do not support FIDO2 passkey or Windows Hello for Business authentication. Microsoft's own documentation confirms this:

"Some PowerShell modules that use Internet Explorer instead of Edge aren't capable of performing FIDO2 authentication. For example, PowerShell modules for SharePoint Online or Teams, or any PowerShell scripts that require admin credentials, don't prompt for FIDO2."

For organizations enforcing phishing-resistant MFA as a Conditional Access requirement — which CMMC Level 2 effectively mandates — this creates a gap: admins who need to run Teams PowerShell, SharePoint Online PowerShell, or other legacy modules cannot authenticate with their phishing-resistant credentials. The common workaround is to exempt these admin accounts from the phishing-resistant MFA requirement, which defeats the purpose.

The solution: Run admin PowerShell sessions inside an AVD session host that is secured with phishing-resistant authentication. The admin authenticates to the AVD broker with FIDO2 or WHfB. Inside the session, PowerShell modules authenticate using a managed identity assigned to the session host VM — no passwords, no certificates, no FIDO2 prompts, zero credentials stored or typed.


Architecture

LayerWhat it does
User → AVD brokerAdmin authenticates with phishing-resistant MFA (FIDO2 / WHfB). Conditional Access enforces this.
AVD session hostHas a system-assigned managed identity with the necessary admin Graph API permissions
PowerShell module → Graph APIModule authenticates via managed identity — Connect-MicrosoftTeams -Identity, Connect-MgGraph -Identity, etc.

The phishing-resistant authentication happens at the session boundary. The managed identity provides zero-credential access to the API. The admin never types a password or handles a certificate.


Which PowerShell Modules Support Managed Identity

ModuleManaged identity supportConnection command
Microsoft TeamsYesConnect-MicrosoftTeams -Identity
Microsoft GraphYesConnect-MgGraph -Identity
Exchange OnlineYesConnect-ExchangeOnline -ManagedIdentity -Organization contoso.onmicrosoft.us
SharePoint Online (PnP)YesConnect-PnPOnline -Url https://contoso.sharepoint.us -ManagedIdentity
SharePoint Online Management ShellNo — use PnP or Graph insteadN/A
Azure Az moduleYesConnect-AzAccount -Identity
Security & ComplianceNo native managed identity — use Connect-IPPSSession with certificate-based auth as fallbackCertificate on session host
Modules without managed identity support

For modules that do not support managed identity authentication, use certificate-based authentication as the fallback. Install a certificate on the session host and configure the app registration to accept certificate credentials. This is still zero-password — the certificate is bound to the machine, not typed by the user.


Prerequisites

Session Host VM

Use a personal host pool with one VM per admin. Each VM has its own system-assigned managed identity with permissions scoped to that admin's role.

RequirementConfiguration
VM typePersonal pool — each admin gets a dedicated session host
OSWindows 11 Enterprise (single-session)
Managed identitySystem-assigned — enabled on each session host VM
PowerShell modulesPre-installed on the session host image (Teams, Graph, Exchange Online, PnP, Az)
NetworkSession hosts can reach Microsoft Graph and M365 service endpoints

App Registration and Permissions

The managed identity authenticates as the VM's service principal. You must grant the necessary Graph API application permissions to each session host's managed identity.

Example: Teams admin session host

# Connect to Graph with admin credentials (one-time setup)
Connect-MgGraph -Environment USGov -Scopes "AppRoleAssignment.ReadWrite.All"

# Get the managed identity's service principal
$miObjectId = (Get-MgServicePrincipal -Filter "displayName eq 'avd-admin-teams-01'").Id

# Get the Microsoft Graph service principal
$graphSP = Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'"

# Find the Teams admin app role (example: Organization.ReadWrite.All)
$appRole = $graphSP.AppRoles | Where-Object { $_.Value -eq "Organization.ReadWrite.All" }

# Grant the permission to the managed identity
New-MgServicePrincipalAppRoleAssignment `
-ServicePrincipalId $miObjectId `
-PrincipalId $miObjectId `
-ResourceId $graphSP.Id `
-AppRoleId $appRole.Id

Repeat for each Graph permission the admin role requires. Follow least privilege — grant only the specific app roles needed for the admin's function, not broad directory-wide permissions.

Managed identity permissions are application permissions, not delegated

Managed identities authenticate as the application, not as a user. This means:

  • There is no user context — actions are performed as the service principal, not as "admin@contoso.us"
  • Audit logs show the managed identity's service principal name, not the admin's UPN
  • Permissions granted are application permissions, which are typically broader than delegated permissions

Mitigate by:

  • Using one session host per admin role (Teams admin, Exchange admin) with only the permissions that role needs
  • Logging which user was signed into the AVD session when the managed identity was used (AVD sign-in logs correlate the user to the session host)
  • Reviewing managed identity permission grants in recurring access reviews

Conditional Access

Create a CA policy requiring phishing-resistant MFA for admin access to the AVD broker:

Users:

  • Include: Admin security group (e.g., AVD-Admin-Workstation-Users)

Target resources: Azure Virtual Desktop, Azure Virtual Desktop Client, Windows Cloud Login

Grant: Require authentication strength: Phishing-resistant MFA

This ensures the admin authenticates with FIDO2 or WHfB before reaching the session host. Once inside the session, the managed identity handles API authentication — no second authentication prompt.


Usage

Once configured, the admin workflow is:

  1. Open AVD client and connect to the admin session host
  2. Authenticate with FIDO2 key (or WHfB) at the Entra login prompt
  3. Open PowerShell inside the AVD session
  4. Connect using managed identity:
# Teams administration
Connect-MicrosoftTeams -Identity

# Graph API operations
Connect-MgGraph -Identity

# Exchange Online administration
Connect-ExchangeOnline -ManagedIdentity -Organization contoso.onmicrosoft.us

# SharePoint administration (via PnP)
Connect-PnPOnline -Url https://contoso.sharepoint.us -ManagedIdentity

No passwords typed. No certificates managed. No FIDO2 compatibility issues. The phishing-resistant authentication happened at the AVD broker; the managed identity provides the API access.


Beyond PowerShell: Managed Identities as Zero-Credential Infrastructure

Managed identities are not limited to PowerShell admin sessions. They can replace stored credentials anywhere an Azure-hosted workload needs to access Microsoft APIs:

Use caseWhat managed identity replaces
PowerShell admin modules (this scenario)Passwords, certificates, FIDO2 workarounds
Azure Automation runbooksStored credentials or Run As accounts (deprecated)
Azure Functions calling Graph APIClient secrets in app settings
Logic Apps connecting to M365OAuth connection credentials
Key Vault access from VMsAccess policies based on service principal secrets
Azure DevOps / GitHub ActionsWorkload identity federation replaces long-lived client secrets

The principle is the same: the Azure resource has an identity issued by Entra, and that identity authenticates to APIs without any stored or transmitted credential. This eliminates an entire category of secret management — no Key Vault entries to rotate, no certificates to renew, no passwords to store.

Managed identities can obviate Key Vault for many scenarios

Key Vault is often deployed to store secrets that managed identities make unnecessary. If the workload consuming the secret runs on Azure (VMs, App Service, Functions, AKS), evaluate whether a managed identity can authenticate directly to the target API instead of retrieving a secret from Key Vault. This removes a dependency, reduces latency, and eliminates the secret lifecycle entirely.

📩 Don't Miss the Next Solution

Join the list to see the real-time solutions I'm delivering to my GCC High clients.