Monitoring with PowerShell: Monitoring legacy authentication logons

This is going to be the last blog for a couple of weeks, as I’m going to be enjoying some vacation time. I’ll be seeing you all soon! 🙂

So Microsoft has announced a while back that legacy authentication is no longer going to be supported, due to COVID we had some extra time to prepare our clients for this change as its been postponed to July of 2021. We’ve helped all of our clients move to modern authentication last year but I understood there is still a bit of a struggle for other MSPs to achieve this.

With a P1 subscription retrieving the Legacy Authentication reports is very straightforward, but I’ve created these methods for users without P1 in mind. You have to keep in mind that this method is slightly less accurate than using the P1 sign in report.

There’s two scripts in this case; one to detect if Azure Security Defaults are enabled, which disables Legacy Authentication for you. And another to detect if there are apps being used that might use legacy authentication. You’ll still have to do some manual investigation and move users over to newer apps, but it should help you tackle modern auth in no time. 🙂

Detecting if Azure Security Defaults are enabled

Before running this script, you’ll have to add some permissions to your Secure Application Model, do that by performing this:

  • Go to the Azure Portal.
  • Click on Azure Active Directory, now click on “App Registrations”.
  • Find your Secure App Model application. You can search based on the ApplicationID.
  • Go to “API Permissions” and click Add a permission.
  • Choose “Microsoft Graph” and “Application permission”.
  • Search for “Reports” and click on “Policy.read.all”. Click on add permission
  • Do the same for “Delegate Permissions”.
  • Finally, click on “Grant Admin Consent for Company Name.
######### Secrets #########
$ApplicationId = 'AppID'
$ApplicationSecret = 'AppSecret' | ConvertTo-SecureString -Force -AsPlainText
$TenantID = 'Your-TenantID'
$RefreshToken = 'VeryLongRefreshToken'
$UPN = "UPN-Used-To-Generate-Tokens"
######### Secrets #########
write-host "Generating token to log into Azure AD. Grabbing all tenants" -ForegroundColor Green
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)
$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID
Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId $upn -MsAccessToken $graphToken.AccessToken -TenantId $tenantID | Out-Null
$tenants = Get-AzureAdContract -All:$true
Disconnect-AzureAD
$SecDefaults = foreach ($Tenant in $Tenants) {
    write-host "Processing $($Tenant.DisplayName)"
    $CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes "https://graph.microsoft.com/.default" -ServicePrincipal -Tenant $tenant.CustomerContextId
    $Header = @{
        Authorization = "Bearer $($CustGraphToken.AccessToken)"
    }
    $Enabled = (Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/policies/identitySecurityDefaultsEnforcementPolicy" -Headers $Header -Method get -ContentType "application/json").IsEnabled
    [PSCustomObject]@{
        TenantName                  = $tenant.DisplayName
        'Security Defaults Enabled' = $enabled
    }
}

$SecDefaults

Detecting Legacy Application Usage

So finding legacy application usage is the biggest step in finding out if users are still using Legacy Authentication, for that use the following script:

######### Secrets #########
$ApplicationId = 'AppID'
$ApplicationSecret = 'AppSecret' | ConvertTo-SecureString -Force -AsPlainText
$TenantID = 'Your-TenantID'
$RefreshToken = 'VeryLongRefreshToken'
$UPN = "UPN-Used-To-Generate-Tokens"
######### Secrets #########
write-host "Generating token to log into Azure AD. Grabbing all tenants" -ForegroundColor Green
$credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret)
$aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID
$graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID
Connect-AzureAD -AadAccessToken $aadGraphToken.AccessToken -AccountId $upn -MsAccessToken $graphToken.AccessToken -TenantId $tenantID | Out-Null
$tenants = Get-AzureAdContract -All:$true
Disconnect-AzureAD
$LegacyAuth = foreach ($Tenant in $Tenants) {
    write-host "Processing tenant $($tenant.displayname)"
    $CustGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes "https://graph.microsoft.com/.default" -ServicePrincipal -Tenant $tenant.CustomerContextId
    $Header = @{
        Authorization = "Bearer $($CustGraphToken.AccessToken)"
    }
    $VersionReport = (Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/reports/getEmailAppUsageVersionsUserCounts(period='D7')" -Headers $Header -Method get -ContentType "application/json") | ConvertFrom-Csv
    $LegacyClients = if ($versionreport.'Outlook 2007' -or $versionreport.'Outlook 2010' -or $versionreport.'Outlook 2013') {
        $VersionReport
    }
    $AppReports = (Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/reports/getEmailAppUsageAppsUserCounts(period='D7')" -Headers $Header -Method get -ContentType "application/json") | ConvertFrom-Csv

    $LegacyApplications = if ($AppReports.'Other For Mobile' -or $AppReports.'POP3 App' -or $AppReports.'SMTP App' -or $AppReports.'IMAP4 App' -or $AppReports.'Mail For Mac') {
        $AppReports
    }
    $UserDetails = (Invoke-RestMethod -Uri "https://graph.microsoft.com/beta/reports/getEmailAppUsageUserDetail(period='D7')" -Headers $Header -Method get -ContentType "application/json") | ConvertFrom-Csv

    [PSCustomObject]@{
        Tenant        = $tenant.DisplayName
        LegacyClients = $LegacyClients
        LegacyApps    = $LegacyApplications
        UserDetails   = $UserDetails
    }

}

if ($LegacyAuth.LegacyClients -or $LegacyAuth.LegacyApps) {
    write-host "Unhealthy - Clients with legacy authenticaiton or Legacy clients have been detected"
    $LegacyAuth | Where-Object {$_.LegacyClients -ne $null -or $_.LegacyApps -ne $null}
}

And that’s it! It might not be as accurate as the normal P1 report, but it surely helps in capturing Legacy Authentication. As always, Happy PowerShelling!

Recent Articles

The return of CyberDrain CTF

CyberDrain CTF returns! (and so do I!)

It’s been since september that I actually picked up a digital pen equivalent and wrote anything down. This was due to me being busy with life but also my side projects like CIPP. I’m trying to get back into the game of scripting and blogging about these scripts. There’s still so much to automate and so little time, right? ;)

Monitoring with PowerShell: Monitoring Acronis Backups

Intro

This is a monitoring script requested via Reddit, One of the reddit r/msp users wondered how they can monitor Acronis a little bit easier. I jumped on this because it happened pretty much at the same time that I was asked to speak at the Acronis CyberSummit so it kinda made sense to script this so I have something to demonstrate at my session there.

Monitoring with PowerShell: Monitoring VSS Snapshots

Intro

Wow! It’s been a while since I’ve blogged. I’ve just been so swamped with CIPP that I’ve just let the blogging go entirely. It’s a shame because I think out of all my hobbies it’s one I enjoy the most. It’s always nice helping others achieve their scripting target. I even got a couple of LinkedIn questions asking if I was done with blogging but I’m not. Writing always gives me some more piece of mind so I’ll try to catch up again. I know I’ve said that before but this time I’ll follow through. I’m sitting down right now and scheduling the release of 5 blogs in one go. No more whining and no more waiting.