Free script · PowerShell

OneDrive usage report: owner, storage and last activity

Export every OneDrive in your tenant with its owner, storage used, storage quota and the date content last changed, so you can size a OneDrive migration and spot empty or abandoned accounts before you move them.

PowerShellRead-onlyUpdated
Read-only: makes no changes
Before you run it

What you need

Admin roles

  • SharePoint Administrator

Runs on

  • Windows PowerShell 5.1 on Windows, or PowerShell 7 on Windows with Import-Module -UseWindowsPowerShell
Parameters

Options you can set

ParameterWhat it does
-AdminUrlRequired. Your SharePoint admin URL, for example https://contoso-admin.sharepoint.com.
-OutputPathOptional. Where to save the CSV. Default: OneDriveUsageReport_yyyyMMdd_HHmm.csv in the current folder.
-SkipConnectOptional switch. Use a session you already opened with Connect-SPOService.
How to run it

Step by step

  1. 1

    Step 1

    Install the SharePoint Online Management Shell (see install SharePoint Online Management Shell).

  2. 2

    Step 2

    Save the script as Get-CMOneDriveUsageReport.ps1, for example in C:\Scripts.

  3. 3

    Step 3

    Open Windows PowerShell from the Start menu and run cd C:\Scripts.

  4. 4

    Step 4

    Run .\Get-CMOneDriveUsageReport.ps1 -AdminUrl https://contoso-admin.sharepoint.com and sign in as a SharePoint Administrator.

  5. 5

    Step 5

    Open the CSV the script names at the end. Sort by StorageUsageCurrent to plan migration batches, or by LastContentModifiedDate to find inactive OneDrives.

What you get: A UTF-8 CSV with one row per OneDrive: Url, Owner, Title, StorageUsageCurrent, StorageQuota, LastContentModifiedDate and LockState. Storage values are as Get-SPOSite returns them. For sign-in and file activity per user, also check the OneDrive usage report in the Microsoft 365 admin center.

The script

Get-CMOneDriveUsageReport.ps1

<#
.SYNOPSIS
    Get-CMOneDriveUsageReport.ps1

.DESCRIPTION
    Lists every OneDrive (personal site) in the tenant with owner, storage used,
    storage quota and last content modified date, and exports it to CSV.
    Read-only: it changes nothing in your tenant.

    The site query is the one Microsoft documents for listing OneDrive URLs:
      Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'"

    Provided by cloud-migrations.au as is; test before use.
    Read the script before you run it and try it in a test tenant first.

.NOTES
    Requirements
      - SharePoint Online Management Shell:
          Install-Module -Name Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser
      - SharePoint Administrator role
      - Windows PowerShell 5.1, or PowerShell 7 with:
          Import-Module Microsoft.Online.SharePoint.PowerShell -UseWindowsPowerShell
    Commands used (documented by Microsoft): Connect-SPOService, Get-SPOSite, Disconnect-SPOService

.EXAMPLE
    .\Get-CMOneDriveUsageReport.ps1 -AdminUrl https://contoso-admin.sharepoint.com
#>
[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)][string]$AdminUrl,
    [string]$OutputPath = (Join-Path -Path (Get-Location) -ChildPath ('OneDriveUsageReport_{0}.csv' -f (Get-Date -Format 'yyyyMMdd_HHmm'))),
    [switch]$SkipConnect
)

$ErrorActionPreference = 'Stop'

# 1. Connect
if (-not $SkipConnect) {
    try {
        Write-Host "Connecting to $AdminUrl ..."
        Connect-SPOService -Url $AdminUrl
    }
    catch {
        Write-Error "Could not connect to SharePoint: $($_.Exception.Message)"
        return
    }
}

# 2. List OneDrive sites
try {
    Write-Progress -Activity 'OneDrive usage report' -Status 'Listing OneDrive sites (this can take a while in large tenants)...' -PercentComplete 10
    $sites = @(Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Url -like '-my.sharepoint.com/personal/'")
}
catch {
    Write-Error "Get-SPOSite failed: $($_.Exception.Message)"
    return
}
Write-Host ("Found {0} OneDrive sites." -f $sites.Count)

# 3. Shape the rows
$results = New-Object System.Collections.Generic.List[object]
$i = 0
foreach ($s in $sites) {
    $i++
    if ($i % 50 -eq 0 -or $i -eq $sites.Count) {
        Write-Progress -Activity 'OneDrive usage report' -Status ("Processing {0} of {1}" -f $i, $sites.Count) -PercentComplete (10 + (($i / [math]::Max($sites.Count, 1)) * 90))
    }
    $results.Add([pscustomobject][ordered]@{
        Url                     = $s.Url
        Owner                   = $s.Owner
        Title                   = $s.Title
        StorageUsageCurrent     = $s.StorageUsageCurrent
        StorageQuota            = $s.StorageQuota
        LastContentModifiedDate = $s.LastContentModifiedDate
        LockState               = $s.LockState
    })
}
Write-Progress -Activity 'OneDrive usage report' -Completed

# 4. Export
try {
    $results | Sort-Object -Property StorageUsageCurrent -Descending | Export-Csv -Path $OutputPath -NoTypeInformation -Encoding UTF8
    Write-Host ("Done. {0} OneDrive sites written." -f $results.Count)
    Write-Host "Report saved to: $((Resolve-Path -Path $OutputPath).Path)"
}
catch {
    Write-Error "Could not write the CSV to $OutputPath : $($_.Exception.Message)"
}
finally {
    if (-not $SkipConnect) { Disconnect-SPOService }
}
Sources

Commands documented here

Every command in the script is documented on these vendor pages. Test in a non-production tenant or environment first.