How to speed up Microsoft Graph Using the PowerShell SDK script

1.1k Views Asked by At

How would I speed up the processing of my PowerShell script?

At the moment it takes about 1-2 hours to run 1K+ uses records, really need to speed it up.

  # Must be run in Powershell 5.1 or else you can't get account creation date
    # Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

    $maximumfunctioncount = 8192

    Install-Module Microsoft.Graph -Scope CurrentUser -Force -AllowClobber

    Connect-MgGraph -Scopes "Directory.Read.All","User.Read.All","AuditLog.Read.All"

    Select-MgProfile -Name "Beta"

    # Add a line from the variable name onwards to uncomment the license SKU

    $LicenseSku = 'ENTERPRISEPACK'
   

    # Use this to check for the license SKU

    # Get-MgSubscribedSku -All -Select SkuPartNumber, SkuId, SkuPartNumber, ConsumedUnits | Format-List

 

    # Get the assigned users details & exports as a CSV file

    $licenseDetails = Get-MgSubscribedSku -All | Where SkuPartNumber -eq $LicenseSku

    Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($licenseDetails.SkuId) )" -ConsistencyLevel eventual -All | Export-Csv -Path "C:\temp\LiceneUsers.csv"

 

    # Imports the above CSV file

    $UserCSVExtract = Import-Csv -Path "C:\temp\LiceneUsers.csv"

 

    # This is the final CSV file that is created with the user UPN + last sign-in date + account creation date

    $FinalCSVName = 'c:\temp\License CSV '+$LicenseSku + '.csv'

 

    $Result=@()

    foreach($user in $UserCSVExtract)

    {

        $usersignindate = Get-MgUser -UserId $user.ID -Select SignInActivity | Select -ExpandProperty SignInActivity

       $userprops = [ordered]@{

            UserPrincipalName = $user.UserPrincipalName

            LastSignInDateTime = $usersignindate.LastSignInDateTime

            AccountCreationDate = $user.CreatedDateTime
    }

        $userObj =  new-object -Type PSObject -Property $userprops

        $Result += $userObj | Export-csv -Path $FinalCSVName -Append
    }
    $Result

EDIT2:

#Connect to Microsoft Graph
Connect-MgGraph -scope User.Read.All, AuditLog.read.All

#Select the beta profile
Select-MgProfile -name beta

#Gather all users in tenant
$AllUsers = Get-MgUser -All

#Create a new empty array list object
$Report = [System.Collections.Generic.List[Object]]::new()

Foreach ($user in $AllUsers)
{
    #Null variables
    $SignInActivity = $null
    $Licenses = $null

    #Display progress output
    Write-host "Gathering sign-in information for $($user.DisplayName)" -ForegroundColor Cyan

    #Get current user information
    $SignInActivitiy = Get-MgUser -UserId  $user.id -Property signinactivity | Select-Object -ExpandProperty signinactivity
    $licenses = (Get-MgUserLicenseDetail -UserId $User.id).SkuPartNumber -join ", "

    #Create informational object to add to report
    $obj = [pscustomobject][ordered]@{
            DisplayName              = $user.DisplayName
            UserPrincipalName        = $user.UserPrincipalName
            Licenses                 = $licenses
            LastInteractiveSignIn    = $SignInActivitiy.LastSignInDateTime
            LastNonInteractiveSignin = $SignInActivitiy.LastNonInteractiveSignInDateTime
        }
    
    #Add current user info to report
    $report.Add($obj)
}

$report | Export-CSV -path C:\temp\Microsoft365_User_Activity-Report.csv -NoTypeInformation
2

There are 2 best solutions below

2
Glen Scales On

You don't really need to use the Beta endpoint as signInActivity is in the v1.0 endpoint and also unless you have another need for it export the results of the first Get-MgUser to a CSV isn't required. The slowest part of you script would be the individual Get-MgUser for each user in the CSV that would create one request for every user which isn't need because you can get all the information you after from the first request. (Even if you where going to do this you would want to batch the Get-MgUser).

Eg a condensed version of what you trying to do can be done using a oneliner

Get-MgUser -Filter "assignedLicenses/any(x:x/skuId eq $($licenseDetails.SkuId) )" -ConsistencyLevel eventual -All -Property UserPrincipalName,CreatedDateTime,signInActivity | select UserPrincipalName,CreatedDateTime,@{name="LastSignInDateTime";expression={$_.signInActivity.lastSignInDateTime}} | export-csv -NoTypeInformation "c:\temp\urep.csv"

[edit]

#Connect to Microsoft Graph
Connect-MgGraph -scope User.Read.All, AuditLog.read.All

$skuList = @{}
Get-MgSubscribedSku -All -Select SkuPartNumber, SkuId, SkuPartNumber | ForEach-Object {$skuList.add($_.SkuId,$_.SkuPartNumber)}
#Gather all users in tenant
$AllUsers = Get-MgUser -All -Property DisplayName,UserPrincipalName,SigninActivity,AssignedLicenses

#Create a new empty array list object
$Report = [System.Collections.Generic.List[Object]]::new()

Foreach ($user in $AllUsers)
{
    #Null variables 
    $Licenses = @()

    #Display progress output
    Write-host "Gathering sign-in information for $($user.DisplayName)" -ForegroundColor Cyan

    foreach($license in $user.AssignedLicenses){
        if($skuList.ContainsKey($license.SkuId)){
            $Licenses += $skuList[$license.SkuId]
        }else{
            $Licenses += $license.SkuId
        }
    }   

    #Create informational object to add to report
    $obj = [pscustomobject][ordered]@{
            DisplayName              = $user.DisplayName
            UserPrincipalName        = $user.UserPrincipalName
            Licenses                 = ($Licenses -join ',')
            LastInteractiveSignIn    = $user.SigninActivity.LastSignInDateTime
            LastNonInteractiveSignin = $user.SigninActivity.LastNonInteractiveSignInDateTime
        }
    
    #Add current user info to report
    $report.Add($obj)
}

$report | Export-CSV -path C:\temp\Microsoft365_User_Activity-Report.csv -NoTypeInformation

0
Kavya June On

The code might not work now as MS introduced separate module for beta. You need to install the module separately using Install-Module -Name Microsoft.Graph.Beta