Finding all domains used to sync OneDrive

By Robert Dyjas 4 months ago • Edit this post

If you're going to restrict syncing OneDrive for Business libraries to specific domains only, you might want to first check, which domains are currently being used to synchronize data.

This is most useful if your environment consist of many different domains and/or forests. To get such data we'll be using audit log functionality in Microsoft 365 Compliance Center.

Table of Contents

Prerequisites

Auditing turned on

If you're not sure if it's already turned on, go to Audit page in M365 Compliance Center and check if you have the option to start recording activity:

2020 11 17 21 25 11

If the button is available and the search is greyed out, you need to turn the audit log on first.

Exchange Online PowerShell module installed

See the article about Exchange Online module for more details about installation and connecting to your environment.

Proper role

View-Only Audit Logs or Audit Logs role in Exchange Online is required (source).

If your account has Global Admin (in Microsoft 365) or Organization Management (in Exchange Online), that should be enough. In the environment, where access is limited, check if the role assigned to your account has the correct permission level.

In legacy admin center:

2020 11 17 21 42 55

Or in the new one:

2020 11 17 21 43 36 window

Getting data from GUI

If you want to get the data once, you can go to audit log and search for Allowed computer to sync files event:

2020 11 17 21 57 07 window

From this level you you find machine's domain data by choosing More information:

2020 11 17 21 59 33 window

And finding MachineDomainInfo there:

2020 11 17 22 03 27 window

You can also export the results to .csv file. Unfortunately, it only exports basic details, without any option to include what we saw under More information.

Getting data programatically

Using Exchange Online PowerShell module you can get data on scheduled basis. You can also format your data in whatever way you prefer, so it seems pretty neat to explore that option.

Before we start, let's define some basic variables:

# Paths
$userDataFilePath = Join-Path $logFolder 'SyncEvents.xlsx'

# Cloud service account
$cloudServiceAccount = 'ServiceAccount@tenant.onmicrosoft.com'
$cloudSvcAccCredsPath = Join-Path 'C:\Scripts\Src\' "$cloudServiceAccount-creds.xml"
$cloudSvcAccCreds = Import-Clixml $cloudSvcAccCredsPath

# Set logging level
$VerbosePreference = 'Continue'

# Set how long to check in the past
$checkUntil = (Get-Date).AddDays(-1)

# Initialize
$allToBeBlocked = @()
$end = (Get-Date)

# Domains to be excluded from the report
$domainGUIDArray = @(
  '11111111-aaaa-2222-3333-444444444444',
  'bbbbbbbb-bc25-4436-dddd-eeeeeeeeeeee'
  )

Then let's connect to Exchange Online and get some data:

Connect-ExchangeOnline -Credential $cloudSvcAccCreds

while ($end -gt $checkUntil) {
  try {
    # Generate session ID
    $sessID = "OneDriveSyncCheck-$(Get-Random)"
    $start = $end.AddHours(-1)
    Write-Verbose "Checking entries to $end"  
    $res = $null
    $params = @{
      Operations = 'ManagedSyncClientAllowed'
      StartDate = $start
      EndDate = $end
      ResultSize = 5000
      SessionCommand = 'ReturnNextPreviewPage'
      SessionID = $sessID
      ErrorAction = 'Stop'
    }
    $res = Search-UnifiedAuditLog @params
    Write-Verbose "Found $($res.count) entries"
    $wouldBeBlocked = $res | Where-Object {
      ($_.AuditData | ConvertFrom-Json).MachineDomainInfo -notin $domainGUIDArray
    }
    $allToBeBlocked += $wouldBeBlocked | Sort-Object userids -unique | Select-Object -Property UserIds, @{n="UserAgent";e={($_.AuditData | ConvertFrom-Json).UserAgent}}, CreationDate
    $mostRecentEntry = $res.CreationDate | Sort-Object | Select-Object -First 1
    Write-Verbose "End date set to $mostRecentEntry"
    $end = $mostRecentEntry
  } catch {
    # In case any errors, always worth reconnecting
    Connect-ExchangeOnline -Credential $cloudSvcAccCreds
    Write-Error $_
  }
} # end of loop

Code deep dive

# Paths
$userDataFilePath = Join-Path $logFolder 'SyncEvents.xlsx'

# Cloud service account
$cloudServiceAccount = 'ServiceAccount@tenant.onmicrosoft.com'
$cloudSvcAccCredsPath = Join-Path 'C:\Scripts\Src\' "$cloudServiceAccount-creds.xml"
$cloudSvcAccCreds = Import-Clixml $cloudSvcAccCredsPath

# Set logging level
$VerbosePreference = 'Continue'

We only define basic variables here, nothing special. Next, let's define time range to be checked for events. Make sure to check how long it takes to get all the data, it might depend on your tenant size:

# Set how long to check in the past
$checkUntil = (Get-Date).AddDays(-1)

# Initialize
$allToBeBlocked = @()
$end = (Get-Date)

Next, we can define an array of domains we'd like to exclude from the report. If you don't exclude anything, your list might be pretty big soon:

# Domains to be excluded from the report
$domainGUIDArray = @(
  '11111111-aaaa-2222-3333-444444444444',
  'bbbbbbbb-bc25-4436-dddd-eeeeeeeeeeee'
  )

Then we need to connect to Exchange Online. Make sure that the sign-in method you use is suitable for unattended run. You can have a look at App-only authentication:

Connect-ExchangeOnline -Credential $cloudSvcAccCreds

And now we start our processing. We want our loop to end once it reaches certain timestamp and we wrap all the processing in try catch block for error handling:

while ($end -gt $checkUntil) {
  try {

Then we generate session ID to be used while sending all the requests. See Parameters of Search-UnifiedAuditLog for details.

For SessionCommand we set ReturnNextPreviewPage value, to get sorted data.

ResultSize is set to 5000, which is maximum value.

We also need to specify ErrorAction = 'Stop' so that we can use try/catch block.

    # Generate session ID
    $sessID = "OneDriveSyncCheck-$(Get-Random)"
    $start = $end.AddHours(-1)
    Write-Verbose "Checking entries to $end"  
    $res = $null
    $params = @{
      Operations = 'ManagedSyncClientAllowed'
      StartDate = $start
      EndDate = $end
      ResultSize = 5000
      SessionCommand = 'ReturnNextPreviewPage'
      SessionID = $sessID
      ErrorAction = 'Stop'
    }

Then we use splatting to run our command.

If it runs successfully, we process the data to get desired format.

Once we get data processed, we check for most recent entry and then set it as new end date for next search.

    $res = Search-UnifiedAuditLog @params
    Write-Verbose "Found $($res.count) entries"
    $wouldBeBlocked = $res | Where-Object {
      ($_.AuditData | ConvertFrom-Json).MachineDomainInfo -notin $domainGUIDArray
    }
    $allToBeBlocked += $wouldBeBlocked | Sort-Object userids -unique | Select-Object -Property UserIds, @{n="UserAgent";e={($_.AuditData | ConvertFrom-Json).UserAgent}}, CreationDate
    $mostRecentEntry = $res.CreationDate | Sort-Object | Select-Object -First 1
    Write-Verbose "End date set to $mostRecentEntry"
    $end = $mostRecentEntry
  } catch {

As most of the errors I saw were caused by disconnected session, let's try to reconnect. Worth noting - in case any error, new value for $end won't be set so the previous query will be executed:

    # In case any errors, always worth reconnecting
    Connect-ExchangeOnline -Credential $cloudSvcAccCreds
    Write-Error $_
  }
} # end of loop