Skip to content

Instantly share code, notes, and snippets.

@DanClowry
Last active June 23, 2023 21:55
Show Gist options
  • Save DanClowry/a01e0a54d744ab4cfdef1c9ddaf9cac7 to your computer and use it in GitHub Desktop.
Save DanClowry/a01e0a54d744ab4cfdef1c9ddaf9cac7 to your computer and use it in GitHub Desktop.
Enable Unified Audit Log for Microsoft 365 Delegated Tenants
Original scripts sourced from https://gcits.com/knowledge-base/enabling-unified-audit-log-delegated-office-365-tenants-via-powershell/
How to use these scripts:
1. Modify the headers of each script to suit your environment (username, admin password, admin prefix, CSV paths, etc)
2. Run GetAuditStats.ps1 and sign into your account with delegated admin access when prompted - wait at least 12 hours after running this script before proceeding to step 3 to allow any new admin accounts to properly provision
3. Run EnableOrgCustomisation.ps1 and sign into your account with delegated admin access when prompted - wait at least 48 hours after running this script before proceeding to step 4 to ensure that tenants are properly hydrated
a. You may need to rerun this script 2 or 3 times to ensure that every tenant is hydrated. It seems like sometimes the hydration command errors out and doesn't properly hydrate a tenant on the first go ¯\_(ツ)_/¯.
4. Run EnableAuditing.ps1 and sign into your account with delegated admin access when prompted
5. Confirm that auditing is enabled for tenants and that the temporary Global Admin account created in GetAuditStats.ps1 has been deleted from the tenant
# This script will use the admin users created by the first script to enable the Unified Audit Log in each tenant. If enabling the Unified Audit Log is successful, it'll remove the created admin. If it's not successful, it'll keep the admin in place and add it to another CSV. You can retry these tenants by modifying the $Customers value to import the RemainingAdminsCsv in the next run. #>
#-------------------------------------------------------------
# Here are some things you can modify:
# IMPORTANT: This is the default password for the temporary admin users. Use the same password that you specified in the first script.
$NewAdminPassword = "Password123"
# This is the CSV containing the details of the created admins generated by the first script. If you changed the path in the first script, you'll need to change it here.
$Customers = import-csv "C:\temp\CreatedAdmins.csv"
# This CSV will contain a list of all admins removed by this script.
$RemovedAdminsCsv = "C:\temp\RemovedAdmins.csv"
# This CSV will contain a list of all unsuccessful admins left unchanged by this script. Use it to retry this script without having to start again.
$RemainingAdminsCsv = "C:\temp\RemainingAdmins.csv"
#-------------------------------------------------------------
Connect-MsolService
foreach ($Customer in $Customers) {
Write-Host $Customer.CompanyName.ToUpper()
Write-Host " "
$NewAdminUPN = $Customer.UserPrincipalName
$secpasswd = ConvertTo-SecureString $NewAdminPassword -AsPlainText -Force
$NewAdminCreds = New-Object System.Management.Automation.PSCredential ($NewAdminUPN, $secpasswd)
Write-Host " "
Write-Output "Getting the Exchange Online cmdlets as $NewAdminUPN"
Connect-ExchangeOnline -Credential $NewAdminCreds -ShowBanner:$false -CommandName:@("Get-AdminAuditLogConfig", "Set-AdminAuditLogConfig")
# Enable the Unified Audit Log
Set-AdminAuditLogConfig -UnifiedAuditLogIngestionEnabled $true
# Find out whether it worked
$AuditLogConfigResult = Get-AdminAuditLogConfig
Disconnect-ExchangeOnline -Confirm:$false
# If it worked, remove the Admin and add the removed admin details to a CSV
if ($AuditLogConfigResult.UnifiedAuditLogIngestionEnabled) {
# Remove the temporary admin
Write-Host "Removing the temporary Admin"
Remove-MsolUser -TenantId $Customer.TenantId -UserPrincipalName $NewAdminUPN -Force
$AdminProperties = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.CompanyName
DefaultDomainName = $Customer.DefaultDomainName
UserPrincipalName = $NewAdminUPN
Action = "REMOVED"
}
$RemovedAdmins = @()
$RemovedAdmins += New-Object psobject -Property $AdminProperties
$RemovedAdmins | Select-Object TenantId, CompanyName, DefaultDomainName, UserPrincipalName, Action | Export-Csv -notypeinformation -Path $RemovedAdminsCsv -Append
}
# If it didn't work, keep the Admin and add the admin details to another CSV. You can use the RemainingAdmins CSV if you'd like to try again.
if (!$AuditLogConfigResult.UnifiedAuditLogIngestionEnabled) {
Write-Host "Enabling Audit Log Failed, keeping the temporary Admin"
$AdminProperties = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.CompanyName
DefaultDomainName = $Customer.DefaultDomainName
UserPrincipalName = $NewAdminUPN
Action = "UNCHANGED"
}
$RemainingAdmins = @()
$RemainingAdmins += New-Object psobject -Property $AdminProperties
$RemainingAdmins | Select-Object TenantId, CompanyName, DefaultDomainName, UserPrincipalName, Action | Export-Csv -notypeinformation -Path $RemainingAdminsCsv -Append
}
Write-Host " "
Write-Host "----------------------------------------------------------"
Write-Host " "
}
# This script will use the admin users created by the first script to enable the Unified Audit Log in each tenant. If enabling the Unified Audit Log is successful, it'll remove the created admin. If it's not successful, it'll keep the admin in place and add it to another CSV. You can retry these tenants by modifying the $Customers value to import the RemainingAdminsCsv in the next run. #>
#-------------------------------------------------------------
# Here are some things you can modify:
# IMPORTANT: This is the default password for the temporary admin users. Use the same password that you specified in the first script.
$NewAdminPassword = "Password123"
# This is the CSV containing the details of the created admins generated by the first script. If you changed the path in the first script, you'll need to change it here.
$Customers = import-csv "C:\temp\CreatedAdmins.csv"
# This CSV will contain a list of all tenants who have organization customization enabled.
$HydratedAdminsCsv = "C:\temp\HydratedTenants.csv"
# This CSV will contain a list of all tenants who failed to have organization customization enabled. Use it to retry this script without having to start again.
$FailedTenantsCsv = "C:\temp\FailedTenants.csv"
#-------------------------------------------------------------
Connect-MsolService
foreach ($Customer in $Customers) {
Write-Host $Customer.CompanyName.ToUpper()
Write-Host " "
$NewAdminUPN = $Customer.UserPrincipalName
$secpasswd = ConvertTo-SecureString $NewAdminPassword -AsPlainText -Force
$NewAdminCreds = New-Object System.Management.Automation.PSCredential ($NewAdminUPN, $secpasswd)
Write-Host " "
Write-Output "Getting the Exchange Online cmdlets as $NewAdminUPN"
Connect-ExchangeOnline -Credential $NewAdminCreds -ShowBanner:$false -CommandName:@("Enable-OrganizationCustomization", "Get-OrganizationConfig")
# Get tenant's current hydration status
$OrganizationConfigResult = Get-OrganizationConfig
# Only enable org customisation if it hasn't already been enabled
if ($OrganizationConfigResult.IsDehydrated) {
# Enable the customization of the Exchange Organisation
Enable-OrganizationCustomization
# Recheck that tenant is now hydrated
$OrganizationConfigResult = Get-OrganizationConfig
}
Disconnect-ExchangeOnline -Confirm:$false
# If it worked, add the admin details to the hydrated CSV
if (!$OrganizationConfigResult.IsDehydrated) {
Write-Host "Tenant hydrated"
$AdminProperties = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.CompanyName
DefaultDomainName = $Customer.DefaultDomainName
UserPrincipalName = $NewAdminUPN
Action = "HYDRATED"
}
$HydratedTenants = @()
$HydratedTenants += New-Object psobject -Property $AdminProperties
$HydratedTenants | Select-Object TenantId, CompanyName, DefaultDomainName, UserPrincipalName, Action | Export-Csv -notypeinformation -Path $HydratedAdminsCsv -Append
}
if ($OrganizationConfigResult.IsDehydrated) {
Write-Host "Tenant did not hydrate"
$AdminProperties = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.CompanyName
DefaultDomainName = $Customer.DefaultDomainName
UserPrincipalName = $NewAdminUPN
Action = "DEHYDRATED"
}
$DehydratedTenants = @()
$DehydratedTenants += New-Object psobject -Property $AdminProperties
$DehydratedTenants | Select-Object TenantId, CompanyName, DefaultDomainName, UserPrincipalName, Action | Export-Csv -notypeinformation -Path $FailedTenantsCsv -Append
}
Write-Host " "
Write-Host "----------------------------------------------------------"
Write-Host " "
}
Write-Host "Tenant Hydration Completed for all tenants, please wait 48 hours before running the third script."
Write-Host " "
# This script will connect to all delegated Office 365 tenants and check whether the Unified Audit Log is enabled. If it's not, it will create an Exchange admin user with a standard password. Once it's processed, you'll need to wait a few hours (preferably a day), then run the second script. The second script connects to your customers' Office 365 tenants via the new admin users and enables the Unified Audit Log ingestion. If successful, the second script will also remove the admin users created in this script. #>
#-------------------------------------------------------------
# Here are some things you can modify:
# This is your partner admin user name that has delegated administration permission
$UserName = "training@gcits.com"
# IMPORTANT: This is the default password for the temporary admin users. Don't leave this as Password123, create a strong password between 8 and 16 characters containing Lowercase letters, Uppercase letters, Numbers and Symbols.
$NewAdminPassword = "Password123"
# IMPORTANT: This is the default User Principal Name prefix for the temporary admin users. Don't leave this as gcitsauditadmin, create something UNIQUE that DOESNT EXIST in any of your tenants already. If it exists, it'll be turned into an admin and then deleted.
$NewAdminUserPrefix = "gcitsauditadmin"
# This is the path for the exported CSVs. You can change this, though you'll need to make sure the path exists. This location is also referenced in the second script, so I recommend keeping it the same.
$CreatedAdminsCsv = "C:\temp\CreatedAdmins.csv"
$UALCustomersCsv = "C:\temp\UALCustomerStatus.csv"
# Here's the end of the things you can modify.
#-------------------------------------------------------------
# Connect to Azure Active Directory via Powershell
Connect-MsolService
$Customers = Get-MsolPartnerContract -All
$CompanyInfo = Get-MsolCompanyInformation
Write-Host "Found $($Customers.Count) customers for $($CompanyInfo.DisplayName)"
Write-Host " "
Write-Host "----------------------------------------------------------"
Write-Host " "
foreach ($Customer in $Customers) {
Write-Host $Customer.Name.ToUpper()
Write-Host " "
# Get license report
Write-Host "Getting license report:"
$CustomerLicenses = Get-MsolAccountSku -TenantId $Customer.TenantId
foreach ($CustomerLicense in $CustomerLicenses) {
Write-Host "$($Customer.Name) is reporting $($CustomerLicense.SkuPartNumber) with $($CustomerLicense.ActiveUnits) Active Units. They've assigned $($CustomerLicense.ConsumedUnits) of them."
}
if ($CustomerLicenses.Count -gt 0) {
Write-Host " "
# Get the initial domain for the customer.
$InitialDomain = Get-MsolDomain -TenantId $Customer.TenantId | Where-Object { $_.IsInitial -eq $true }
Write-Host "Getting UAL setting for $($InitialDomain.Name)"
# Invoke-Command establishes a Windows PowerShell session based on the URL,
# runs the command, and closes the Windows PowerShell session.
Connect-ExchangeOnline -DelegatedOrganization $Customer.TenantId -UserPrincipalName $UserName -ShowBanner:$false -CommandName:"Get-AdminAuditLogConfig"
$AuditLogConfig = Get-AdminAuditLogConfig
Disconnect-ExchangeOnline -Confirm:$false
Write-Host " "
Write-Host "Audit Log Ingestion Enabled:"
Write-Host $AuditLogConfig.UnifiedAuditLogIngestionEnabled
# Check whether the Unified Audit Log is already enabled and log status in a CSV.
if ($AuditLogConfig.UnifiedAuditLogIngestionEnabled) {
$UALCustomerExport = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.Name
DefaultDomainName = $Customer.DefaultDomainName
UnifiedAuditLogIngestionEnabled = $AuditLogConfig.UnifiedAuditLogIngestionEnabled
UnifiedAuditLogFirstOptInDate = $AuditLogConfig.UnifiedAuditLogFirstOptInDate
DistinguishedName = $AuditLogConfig.DistinguishedName
}
$UALCustomersexport = @()
$UALCustomersExport += New-Object psobject -Property $UALCustomerExport
$UALCustomersExport | Select-Object TenantId, CompanyName, DefaultDomainName, UnifiedAuditLogIngestionEnabled, UnifiedAuditLogFirstOptInDate, DistinguishedName | Export-Csv -notypeinformation -Path $UALCustomersCSV -Append
}
# If the Unified Audit Log isn't enabled, log the status and create the admin user.
if (!$AuditLogConfig.UnifiedAuditLogIngestionEnabled) {
$UALDisabledCustomers += $Customer
$UALCustomersExport = @()
$UALCustomerExport = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.Name
DefaultDomainName = $Customer.DefaultDomainName
UnifiedAuditLogIngestionEnabled = $AuditLogConfig.UnifiedAuditLogIngestionEnabled
UnifiedAuditLogFirstOptInDate = $AuditLogConfig.UnifiedAuditLogFirstOptInDate
DistinguishedName = $AuditLogConfig.DistinguishedName
}
$UALCustomersExport += New-Object psobject -Property $UALCustomerExport
$UALCustomersExport | Select-Object TenantId, CompanyName, DefaultDomainName, UnifiedAuditLogIngestionEnabled, UnifiedAuditLogFirstOptInDate, DistinguishedName | Export-Csv -notypeinformation -Path $UALCustomersCSV -Append
# Build the User Principal Name for the new admin user
$NewAdminUPN = -join ($NewAdminUserPrefix, "@", $($InitialDomain.Name))
Write-Host " "
Write-Host "Audit Log isn't enabled for $($Customer.Name). Creating a user with UPN: $NewAdminUPN, assigning user to Company Administrators role."
Write-Host "Adding $($Customer.Name) to CSV to enable UAL in second script."
New-MsolUser -TenantId $Customer.TenantId -DisplayName "Audit Admin" -UserPrincipalName $NewAdminUPN -Password $NewAdminPassword -ForceChangePassword $false
Add-MsolRoleMember -TenantId $Customer.TenantId -RoleName "Company Administrator" -RoleMemberEmailAddress $NewAdminUPN
$AdminProperties = @{
TenantId = $Customer.TenantId
CompanyName = $Customer.Name
DefaultDomainName = $Customer.DefaultDomainName
UserPrincipalName = $NewAdminUPN
Action = "ADDED"
}
$CreatedAdmins = @()
$CreatedAdmins += New-Object psobject -Property $AdminProperties
$CreatedAdmins | Select-Object TenantId, CompanyName, DefaultDomainName, UserPrincipalName, Action | Export-Csv -notypeinformation -Path $CreatedAdminsCsv -Append
Write-Host " "
}
}
Write-Host " "
Write-Host "----------------------------------------------------------"
Write-Host " "
}
Write-Host "Admin Creation Completed for tenants without Unified Audit Logging, please wait 12 hours before running the second script."
Write-Host " "
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment