Post

Streamlining Azure CLI & PowerShell Authentication on Windows 11

Set up a secure and convenient Azure authentication workflow on a Windows 11 machine using Windows Credential Manager and PowerShell profiles.

Streamlining Azure CLI & PowerShell Authentication on Windows 11

I recently cleaned up my Windows 11 work machines and did a fresh install, OneDrive and winget made installing tools and pulling down configurations easy, I wanted to clean up how I authenticate with Azure when using the Az CLI and Azure PowerShell. I wanted something that was both secure and convenient for daily use and switching between accounts.

After some experimentation, I landed on a solution that uses Windows Credential Manager with PowerShell profiles to enable seamless authentication for both Az CLI and Azure PowerShell.

The Problem

When working with Azure daily, you need:

  • Quick, seamless authentication
  • Support for both Az CLI and Azure PowerShell
  • Ability to manage multiple service principals
  • Security (no plain text secrets lying around)

The Solution: Windows Credential Manager + PowerShell Profile

Instead doing an interactive sign-in or storing secrets in environment variables, I’m using Windows Credential Manager to encrypt and store service principal credentials, then loading them automatically through my PowerShell profile.

Prerequisites: Creating a Service Principal

Before we set up authentication, you’ll need a service principal. Here’s how to create one with contributor permissions:

Using Azure Portal

  1. Navigate to Azure Active Directory > App registrations > New registration
  2. Give it a name (e.g., “My-DevOps-SP”) and click Register
  3. Note the Application (client) ID and Directory (tenant) ID
  4. Go to Certificates & secrets > New client secret
  5. Add a description and expiration period, then click Add
  6. Copy the secret value immediately (you won’t see it again!)

Using Az CLI

1
2
3
4
5
6
7
8
9
10
# Create service principal with Contributor role at subscription level
az ad sp create-for-rbac --name "My-DevOps-SP" --role Contributor --scopes /subscriptions/YOUR_SUBSCRIPTION_ID

# Output will show:
# {
#   "appId": "your-client-id",
#   "displayName": "My-DevOps-SP",
#   "password": "your-client-secret",
#   "tenant": "your-tenant-id"
# }

Assigning Permissions

For basic Azure operations, assign the service principal to your subscription:

1
2
3
4
5
# Contributor role (can create/manage resources)
az role assignment create --assignee YOUR_CLIENT_ID --role Contributor --scope /subscriptions/YOUR_SUBSCRIPTION_ID

# Or Reader role (read-only access)
az role assignment create --assignee YOUR_CLIENT_ID --role Reader --scope /subscriptions/YOUR_SUBSCRIPTION_ID

You can also assign roles through the Azure Portal:

  1. Go to your Subscription > Access control (IAM) > Add role assignment
  2. Select a role (e.g., Contributor or Reader)
  3. Search for your service principal name and assign it

Now you have the three values needed: Tenant ID, Client ID, and Client Secret.

Step 1: Store Your Service Principal Credentials

First, let’s create a helper function to securely store service principal profiles. Add this to your PowerShell session by copying and pasting it in:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function Add-AzureServicePrincipalProfile {
    param(
        [Parameter(Mandatory)]
        [string]$ProfileName,
        
        [Parameter(Mandatory)]
        [string]$TenantId,
        
        [Parameter(Mandatory)]
        [string]$ClientId,
        
        [Parameter(Mandatory)]
        [string]$ClientSecret
    )
    
    $azureDir = "$env:USERPROFILE\.azure"
    if (-not (Test-Path $azureDir)) {
        New-Item -ItemType Directory -Path $azureDir | Out-Null
    }
    
    $secureSecret = ConvertTo-SecureString $ClientSecret -AsPlainText -Force
    $credential = New-Object System.Management.Automation.PSCredential($ClientId, $secureSecret)
    
    $credPath = "$azureDir\sp-$ProfileName-credential.xml"
    $tenantPath = "$azureDir\sp-$ProfileName-tenant.txt"
    
    $credential | Export-Clixml -Path $credPath
    Set-Content -Path $tenantPath -Value $TenantId
    
    Write-Host "✓ Profile '$ProfileName' saved successfully" -ForegroundColor Green
}

Now store your service principal(s):

1
2
3
4
5
6
7
8
9
10
11
12
13
# Store your default service principal
Add-AzureServicePrincipalProfile `
    -ProfileName "default" `
    -TenantId "your-tenant-id" `
    -ClientId "your-client-id" `
    -ClientSecret "your-client-secret"

