O365-GlobalAdminMfaDisabledReport.ps1

<#PSScriptInfo
.VERSION 1.0
.GUID 90295b93-0521-4a62-bd5f-e73637ee59a5
.AUTHOR Soren Lindevang
.COMPANYNAME
.COPYRIGHT
.TAGS PowerShell Office 365 Reporting Report Multifactor MultifactorAuthentication Authentication MFA Azure Automation
.LICENSEURI
.PROJECTURI
.ICONURI
.EXTERNALMODULEDEPENDENCIES
.REQUIREDSCRIPTS
.EXTERNALSCRIPTDEPENDENCIES
.RELEASENOTES
#>


<#
.SYNOPSIS
    Generate Report of Office 365 Global Admins not secured with multi-factor authentication.
 
.DESCRIPTION
    Searches for global admins with multifactor authentication disabled in a Office 365 tenant.
     
    Option to send a CSV report over e-mail.
     
    Designed for execution in Azure Automation.
 
    Check out the GitHub Repo for more information: http://soren.cloud/o365-secure-score-azure-automation-part-3-global-admin-with-mfa-disabled-report
 
.PARAMETER AutomationPSCredentialName
    Name of the Automation Credential used when connecting to Office 365 / Azure Active Directory.
 
    The Account should at least have 'User management administrator' rights in the tenant.
 
    Example: Office 365 - User Management Service Account
 
.PARAMETER ExcludeUserAccount
    Global admins to be excluded when searching for accounts with MFA disabled.
 
    Must be the user principal name (UPN) of the global admin account(s).
 
    Example 1: ['gadmin1@tenant.onmicrosoft.com']
    Example 2: ['gadminA@tenant.onmicrosoft.com','gadminB@tenant.onmicrosoft.com']
 
.PARAMETER SendReport
     If this switch is present, the script sends an email with a CSV file attached, if any MFA-disabled accounts are detected.
      
     If used, please do modify the 'SendMailReport' variables in the 'Declarations' area.
 
     Example 1: true
     Example 2: false
 
     Default value = false
 
.PARAMETER ReportSmtpServerAddress
     This field is mandatory if 'SendReport' switch is present. Defines the SMTP server address (FQDN or IP address)
 
     Example 1: smtp.office365.com
     Example 2: 123.45.67
 
.PARAMETER ReportSmtpServerPort
     This field is mandatory if 'SendReport' switch is present. Defines the port used by the SMTP server
      
     Example 1: 587
     Example 2: 25
 
 
.PARAMETER ReportSmtpFromAddress
     This field is mandatory if 'SendReport' switch is present. Defines the from address when sending reports
 
     Example 1: Office 365 Automation <noreply@domain.com>
     Example 2: noreply@domain.com
 
.PARAMETER ReportSmtpToAddress
     This field is mandatory if 'SendReport' switch is present. Defines the recipient address(es) when sending reports
 
     Example 1: ["recipient_a@domain.com"]
     Example 2: ["recipient_a@domain.com","recipient_b@domain.com"]
 
.PARAMETER ReportSmtpPSCredentialName
    This field is mandatory if 'SendReport' switch is present. Name of the Automation Credential used when connecting sending a report.
 
    If using a Exchange Online Mailbox, the Account should at least have 'send-as' permissions of the mailbox defined in 'ReportSmtpFromAddress'.
 
    Example: Office 365 Automation Mailbox
 
.PARAMETER EnableVerbose
     If this switch is present, 'VerbosePreference' will be set to "Continue" in the script.
      
     Build-in Verbose switch is not supported by Azure Automation (yet).
      
     Example 1: true
     Example 2: false
 
     Default value = false
 
.INPUTS
    N/A
 
.OUTPUTS
    N/A
 
.NOTES
    Version: 1.0
    Author: Soren Greenfort Lindevang
    Creation Date: 06.06.2018
    Purpose/Change: Initial script development
   
.EXAMPLE
    N/A
#>

