Skip to content

Instantly share code, notes, and snippets.

@machv
Last active August 4, 2020 12:14
Show Gist options
  • Save machv/d8a32dcbb22e3cc83dc97b136aca00e3 to your computer and use it in GitHub Desktop.
Save machv/d8a32dcbb22e3cc83dc97b136aca00e3 to your computer and use it in GitHub Desktop.
#region create AAD app
# based on https://docs.microsoft.com/en-us/powershell/partnercenter/secure-app-model?view=partnercenterps-1.5
$DisplayName = "MFA Status Ingester"
Connect-AzureAD
$adAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
ResourceAppId = "00000002-0000-0000-c000-000000000000";
ResourceAccess =
[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
Id = "5778995a-e1bf-45b8-affa-663a9f3f4d04";
Type = "Role"},
[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
Id = "a42657d6-7f20-40e3-b6f0-cee03008a62a";
Type = "Scope"},
[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
Id = "311a71cc-e848-46a1-bdf8-97ff7156d8e6";
Type = "Scope"}
}
$graphAppAccess = [Microsoft.Open.AzureAD.Model.RequiredResourceAccess]@{
ResourceAppId = "00000003-0000-0000-c000-000000000000";
ResourceAccess =
[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
Id = "bf394140-e372-4bf9-a898-299cfc7564e5";
Type = "Role"},
[Microsoft.Open.AzureAD.Model.ResourceAccess]@{
Id = "7ab1d382-f21e-4acd-a863-ba3e13f7da61";
Type = "Role"}
}
$SessionInfo = Get-AzureADCurrentSessionInfo
$app = New-AzureADApplication -AvailableToOtherTenants $true -DisplayName $DisplayName -RequiredResourceAccess $adAppAccess, $graphAppAccess -ReplyUrls @("https://localhost:15975")
$password = New-AzureADApplicationPasswordCredential -ObjectId $app.ObjectId -StartDate (get-date) -EndDate ((Get-Date).addYears(5)) -CustomKeyIdentifier "PowerShell"
#$spn = New-AzureADServicePrincipal -AppId $app.AppId -DisplayName $DisplayName
Write-Host "ApplicationId = $($app.AppId)"
Write-Host "ApplicationSecret = $($password.Value)"
Write-Host -ForegroundColor Yellow "Don't forget to grant admin consent to this app in Azure AD portal!"
#endregion
#region Initial login - onetime
if(-not (Get-Module -ListAvailable "Oauth2Toolkit")) {
Install-Module "Oauth2Toolkit"
}
$clientId = $app.AppId
$clientSecret = $password.Value
$configFilePath = "$($env:USERPROFILE)\aad.cnf"
$response = Invoke-CodeGrantFlow -RedirectUrl "https://localhost:15975/" -ClientId $clientId -ClientSecret $clientSecret -Tenant $SessionInfo.TenantId -Resource $clientId -AlwaysPrompt $true
$json = @{
RefreshToken = $response.refresh_token
ClientSecret = $clientSecret
ClientId = $clientId
TenantId = $SessionInfo.TenantId
} | ConvertTo-Json
[Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($json)) | Set-Content $configFilePath
#endregion
#region Get report - Save as second file and schedule in Task Scheduler
$configFilePath = "$($env:USERPROFILE)\aad.cnf"
$reportPath = "E:\MFA_Report.csv"
$data = Get-Content $configFilePath
$config = [System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($data)) | ConvertFrom-Json
$token = New-AccessToken -Tenant $config.TenantId -ClientId $config.ClientId -ClientSecret $config.ClientSecret -RefreshToken $config.RefreshToken
$msGraphToken = Invoke-OnBehalfOfFlow -Tenant $config.TenantId -ClientId $config.ClientId -ClientSecret $config.ClientSecret -AccessToken $token.AccessToken -Resource "https://graph.microsoft.com"
$adGraphToken = Invoke-OnBehalfOfFlow -Tenant $config.TenantId -ClientId $config.ClientId -ClientSecret $config.ClientSecret -AccessToken $token.AccessToken -Resource "https://graph.windows.net"
Connect-MsolService -AdGraphAccessToken $adGraphToken.access_token -MsGraphAccessToken $msGraphToken.access_token
Get-MsolUser -All | Select-Object @{N='UserPrincipalName';E={$_.UserPrincipalName}},
@{N='MFA Status';E={if ($_.StrongAuthenticationRequirements.State){$_.StrongAuthenticationRequirements.State} else {"Disabled"}}},
@{N='MFA Methods';E={$_.StrongAuthenticationMethods.methodtype}} | Export-Csv -Path $reportPath -NoTypeInformation -Encoding UTF8
#endregion
function New-AccessToken
{
param(
[string]$Tenant,
[Parameter(ParameterSetName='ClientCredential')]
[pscredential]$Client,
[Parameter(ParameterSetName='ClientExplicit')]
[string]$ClientId,
[Parameter(ParameterSetName='ClientExplicit')]
[string]$ClientSecret,
[string]$RefreshToken
)
$authUrl = "https://login.microsoftonline.com/{0}/oauth2/token" -f $Tenant
$parameters = @{
grant_type = "refresh_token"
client_secret= $ClientSecret
refresh_token = $RefreshToken
client_id = $ClientId
}
$response = Invoke-RestMethod -Uri $authUrl -Method Post -Body $parameters
$expires = ConvertFrom-Timestamp -Timestamp $response.expires_on
$result = [PSCustomObject]@{
Expires = $expires
AccessToken = $response.access_token
}
$result
}
function Invoke-OnBehalfOfFlow
{
# https://docs.microsoft.com/en-us/azure/active-directory/develop/v1-oauth2-on-behalf-of-flow
param(
[Parameter(Mandatory = $true)]
[string]$Tenant,
[Parameter(Mandatory = $true)]
[string]$ClientId,
[Parameter(Mandatory = $true)]
[string]$clientSecret,
[Parameter(Mandatory = $true)]
[string]$AccessToken,
[Parameter()]
[string]$Resource = "https://graph.microsoft.com"
)
$payload = @{
grant_type = "urn:ietf:params:oauth:grant-type:jwt-bearer"
requested_token_use = "on_behalf_of"
scope = "openid"
assertion = $AccessToken
resource = $Resource
client_id = $ClientId
client_secret = $clientSecret
}
$response = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$Tenant/oauth2/token" -Body $payload
$response
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment