# Upload all files from Datto local copy to SharePoint via Graph API # This script runs ON the ACG-DWP-X-BB VM and uploads directly param( [string]$SourcePath = "C:\Users\Public\Desktop\Datto Workplace Server Projects\Quality Department", [string]$TenantId = "19a568e8-9e88-413b-9341-cbc224b39145", [string]$ClientId = "709e6eed-0711-4875-9c44-2d3518c47063", [string]$ClientSecret = "", # Will be passed via command line [string]$SiteUrl = "https://birthbiologic.sharepoint.com/sites/QualitySystemsDepartment", [string]$DriveId = "b!F8BzMb1YakCIWCyWlmczb09LHqtxDxVMpLT6kAwYmsM7NUY4oPLSRq7ng3tJq-E9" ) $ErrorActionPreference = 'Stop' Write-Host "===================================================================" Write-Host " Upload ALL Files from Datto to SharePoint via Graph API" Write-Host "===================================================================" Write-Host "" Write-Host "Source: $SourcePath" Write-Host "Target: $SiteUrl/Documents" Write-Host "" # Get access token Write-Host "Getting Graph API token..." $tokenBody = @{ client_id = $ClientId client_secret = $ClientSecret scope = "https://graph.microsoft.com/.default" grant_type = "client_credentials" } $tokenResponse = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$TenantId/oauth2/v2.0/token" -Body $tokenBody $token = $tokenResponse.access_token Write-Host "[OK] Token acquired" Write-Host "" # Get all files from source Write-Host "Scanning source files..." $files = Get-ChildItem $SourcePath -Recurse -File -ErrorAction SilentlyContinue Write-Host "[OK] Found $($files.Count) files to upload" Write-Host "" # Upload each file $uploaded = 0 $errors = @() foreach ($file in $files) { $relativePath = $file.FullName.Substring($SourcePath.Length + 1) $uploadPath = $relativePath.Replace('\', '/') try { # For files < 4MB, use simple upload if ($file.Length -lt 4MB) { $uploadUrl = "https://graph.microsoft.com/v1.0/drives/$DriveId/root:/$uploadPath`:/content" $headers = @{ "Authorization" = "Bearer $token" "Content-Type" = "application/octet-stream" } $fileBytes = [System.IO.File]::ReadAllBytes($file.FullName) Invoke-RestMethod -Method Put -Uri $uploadUrl -Headers $headers -Body $fileBytes | Out-Null } else { # For large files, use upload session (simplified - just do small files for now) Write-Host " SKIP (>4MB): $uploadPath" continue } $uploaded++ if ($uploaded % 100 == 0) { Write-Host " Uploaded $uploaded / $($files.Count) files..." } } catch { $errors += [PSCustomObject]@{ File = $relativePath Error = $_.Exception.Message } Write-Host " ERROR: $relativePath - $($_.Exception.Message)" } } Write-Host "" Write-Host "===================================================================" Write-Host " Upload Complete" Write-Host "===================================================================" Write-Host "" Write-Host "Uploaded: $uploaded / $($files.Count) files" Write-Host "Errors: $($errors.Count)" Write-Host "" if ($errors.Count -gt 0) { Write-Host "First 10 errors:" $errors | Select-Object -First 10 | ForEach-Object { Write-Host " $($_.File): $($_.Error)" } }