[cmdletbinding()]
param (
    [Parameter(
        Mandatory=$true)]
        [string]$AutomationPSCredentialName,
    [Parameter(
        Mandatory=$false)]
        [string[]]$ExcludeUserAccount,
    [Parameter(
        Mandatory=$false)]
        [switch]$SendReport,
    [Parameter(
        Mandatory=$false)]
        [string]$ReportSmtpServerAddress,
    [Parameter(
        Mandatory=$false)]
        [string]$ReportSmtpServerPort,
    [Parameter(
        Mandatory=$false)]
        [string]$ReportSmtpFromAddress,
    [Parameter(
        Mandatory=$false)]
        [string[]]$ReportSmtpToAddress,
    [Parameter(
        Mandatory=$false)]
        [string]$ReportSmtpPSCredentialName,
    [Parameter(
        Mandatory=$false)]
        [switch]$EnableVerbose
)


#-----------------------------------------------------------[Functions]------------------------------------------------------------

# Test if script is running in Azure Automation
function Test-AzureAutomationEnvironment
    {
    if ($env:AUTOMATION_ASSET_ACCOUNTID)
        {
        Write-Verbose "This script is executed in Azure Automation"
        }
    else
        {
        $ErrorMessage = "This script is NOT executed in Azure Automation."
        throw $ErrorMessage
        }
    }

function Stop-AutomationScript
    {
    param(
        [ValidateSet("Failed","Success")]
        [string]
        $Status = "Success"
        )
    Write-Output ""
    if ($Status -eq "Success")
        {
        Write-Output "Script successfully completed"
        }
    elseif ($Status -eq "Failed")
        {
        Write-Output "Script stopped with an Error"
        }
    Break
    }


#----------------------------------------------------------[Declarations]----------------------------------------------------------

# General Send Report Variables
$ReportSubject = "Report: Global Admin(s) with MFA Disabled"
$ReportBody = "CSV file attached, containing Global Admins with MFA disabled" 



#-----------------------------------------------------------[Execution]-----------------------------------------------------------

# Check if script is executed in Azure Automation
Test-AzureAutomationEnvironment

Write-Output "::: Parameters :::"
Write-Output "AutomationPSCredentialName: $AutomationPSCredentialName"
Write-Output "ExcludeUserAccount: $ExcludeUserAccount"
Write-Output "SendReport: $SendReport"
Write-Output "ReportSmtpServerAddress $ReportSmtpServerAddress"
Write-Output "ReportSmtpServerPort $ReportSmtpServerPort"
Write-Output "ReportSmtpFromAddress $ReportSmtpFromAddress"
Write-Output "ReportSmtpToAddress $ReportSmtpToAddress"
Write-Output "ReportSmtpPSCredentialName: $ReportSmtpPSCredentialName"
Write-Output "EnableVerbose: $EnableVerbose"
Write-Output ""

# Handle Verbose Preference
if ($EnableVerbose -eq $true)
    {
    $VerbosePreference = "Continue"
    }

# Get AutomationPSCredential
Write-Output "::: Connection :::"
try
    {
    Write-Output "Importing Automation Credential"
    $Credential = Get-AutomationPSCredential -Name $AutomationPSCredentialName -ErrorAction Stop
    }
catch 
    {
    Write-Error $_.Exception
    Stop-AutomationScript -Status Failed
    }
Write-Verbose "Successfully imported credentials"

# Connect MsolService
try 
    {
    Connect-MsolService -Credential $Credential -ErrorAction Stop
    }
catch
    {
    Write-Error $_.Exception
    Stop-AutomationScript -Status Failed
    }

# Collect Global Admins with MFA Disabled
try
    {
    $GlobalAdminRole = Get-MsolRole -RoleName "Company Administrator" -ErrorAction Stop
    $GlobalAdminMembers = Get-MsolRoleMember -RoleObjectId $GlobalAdminRole.ObjectId -ErrorAction Stop
    $GlobalAdminMembersCount = $($GlobalAdminMembers | Measure-Object).Count
    $GlobalAdminsMfaDisabled = $GlobalAdminMembers | Where-Object {!$_.StrongAuthenticationRequirements}
    $GlobalAdminsMfaDisabledCount = $($GlobalAdminsMfaDisabled | Measure-Object).Count
    }
catch 
    {
    Write-Error $_.Exception
    Stop-AutomationScript -Status Failed
    }

