Skip to content

Lab 03: Conditional Access - CLI Solutions

Note: Conditional Access policies are primarily managed through the portal. CLI/PowerShell is useful for automation and bulk operations.


Prerequisites

powershell
# Install Microsoft Graph module
Install-Module Microsoft.Graph -Scope CurrentUser

# Connect with appropriate scopes
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess", "Policy.Read.All", "Directory.Read.All"

Task 1-2: Named Locations

Create IP-based Named Location

powershell
# Create a trusted IP location
$params = @{
    "@odata.type" = "#microsoft.graph.ipNamedLocation"
    displayName = "Corporate Office IPs"
    isTrusted = $true
    ipRanges = @(
        @{
            "@odata.type" = "#microsoft.graph.iPv4CidrRange"
            cidrAddress = "203.0.113.0/24"
        }
        @{
            "@odata.type" = "#microsoft.graph.iPv4CidrRange"
            cidrAddress = "198.51.100.0/24"
        }
    )
}

New-MgIdentityConditionalAccessNamedLocation -BodyParameter $params

Create Country-based Named Location

powershell
# Create blocked countries location
$params = @{
    "@odata.type" = "#microsoft.graph.countryNamedLocation"
    displayName = "Blocked Countries"
    countriesAndRegions = @("RU", "CN", "KP", "IR")
    includeUnknownCountriesAndRegions = $false
}

New-MgIdentityConditionalAccessNamedLocation -BodyParameter $params

List Named Locations

powershell
# List all named locations
Get-MgIdentityConditionalAccessNamedLocation | 
    Select-Object DisplayName, Id, "@odata.type"

Task 3-6: Conditional Access Policies

Create Basic CA Policy (MFA for All)

