Skip to content

Lab 06: SSPR - CLI/PowerShell Solution

Note: SSPR configuration is limited in CLI. Most settings require the portal or Microsoft Graph API.


Prerequisites

powershell
# Install Microsoft Graph PowerShell SDK
Install-Module Microsoft.Graph -Scope CurrentUser -Force

# Connect with required scopes
Connect-MgGraph -Scopes @(
    "Policy.ReadWrite.Authorization",
    "Directory.ReadWrite.All",
    "User.ReadWrite.All",
    "Group.ReadWrite.All"
)

Task 1: Create Pilot Group

PowerShell (Microsoft Graph)

powershell
# Create the SSPR pilot security group
$group = New-MgGroup -DisplayName "SSPR-Pilot-Users" `
    -Description "Users enabled for Self-Service Password Reset pilot" `
    -MailEnabled:$false `
    -MailNickname "sspr-pilot" `
    -SecurityEnabled:$true

# Get the group ID
$groupId = $group.Id
Write-Host "Created group with ID: $groupId"

# Add test users to the group
$testUsers = @("user1@yourdomain.com", "user2@yourdomain.com")

foreach ($userEmail in $testUsers) {
    $user = Get-MgUser -Filter "userPrincipalName eq '$userEmail'"
    if ($user) {
        New-MgGroupMember -GroupId $groupId -DirectoryObjectId $user.Id
        Write-Host "Added $userEmail to SSPR pilot group"
    }
}

# Verify group members
Get-MgGroupMember -GroupId $groupId | ForEach-Object {
    Get-MgUser -UserId $_.Id | Select-Object DisplayName, UserPrincipalName
}

Azure CLI

bash
# Create the security group
az ad group create \
    --display-name "SSPR-Pilot-Users" \
    --mail-nickname "sspr-pilot" \
    --description "Users enabled for Self-Service Password Reset pilot"

# Get group ID
GROUP_ID=$(az ad group show --group "SSPR-Pilot-Users" --query id -o tsv)

# Add users to group
az ad group member add --group "SSPR-Pilot-Users" --member-id "<user-object-id>"

# List group members
az ad group member list --group "SSPR-Pilot-Users" --query "[].{Name:displayName,UPN:userPrincipalName}" -o table

Task 2-4: SSPR Configuration

⚠️ SSPR policy configuration is NOT available via CLI or basic Graph commands.

You must use the Microsoft Entra admin center or the Microsoft Graph API with specific endpoints.

Using Microsoft Graph API (Advanced)

powershell
# Get current SSPR configuration (read-only via Graph)
# Note: SSPR settings are under authenticationMethodsPolicy

$uri = "https://graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy"
Invoke-MgGraphRequest -Uri $uri -Method GET

# Authentication methods configuration endpoint
$uri = "https://graph.microsoft.com/v1.0/policies/authenticationMethodsPolicy/authenticationMethodConfigurations"
Invoke-MgGraphRequest -Uri $uri -Method GET

View SSPR Activity via PowerShell

powershell
# Get SSPR audit logs
Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'Reset password (self-service)'" `
    -Top 50 | 
    Select-Object ActivityDateTime, 
                  @{N='User';E={$_.InitiatedBy.User.UserPrincipalName}},
                  Result,
                  ResultReason

# Get SSPR registration audit logs  
Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq 'User registered for self-service password reset'" `
    -Top 50 |
    Select-Object ActivityDateTime,
                  @{N='User';E={$_.InitiatedBy.User.UserPrincipalName}},
                  Result

Task 5: Password Writeback (Entra Connect)

Password writeback is configured in Entra Connect on your on-premises sync server, not via cloud CLI.

powershell
# On your Entra Connect server, you can verify writeback status:
# Open PowerShell as Administrator

Import-Module ADSync

# Check current configuration
Get-ADSyncConnector | Where-Object {$_.Type -eq "Extensible2"} | 
    Get-ADSyncConnectorPartition | 
    Format-List

# View password writeback status in connector
Get-ADSyncAutoUpgradeStatus
Get-ADSyncScheduler

Task 6: Test SSPR (User Simulation)

SSPR testing must be done interactively via browser. However, you can verify user registration status:

powershell
# Check if a user is registered for SSPR
$userId = "user@yourdomain.com"

# Get user's authentication methods
$methods = Get-MgUserAuthenticationMethod -UserId $userId

Write-Host "Authentication methods for $userId :"
$methods | ForEach-Object {
    $_.AdditionalProperties
}

# More detailed method info
Get-MgUserAuthenticationPhoneMethod -UserId $userId
Get-MgUserAuthenticationEmailMethod -UserId $userId
Get-MgUserAuthenticationMicrosoftAuthenticatorMethod -UserId $userId