if ($GlobalAdminsMfaDisabled)
    {
    Write-Verbose "Successfully Collected Global Admins with MFA Disabled"
    Write-Output "Found $GlobalAdminsMfaDisabledCount Global Admin(s) with MFA Disabled"
    $count = $null
    foreach ($GlobalAdmin in $GlobalAdminsMfaDisabled)
        {
        $count++
        Write-Verbose "($count): $($GlobalAdmin.EmailAddress)"
        }
    }
else
    {
    Write-Output "All Global Admins ($GlobalAdminMembersCount) have MFA enabled"
    Stop-AutomationScript -Status Success
    }


# Exclusion
if ($ExcludeUserAccount)
    {
    Write-Verbose "User Account Exclusion Switch Set - Processesing"
    $GlobalAdminsMfaDisabled_Excluded = $GlobalAdminsMfaDisabled | Where-Object {$ExcludeUserAccount -contains $_.EmailAddress}
    $GlobalAdminsMfaDisabled_ToProcess = $GlobalAdminsMfaDisabled | Where-Object {$ExcludeUserAccount -notcontains $_.EmailAddress}
    foreach ($GlobalAdmin in $GlobalAdminsMfaDisabled_Excluded)
        {
        Write-Output "Excluded following Global Admin: $($GlobalAdmin.EmailAddress)"
        }
    if (!$GlobalAdminsMfaDisabled_ToProcess)
        {
        Write-Output "All Global Admins with MFA Disabled has been Excluded"
        Stop-AutomationScript -Status Success
        }
    elseif (!$GlobalAdminsMfaDisabled_Excluded)
        {
        Write-Output "No Global Admins with MFA Disabled Matched the Exclusion List"
        }
    }
else
    {
    Write-Verbose "No User Account Exclusion Switch Set - Continuing"
    }
    

# Send Mail Report
if ($SendReport)
    {
    Write-Output ""
    Write-Output "::: Send Mail Report :::"
    Write-Output "Importing Automation Credential"
    try
        {
        $ReportSmtpPSCredential = Get-AutomationPSCredential -Name $ReportSmtpPSCredentialName -ErrorAction Stop
        }
    catch 
        {
        Write-Error $_.Exception
        Stop-AutomationScript -Status Failed
        }
    Write-Verbose "Successfully imported credentials"

    $ReportTime = Get-Date -Format "MM-dd-yyyy_HH-mm-ss"

    Write-Output "Generate MFA Disabled CSV file"
    try
        {
        $CSVFileName = "GlobalAdminMfaDisabled_" + $ReportTime + ".csv"
        $CSVFilePath = $env:TEMP + "\" + $CSVFileName
        $GlobalAdminsMfaDisabled_ToProcess | Select-Object EmailAddress,DisplayName `
            | Export-CSV -LiteralPath $CSVFilePath -Encoding Unicode -NoTypeInformation -Delimiter "`t" -ErrorAction Stop
        }
    catch 
        {
        Write-Error $_.Exception
        Stop-AutomationScript -Status Failed
        }
    Write-Verbose "Successfully Generated MFA Disabled CSV file"
    $ReportSmtpToString = $ReportSmtpToAddress -join ", "
    Write-Output "Send e-mail to '$ReportSmtpToString' from '$ReportSmtpFromAddress'" 
    try
        {
        Send-MailMessage -To $ReportSmtpToAddress -From $ReportSmtpFromAddress -Subject $ReportSubject `
            -Body $ReportBody -BodyAsHtml -Attachments $CSVFilePath -SmtpServer $ReportSmtpServerAddress `
            -Port $ReportSmtpServerPort -UseSsl -Credential $ReportSmtpPSCredential -ErrorAction Stop
        }
    catch 
        {
        Write-Error $_.Exception
        Stop-AutomationScript -Status Failed
        }
    Write-Verbose "Successfully sent e-mail to '$ReportSmtpToString' from '$ReportSmtpFromAddress'"
    }
else
    {
    Write-Output "Report switch set to false. No report is sent."
    Stop-AutomationScript -Status Success
    }

# Script Completed
Stop-AutomationScript -Status Success