# Optional: Store additional profiles for different environments
Add-AzureServicePrincipalProfile `
    -ProfileName "production" `
    -TenantId "prod-tenant-id" `
    -ClientId "prod-client-id" `
    -ClientSecret "prod-client-secret"

The credentials are now stored encrypted in ~/.azure/ and can only be accessed by your Windows user account.

Step 2: Configure Your PowerShell Profile

Edit your PowerShell profile, make sure to update the -ProfileName parameter if you used a different name than “default”:

1
notepad $PROFILE

Add the following code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# ============================================
# Azure Authentication Management
# ============================================

function Connect-AzureServicePrincipal {
    param(
        [string]$ProfileName = "default"
    )
    
    $credPath = "$env:USERPROFILE\.azure\sp-$ProfileName-credential.xml"
    $tenantPath = "$env:USERPROFILE\.azure\sp-$ProfileName-tenant.txt"
    
if ((Test-Path $credPath) -and (Test-Path $tenantPath)) {
        $credential = Import-Clixml -Path $credPath
        $tenantId = Get-Content -Path $tenantPath
        
        # For Azure PowerShell
        Connect-AzAccount -ServicePrincipal -Credential $credential -Tenant $tenantId -WarningAction SilentlyContinue | Out-Null
        
        # For Az CLI
        $clientSecret = $credential.GetNetworkCredential().Password
        az login --service-principal -u $credential.UserName -p $clientSecret --tenant $tenantId --output none
        
        Write-Host "✓ Connected to Azure as Service Principal ($ProfileName)" -ForegroundColor Green
    } else {
        Write-Host "✗ Profile '$ProfileName' not found" -ForegroundColor Red
    }
}

function Connect-AzureInteractive {
    # Sign in with your personal account interactively
    Connect-AzAccount -WarningAction SilentlyContinue
    az login
    Write-Host "✓ Connected to Azure interactively" -ForegroundColor Green
}

function Show-AzureAccounts {
    Write-Host "`n=== Azure PowerShell Context ===" -ForegroundColor Cyan
    Get-AzContext | Format-List Name, Account, Subscription, Tenant
    
    Write-Host "`n=== Az CLI Account ===" -ForegroundColor Cyan
    az account show -o table
}

function Disconnect-Azure {
    Disconnect-AzAccount -WarningAction SilentlyContinue | Out-Null
    az logout 2>$null
    Write-Host "✓ Disconnected from Azure" -ForegroundColor Yellow
}

# Convenient aliases
Set-Alias -Name azsp -Value Connect-AzureServicePrincipal
Set-Alias -Name azint -Value Connect-AzureInteractive
Set-Alias -Name azshow -Value Show-AzureAccounts
Set-Alias -Name azlogout -Value Disconnect-Azure

# Auto-connect with default profile on startup (optional)
Connect-AzureServicePrincipal -ProfileName "default"

Save and close the file, then reload your profile:

1
. $PROFILE

How to Use It

Automatic Sign-In

If you leave the last line uncommented, when you launch PowerShell, you’re automatically authenticated to Azure with your default service principal. Both Az CLI and Azure PowerShell are ready to go.

Manual Sign-In with Different Profiles

1
2
3
4
5
# Use default profile
azsp

# Use specific profile
azsp -ProfileName "production"

Switch to Interactive Login

Need to use your personal account instead?

1
2
3
4
5
# Sign out from service principal
azlogout

# Sign in interactively
azint

Check Current Account

1
azshow

Switch Subscriptions

1
2
3
4
5
# Azure PowerShell
Set-AzContext -Subscription "subscription-name"

# Az CLI
az account set --subscription "subscription-name"

Why This Approach?

Security: Credentials are encrypted by Windows and only accessible to your user account. No plain text secrets in files or environment variables.

Convenience: Automatic authentication on PowerShell startup means you’re always ready to work.

Flexibility: Easy switching between multiple service principals or interactive login.

One Solution: Works seamlessly with both Az CLI and Azure PowerShell Module.

Quick Command Reference

CommandDescription
azspConnect with default service principal
azsp -ProfileName "prod"Connect with specific profile
azintInteractive login (personal account)
azshowShow current account info
azlogoutSign out completely

Wrapping Up

Setting up a new machine is always an opportunity to improve your workflows. This authentication setup has made my daily Azure work much smoother.

If you’re setting up Azure authentication on Windows, give this approach a try. Your future self (and your security team) will thank you.


Have questions or suggestions? Feel free to reach out or leave a comment below!

This post is licensed under CC BY 4.0 by the author.