powershell
# Policy: Require MFA for all users, all apps
$params = @{
    displayName = "CA-Require-MFA-All-Users"
    state = "enabledForReportingButNotEnforced"  # Report-only mode
    conditions = @{
        users = @{
            includeUsers = @("All")
            excludeUsers = @("admin-account-object-id")  # Emergency access
        }
        applications = @{
            includeApplications = @("All")
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("mfa")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Create Location-based Policy

powershell
# Get the blocked countries location ID
$blockedLocation = Get-MgIdentityConditionalAccessNamedLocation | 
    Where-Object { $_.DisplayName -eq "Blocked Countries" }

# Policy: Block sign-ins from blocked countries
$params = @{
    displayName = "CA-Block-High-Risk-Countries"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeUsers = @("All")
        }
        applications = @{
            includeApplications = @("All")
        }
        locations = @{
            includeLocations = @($blockedLocation.Id)
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("block")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Create Policy Targeting Specific Group

powershell
# Get group ID
$group = Get-MgGroup -Filter "displayName eq 'CA-Test-Group'"

# Policy for specific group
$params = @{
    displayName = "CA-MFA-For-Test-Group"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeGroups = @($group.Id)
        }
        applications = @{
            includeApplications = @("All")
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("mfa")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Create Guest User Policy

powershell
# Policy: MFA for all guest users
$params = @{
    displayName = "CA-Guest-MFA-Required"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeGuestsOrExternalUsers = @{
                guestOrExternalUserTypes = "b2bCollaborationGuest,b2bCollaborationMember"
                externalTenants = @{
                    membershipKind = "all"
                }
            }
        }
        applications = @{
            includeApplications = @("All")
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("mfa")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Task 7: Enable Policy (Change from Report-Only)

powershell
# Get policy
$policy = Get-MgIdentityConditionalAccessPolicy | 
    Where-Object { $_.DisplayName -eq "CA-Require-MFA-All-Users" }

# Update to enabled
Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id `
    -State "enabled"

# Or back to report-only
Update-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $policy.Id `
    -State "enabledForReportingButNotEnforced"

Task 8-9: Review and Audit

List All Policies

powershell
# List all CA policies with their state
Get-MgIdentityConditionalAccessPolicy | 
    Select-Object DisplayName, State, Id |
    Format-Table -AutoSize

Get Policy Details

powershell
# Get specific policy details
$policy = Get-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId "policy-id"
$policy | ConvertTo-Json -Depth 10

Export All Policies (Backup)

powershell
# Export all policies to JSON
$policies = Get-MgIdentityConditionalAccessPolicy
$policies | ConvertTo-Json -Depth 10 | Out-File "ca-policies-backup.json"

Check Sign-in Logs for CA Impact

powershell
# Get sign-in logs with CA results
Connect-MgGraph -Scopes "AuditLog.Read.All"

Get-MgAuditLogSignIn -Top 50 | 
    Select-Object CreatedDateTime, UserDisplayName, AppDisplayName, 
                  ConditionalAccessStatus |
    Format-Table -AutoSize

# Filter for failures due to CA
Get-MgAuditLogSignIn -Filter "conditionalAccessStatus eq 'failure'" -Top 50 |
    Select-Object CreatedDateTime, UserDisplayName, AppDisplayName

Azure CLI Alternative

bash
# Note: Azure CLI has limited CA support, use Graph API or PowerShell

# List CA policies using REST
az rest --method GET \
    --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies"

# Create policy using REST
az rest --method POST \
    --url "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" \
    --body '{
        "displayName": "CA-Test-Policy",
        "state": "enabledForReportingButNotEnforced",
        "conditions": {
            "users": {
                "includeUsers": ["All"]
            },
            "applications": {
                "includeApplications": ["All"]
            }
        },
        "grantControls": {
            "operator": "OR",
            "builtInControls": ["mfa"]
        }
    }'

Policy Templates (Common Scenarios)

Block Legacy Authentication

powershell
$params = @{
    displayName = "CA-Block-Legacy-Auth"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeUsers = @("All")
        }
        applications = @{
            includeApplications = @("All")
        }
        clientAppTypes = @("exchangeActiveSync", "other")
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("block")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Require Compliant Device

powershell
$params = @{
    displayName = "CA-Require-Compliant-Device"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeUsers = @("All")
        }
        applications = @{
            includeApplications = @("All")
        }
        platforms = @{
            includePlatforms = @("all")
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("compliantDevice")
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Session Control - Sign-in Frequency

powershell
$params = @{
    displayName = "CA-Session-Timeout"
    state = "enabledForReportingButNotEnforced"
    conditions = @{
        users = @{
            includeUsers = @("All")
        }
        applications = @{
            includeApplications = @("All")
        }
    }
    grantControls = @{
        operator = "OR"
        builtInControls = @("mfa")
    }
    sessionControls = @{
        signInFrequency = @{
            value = 4
            type = "hours"
            isEnabled = $true
        }
    }
}

New-MgIdentityConditionalAccessPolicy -BodyParameter $params

Cleanup

powershell
# Delete specific policy
$policy = Get-MgIdentityConditionalAccessPolicy | 
    Where-Object { $_.DisplayName -like "CA-Lab-*" }
    
foreach ($p in $policy) {
    Remove-MgIdentityConditionalAccessPolicy -ConditionalAccessPolicyId $p.Id
}

# Delete named locations
$locations = Get-MgIdentityConditionalAccessNamedLocation | 
    Where-Object { $_.DisplayName -like "*Lab*" }

foreach ($loc in $locations) {
    Remove-MgIdentityConditionalAccessNamedLocation -NamedLocationId $loc.Id
}

# Disconnect
Disconnect-MgGraph

Useful Commands Reference

TaskCommand
List policiesGet-MgIdentityConditionalAccessPolicy
Create policyNew-MgIdentityConditionalAccessPolicy
Update policyUpdate-MgIdentityConditionalAccessPolicy
Delete policyRemove-MgIdentityConditionalAccessPolicy
List locationsGet-MgIdentityConditionalAccessNamedLocation
Create locationNew-MgIdentityConditionalAccessNamedLocation
Get sign-in logsGet-MgAuditLogSignIn

Released under the MIT License.