When employees leave an organization, their OneDrive data often needs to be temporarily accessible to colleagues or managers for transition purposes. The traditional approach of adding additional owners to OneDrive accounts creates hidden costs and compliance risks that many IT administrators overlook.

This article demonstrates a PowerShell-based custom action that provides temporary access through time-limited sharing instead of permanent ownership assignment, preventing unlicensed storage accounts and reducing organizational costs.

Manage unlicensed OneDrive user accounts - SharePoint in Microsoft 365 | Microsoft Learn

Understanding the Root Cause

When a user account is disabled or deleted in Microsoft 365, their OneDrive should automatically enter a retention period and then be deleted. However, adding additional owners to OneDrive disrupts this lifecycle, creating unlicensed storage accounts that persist indefinitely.

OneDrive accounts with additional owners don’t get automatically cleaned up when the original user is deleted. These orphaned OneDrives continue consuming storage space without an associated license, creating ongoing costs and compliance risks.

Result: Accumulating storage costs and compliance headaches from OneDrives that should have been deleted months ago.

Instead of permanent ownership, create time-limited shares that expire automatically in 30 days. Steps?

  1. Create Azure AD App Registration
  2. Add required API permissions and grant admin consent
  3. Create client secret and note the values
  4. Update script variables with your App ID, Secret, and Tenant ID

Your Azure AD app needs:

  • Files.ReadWrite.All – To create sharing permissions
  • User.Read.All – To validate user accounts

Install Microsoft Graph PowerShell modules:

Install-Module Microsoft.Graph.Authentication -Force
Install-Module Microsoft.Graph.Users -Force  
Install-Module Microsoft.Graph.Files -Force

Key Commands Explained

Get-MgUserDrive: Retrieves the user’s OneDrive

Get-MgDriveItemChild: Gets files/folders from OneDrive root

Invoke-MgInviteDriveItem: Creates the temporary sharing permission
Links:
Get-MgUserDrive (Microsoft.Graph.Files) | Microsoft Learn
Get-MgDriveItemChild (Microsoft.Graph.Files) | Microsoft Learn
Get-MgInviteDriveItem (Microsoft.Graph.Files) | Microsoft Learn

Working script:

# Azure AD App Configuration
$AppId = "12345678-1234-1234-1234-123456789012"           # Your Azure AD App ID
$ClientSecret = "your-client-secret-value"                 # Your App Secret
$TenantId = "87654321-4321-4321-4321-210987654321"        # Your Tenant ID

# User Configuration
$OriginalUser = "john.smith@yourcompany.com"                     # Departing employee
$NewUser = "manager@yourcompany.com"                           # User who needs access/manager

try {
    # Create credential object
    $SecureSecret = ConvertTo-SecureString $ClientSecret -AsPlainText -Force
    $Credential = New-Object System.Management.Automation.PSCredential($AppId, $SecureSecret)
    
    # Connect to Microsoft Graph
    Connect-MgGraph -TenantId $TenantId -ClientSecretCredential $Credential
    Write-Output "Connected to Microsoft Graph"

    # Get the user's OneDrive
    Write-Output "Getting OneDrive for: $OriginalUser"
    $drive = Get-MgUserDrive -UserId $OriginalUser | Where-Object {$_.Name -eq "OneDrive"}
    if (-not $drive) {
        Write-Error "OneDrive not found for $OriginalUser"
        return
    }
    Write-Output "Found OneDrive: $($drive.Id)"

    # Get all root items
    Write-Output "Getting OneDrive root items..."
    $rootItems = Get-MgDriveItemChild -DriveId $drive.Id -DriveItemId "root"
    if (-not $rootItems) {
        Write-Output "No items found in OneDrive"
        return
    }
    Write-Output "Found $($rootItems.Count) items to share"

    # Set 30-day expiration
    $expirationDate = (Get-Date).AddDays(30).ToString("yyyy-MM-ddTHH:mm:ss.fffZ")
    Write-Output "Setting expiration date: $expirationDate"
    
    $successCount = 0
    $errorCount = 0

    # Share each root item
    foreach ($item in $rootItems) {
        Write-Output "Processing: $($item.Name)"
        
        # Create sharing parameters
        $shareParams = @{
            recipients = @(@{
                email = $NewUser
            })
            roles = @("read")
            requireSignIn = $true
            sendInvitation = $false
            expirationDateTime = $expirationDate
        }
        
        try {
            Invoke-MgInviteDriveItem -DriveId $drive.Id -DriveItemId $item.Id -BodyParameter $shareParams
            $successCount++
            Write-Output "Successfully shared: $($item.Name)"
        }
        catch {
            $errorCount++
            Write-Warning "Failed to share: $($item.Name) - $($_.Exception.Message)"
        }
        
        # Small delay to avoid throttling
        Start-Sleep -Milliseconds 500
    }

    Write-Output ""
    Write-Output "=== SUMMARY ==="
    Write-Output "Original User: $OriginalUser"
    Write-Output "Target User: $NewUser"
    Write-Output "Successfully shared: $successCount items"
    Write-Output "Failed to share: $errorCount items"
    Write-Output "Access expires: $expirationDate"
    Write-Output "==============="
}
catch {
    Write-Error "Script failed: $($_.Exception.Message)"
}
finally {
    # Disconnect from Graph
    if (Get-MgContext) {
        Disconnect-MgGraph
        Write-Output "Disconnected from Microsoft Graph"
    }
}

Understanding the Sharing Parameters


The $shareParams object contains the key configuration for temporary sharing:

$shareParams = @{
    recipients = @(@{
        email = $NewUser                    # Email of user receiving access
    })
    roles = @("read")                       # Permission level: "read" or "write"
    requireSignIn = $true                   # User must authenticate to access
    sendInvitation = $false                 # Don't send email notification
    expirationDateTime = $expirationDate    # When access expires (30 days)
}

Temporary sharing eliminates the unlicensed OneDrive problem while providing necessary business continuity. Access expires automatically, storage stays clean, and you avoid manual cleanup tasks.

The solution uses Azure AD app authentication for reliable enterprise automation.

Why This Approach Works Better?





Additional OwnersTemporary Sharing
Creates unlicensed accountsNo storage impact
Permanent accessAuto-expires in 30 days
Manual cleanup neededFully automated
Compliance risksTime-bounded access

Stop creating orphaned OneDrives. Use time-limited sharing instead.


Leave a Reply

Your email address will not be published. Required fields are marked *