O365 Report Script Enhancements

Viewed 11

So, I've created myself a script for generating CSV files from an O365 tenant. It pulls various data sets such as users, groups etc. However when running this script on larger tenants with 10,000+ users it can take some time and I've been made aware I'm using a lot of Disk I/O. Does anyone have any suggestions on how to enhance the speed of this script?

# PS 7.2 Compatible

# Module Installations (required once)
Install-Module MicrosoftTeams
Install-Module ExchangeOnlineManagement
Install-Module Microsoft.Online.SharePoint.PowerShell

# Module Imports (required everytime a new terminal is ran)
Import-Module ExchangeOnlineManagement -UseWindowsPowerShell
Import-Module MicrosoftTeams
Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShell

# Configurable Vars
$tenantName = "M365x51125269"
$OutputFolder = "C:\Users\admin\Documents\Scripts\O365 Reporting\Output"

# Connecting to Services
Connect-MgGraph -Scopes DeviceManagementApps.Read.All, DeviceManagementApps.ReadWrite.All, DeviceManagementManagedDevices.Read.All, DeviceManagementManagedDevices.ReadWrite.All, DeviceManagementServiceConfig.Read.All, DeviceManagementServiceConfig.ReadWrite.All, Directory.Read.All, Directory.ReadWrite.All, User.Read.All, User.ReadBasic.All, User.ReadWrite.All
Connect-ExchangeOnline 
Connect-SPOService -Url https://$tenantName-admin.sharepoint.com

# Generate a list of all users with the given properties in a variable
$users = Get-MgUser -Property 'accountEnabled, userPrincipalName, displayName, givenName, surname, department,id' -All
$OneDriveUsage = Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'"
$MailboxInfo = Get-EXOMailbox

# Iterate through the variable to pull individual details out
foreach ($user in $users) {

    # License 
    $license = Get-MgUserLicenseDetail -UserId $user.Id

    $CurrentOneDrive = $OneDriveUsage| Where-Object{$_.Owner -eq $user.UserPrincipalName}

    $CurrentMailboxInfo = $MailboxInfo | Where-Object{$_.PrimarySmtpAddress -eq $user.UserPrincipalName}
    $sortedArray = ($CurrentMailboxInfo.EmailAddresses | Select-String '(?<=smtp:)\S+(?!=\S)' -AllMatches).Matches.Value
    $stringSMTP = $sortedArray -join ";"
    
    [PSCustomObject]@{
        'Enabled Credentials' = $user.AccountEnabled        
        'Unique ID' = $user.UserPrincipalName
        'Display Name' = $user.DisplayName
        'Assigned Products' = $license.SkuPartNumber -join " ; "
        'First Name' = $user.GivenName
        'Last Name' = $user.Surname
        'Department' = $user.Department
        'Proxy Addresses' = $stringSMTP
        'OneDrive Storage Usage (MB)' = $CurrentOneDrive.StorageUsageCurrent
    } | Export-Csv -path "$OutputFolder\UserInfo.csv" -Append -NoTypeInformation
}   

# Generate list of all sites in a variable
$siteList = Get-SPOSite -Limit ALL
# Iterate through the variable to pull individual details out
foreach($site in $siteList){
    # Checking the value result to determine a connection
    if ($site.IsTeamsConnected){
        $connectionWrite = 'TRUE'
    }
    else{
        $connectionWrite = 'FALSE'
    }
    # Generate a custom object with our desired properties for export
    [PSCustomObject]@{
        'Unique ID' = $site.Url
        'Display Name' = $site.Title
        'Teams Connected' = $connectionWrite
        'Sharepoint Storage (MB)' = $site.StorageUsageCurrent
        'SharePoint Last Activity Date' = $site.LastContentModifiedDate
    } | Export-Csv -path "$OutputFolder\Sites.csv" -Append -NoTypeInformation
}

$teamList = Get-Team

foreach($team in $teamlist){

    $teamInfo = $team
    $teamReport = Import-CSV "$InputFolder\TeamReport.csv"
    $teamDetails = $teamReport | Where-Object{$_."Team Name" -eq $team.DisplayName}

    $Sites = Get-SPOSite | Where-Object{$_.Title -eq $team.DisplayName}


    [PSCustomObject]@{
        'Display Name' = $teamInfo.DisplayName
        'Teams Last Activity Date' = $teamDetails."Last Activity Date"
        'Sharepoint Storage (MB)' = $Sites.StorageUsageCurrent
    } | Export-Csv -path "$OutputFolder\TeamReport.csv" -Append -NoTypeInformation
}

$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
    if ($group.SecurityEnabled -And -not $group.MailEnabled){
        $members = Get-MgGroupMember -GroupId $group.Id
        [PSCustomObject]@{
            'Display Name' = $group.DisplayName
            'Members' = $members.AdditionalProperties.displayName -join ";"
        } | Export-Csv -path "$OutputFolder\SecurityGroups.csv" -Append -NoTypeInformation
    }
    continue
}

$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
    if ($group.GroupTypes -eq 'Unified'){
        $members = Get-MgGroupMember -GroupId $group.Id
        [PSCustomObject]@{
            'Display Name' = $group.DisplayName
            'Members' = $members.AdditionalProperties.displayName -join ";"
        } | Export-Csv -path "$OutputFolder\UnifiedGroups.csv" -Append -NoTypeInformation
    }
    continue
}

$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
    if ( ( ($group.SecurityEnabled) -and ($group.MailEnabled) ) -and ('Unified' -notin $group.GroupTypes) ){
        $members = Get-MgGroupMember -GroupId $group.Id
        [PSCustomObject]@{
            'Display Name' = $group.DisplayName
            'Members' = $members.AdditionalProperties.displayName -join ";"
        } | Export-Csv -path "$OutputFolder\MailEnabledSecurityGroups.csv" -Append -NoTypeInformation
    }
    continue
}

$Groups = Get-MgGroup -Property "Members" -All
foreach($group in $Groups){
    if  ( (($group.MailEnabled) -and (-not $group.SecurityEnabled)) -and ('Unified' -notin $group.GroupTypes))
    {
            $members = Get-MgGroupMember -GroupId $group.Id
            [PSCustomObject]@{
                'Display Name' = $group.DisplayName
                'Members' = $members.AdditionalProperties.displayName -join ";"
            } | Export-Csv -path "$OutputFolder\DistributionGroups.csv" -Append -NoTypeInformation
    }
    continue
}

$sharedmailList = Get-EXOMailbox
$filteredList = $sharedmailList | Where-Object {$_.RecipientTypeDetails -notcontains "UserMailbox" -and "DiscoveryMailbox"} 
foreach($sharedmail in $filteredList){
    if ($sharedmail.RecipientTypeDetails -eq 'DiscoveryMailBox'){
        continue
    }
    else{
        [PSCustomObject]@{
            'Unique ID' = $sharedmail.PrimarySmtpAddress
            'Display Name' = $sharedmail.DisplayName
        } | Export-Csv -path "$OutputFolder\SharedMailbox.csv" -Append -NoTypeInformation
    }
}


# Disconnect from services to avoid error before finalising script
Disconnect-Graph
Disconnect-ExchangeOnline
Disconnect-SPOService

People are welcome to take this for their own use by the way - I've found it useful for migrations when needing to merge multiple tenancies together but needing input from clients on what they wish to keep or exclude.

0 Answers
Related