List Users Not Registered for SSPR

powershell
# Get all users and check registration status
$users = Get-MgUser -All -Property "Id,DisplayName,UserPrincipalName"

$unregistered = @()

foreach ($user in $users) {
    $methods = Get-MgUserAuthenticationMethod -UserId $user.Id -ErrorAction SilentlyContinue
    
    # If only password method exists, user hasn't registered additional methods
    if ($methods.Count -le 1) {
        $unregistered += [PSCustomObject]@{
            DisplayName = $user.DisplayName
            UPN = $user.UserPrincipalName
            MethodCount = $methods.Count
        }
    }
}

$unregistered | Format-Table -AutoSize
Write-Host "Users not registered for SSPR: $($unregistered.Count)"

Task 7: Review SSPR Activity

PowerShell - Audit Logs

powershell
# SSPR-related audit events
$startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")

# Password reset events
Get-MgAuditLogDirectoryAudit `
    -Filter "category eq 'UserManagement' and activityDateTime ge $startDate" `
    -Top 100 |
    Where-Object { $_.ActivityDisplayName -like "*password*" } |
    Select-Object ActivityDateTime, 
                  ActivityDisplayName,
                  @{N='User';E={$_.TargetResources[0].UserPrincipalName}},
                  Result |
    Format-Table -AutoSize

# SSPR specific events
$ssprvents = @(
    "Reset password (self-service)",
    "User registered for self-service password reset",
    "Self-service password reset flow activity progress"
)

foreach ($event in $ssprvents) {
    Write-Host "`n=== $event ===" -ForegroundColor Cyan
    Get-MgAuditLogDirectoryAudit -Filter "activityDisplayName eq '$event'" -Top 10 |
        Select-Object ActivityDateTime, Result, ResultReason |
        Format-Table
}

Azure CLI - Audit Logs

bash
# Get SSPR audit logs (last 30 days)
az rest --method GET \
    --url "https://graph.microsoft.com/v1.0/auditLogs/directoryAudits?\$filter=activityDisplayName eq 'Reset password (self-service)'" \
    --query "value[].{Time:activityDateTime,User:targetResources[0].userPrincipalName,Result:result}" \
    -o table

Challenge 1: Conditional Access for Registration

powershell
# Create named location for corporate network first
$params = @{
    "@odata.type" = "#microsoft.graph.ipNamedLocation"
    displayName = "Corporate Network"
    isTrusted = $true
    ipRanges = @(
        @{
            "@odata.type" = "#microsoft.graph.iPv4CidrRange"
            cidrAddress = "203.0.113.0/24"  # Replace with your IP range
        }
    )
}
$corpLocation = New-MgIdentityConditionalAccessNamedLocation -BodyParameter $params

# Create CA policy for secure registration
$caPolicy = @{
    displayName = "Secure SSPR Registration"
    state = "enabledForReportingButNotEnforced"  # Report-only mode first
    conditions = @{
        users = @{
            includeUsers = @("All")
            excludeUsers = @("<emergency-access-account-id>")
        }
        userActions = @{
            includeUserActions = @("urn:user:registersecurityinfo")
        }
        locations = @{
            includeLocations = @("All")
            excludeLocations = @($corpLocation.Id)
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("compliantDevice", "domainJoinedDevice")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $caPolicy

Challenge 2: Banned Passwords

powershell
# Configure custom banned passwords
# Note: This requires specific Graph API calls

$uri = "https://graph.microsoft.com/v1.0/groupSettings"

# Get directory settings template for banned passwords
$templateUri = "https://graph.microsoft.com/v1.0/directorySettingTemplates"
$templates = Invoke-MgGraphRequest -Uri $templateUri -Method GET

# Password Rule Settings template ID
$passwordTemplateId = ($templates.value | Where-Object {$_.displayName -eq "Password Rule Settings"}).id

# Note: Full implementation requires portal as the banned password
# list is managed through the Authentication Methods blade
Write-Host "Custom banned passwords must be configured via Entra admin center"
Write-Host "Path: Protection > Authentication methods > Password protection"

Summary: What's Available via CLI

TaskCLI AvailableNotes
Create pilot groupFull support
Add users to groupFull support
Enable SSPR for groupPortal only
Configure auth methodsPortal only
Configure registrationPortal only
Configure notificationsPortal only
Password writebackEntra Connect UI
View audit logsFull support
Check user registrationGraph API
Create CA policiesFull support
Banned passwords⚠️Read only via API

Recommendation: Use the portal for SSPR configuration. Use CLI/PowerShell for:

  • Group management
  • Audit log queries
  • User registration status checks
  • Automation of user provisioning

Released under the MIT License.