sync: auto-sync from GURU-5070 at 2026-06-30 17:21:06
Author: Mike Swanson Machine: GURU-5070 Timestamp: 2026-06-30 17:21:06
This commit is contained in:
12
clients/birth-biologic/scripts/enumerate-datto.ps1
Normal file
12
clients/birth-biologic/scripts/enumerate-datto.ps1
Normal file
@@ -0,0 +1,12 @@
|
||||
$ErrorActionPreference = 'SilentlyContinue'
|
||||
$source = 'C:\Users\Public\Desktop\Datto Workplace Server Projects\Quality Department'
|
||||
$files = Get-ChildItem -LiteralPath $source -Recurse -File
|
||||
$big = @($files | Where-Object { $_.Length -ge 4MB })
|
||||
$bytes = ($files | Measure-Object Length -Sum).Sum
|
||||
$manifest = $files | ForEach-Object { $_.FullName.Substring($source.Length + 1).Replace('\','/') + '|' + $_.Length }
|
||||
$manifest | Out-File -FilePath 'C:\Windows\Temp\quality-manifest.txt' -Encoding UTF8
|
||||
Write-Host "COUNT=$($files.Count)"
|
||||
Write-Host "BIG4MB=$($big.Count)"
|
||||
Write-Host "BYTES=$bytes"
|
||||
Write-Host "MANIFEST_LINES=$($manifest.Count)"
|
||||
Write-Host "MANIFEST_PATH=C:\Windows\Temp\quality-manifest.txt"
|
||||
101
clients/birth-biologic/scripts/upload-quality-final.ps1
Normal file
101
clients/birth-biologic/scripts/upload-quality-final.ps1
Normal file
@@ -0,0 +1,101 @@
|
||||
# Birth Biologic - Quality Systems Department: converge SharePoint to Datto (3768 files)
|
||||
# Idempotent: skips files already present with matching size. Chunked upload sessions for >=4MB.
|
||||
# Long-path safe (\\?\). Refreshes Graph token on long runs. Writes progress to a tailable log.
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$source = 'C:\Users\Public\Desktop\Datto Workplace Server Projects\Quality Department'
|
||||
$driveId = 'b!F8BzMb1YakCIWCyWlmczb09LHqtxDxVMpLT6kAwYmsM7NUY4oPLSRq7ng3tJq-E9'
|
||||
$tenantId = '19a568e8-9e88-413b-9341-cbc224b39145'
|
||||
$clientId = '709e6eed-0711-4875-9c44-2d3518c47063'
|
||||
$clientSecret = 'SECRET_PLACEHOLDER'
|
||||
$logPath = 'C:\Windows\Temp\quality-upload.log'
|
||||
$manifestPath = 'C:\Windows\Temp\quality-manifest.txt'
|
||||
|
||||
"=== upload start ===" | Set-Content -LiteralPath $logPath -Encoding UTF8
|
||||
function Log($m){ $line = (Get-Date -Format 'HH:mm:ss') + ' ' + $m; Write-Host $line; Add-Content -LiteralPath $logPath -Value $line }
|
||||
|
||||
$script:token = $null
|
||||
$script:tokenAt = $null
|
||||
function Get-Token {
|
||||
$body = @{ client_id=$clientId; client_secret=$clientSecret; scope='https://graph.microsoft.com/.default'; grant_type='client_credentials' }
|
||||
$r = Invoke-RestMethod -Method Post -Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" -Body $body
|
||||
$script:token = $r.access_token
|
||||
$script:tokenAt = Get-Date
|
||||
}
|
||||
function Fresh-Token {
|
||||
if ($null -eq $script:token -or ((Get-Date) - $script:tokenAt).TotalMinutes -gt 40) { Get-Token }
|
||||
return $script:token
|
||||
}
|
||||
function Enc($rel){ ($rel.Split('/') | ForEach-Object { [uri]::EscapeDataString($_) }) -join '/' }
|
||||
function Long($p){ if ($p.StartsWith('\\?\')) { $p } else { '\\?\' + $p } }
|
||||
|
||||
Get-Token
|
||||
Log "Token acquired."
|
||||
|
||||
$lines = Get-Content -LiteralPath $manifestPath | Where-Object { $_ -and $_.Contains('|') }
|
||||
$items = foreach($l in $lines){
|
||||
$idx = $l.LastIndexOf('|')
|
||||
[pscustomobject]@{ rel = $l.Substring(0,$idx); size = [int64]$l.Substring($idx+1) }
|
||||
}
|
||||
# small files first so the visible count climbs fast, then the big ones
|
||||
$items = $items | Sort-Object size
|
||||
Log ("Manifest items: " + $items.Count)
|
||||
|
||||
# Internal time budget: exit cleanly before any agent-side cap; re-dispatch resumes (idempotent).
|
||||
$deadline = (Get-Date).AddSeconds(9600)
|
||||
$timedOut = $false
|
||||
|
||||
$uploaded=0; $skipped=0; $errors=0; $bigUp=0; $i=0
|
||||
foreach($it in $items){
|
||||
$i++
|
||||
if ((Get-Date) -gt $deadline){ $timedOut = $true; Log "TIME budget reached at item $i; stopping pass cleanly."; break }
|
||||
$rel = $it.rel; $size = $it.size; $enc = Enc $rel
|
||||
$tok = Fresh-Token
|
||||
$h = @{ Authorization = "Bearer $tok" }
|
||||
|
||||
$exists=$false
|
||||
try {
|
||||
$meta = Invoke-RestMethod -Method Get -Uri "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$enc" -Headers $h
|
||||
if ([int64]$meta.size -eq $size) { $exists=$true }
|
||||
} catch { $exists=$false }
|
||||
if ($exists){ $skipped++; if($i % 250 -eq 0){ Log " $i/$($items.Count) up=$uploaded skip=$skipped err=$errors big=$bigUp" }; continue }
|
||||
|
||||
$full = Long (Join-Path $source ($rel.Replace('/','\')))
|
||||
try {
|
||||
if ($size -lt 4194304){
|
||||
$bytes = [System.IO.File]::ReadAllBytes($full)
|
||||
$hh = @{ Authorization = "Bearer $tok"; 'Content-Type'='application/octet-stream' }
|
||||
Invoke-RestMethod -Method Put -Uri "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$enc`:/content" -Headers $hh -Body $bytes -UseBasicParsing | Out-Null
|
||||
$uploaded++
|
||||
} else {
|
||||
$sessUri = "https://graph.microsoft.com/v1.0/drives/$driveId/root:/$enc`:/createUploadSession"
|
||||
$sessBody = @{ item = @{ '@microsoft.graph.conflictBehavior'='replace' } } | ConvertTo-Json
|
||||
$sess = Invoke-RestMethod -Method Post -Uri $sessUri -Headers @{ Authorization="Bearer $tok"; 'Content-Type'='application/json' } -Body $sessBody
|
||||
$upUrl = $sess.uploadUrl
|
||||
$fs = [System.IO.File]::Open($full,[System.IO.FileMode]::Open,[System.IO.FileAccess]::Read,[System.IO.FileShare]::Read)
|
||||
try {
|
||||
$chunk = 10485760 # 10 MB (multiple of 320 KiB)
|
||||
$buf = New-Object byte[] $chunk
|
||||
$pos = [int64]0
|
||||
while ($pos -lt $size){
|
||||
$read = $fs.Read($buf,0,$chunk)
|
||||
if ($read -le 0){ break }
|
||||
if ($read -eq $chunk){ $payload = $buf } else { $payload = New-Object byte[] $read; [Array]::Copy($buf,$payload,$read) }
|
||||
$end = $pos + $read - 1
|
||||
$ch = @{ 'Content-Range' = "bytes $pos-$end/$size" }
|
||||
Invoke-RestMethod -Method Put -Uri $upUrl -Headers $ch -Body $payload | Out-Null
|
||||
$pos += $read
|
||||
}
|
||||
} finally { $fs.Close() }
|
||||
$uploaded++; $bigUp++
|
||||
Log (" BIG ok " + [math]::Round($size/1MB,1) + "MB: $rel")
|
||||
}
|
||||
} catch {
|
||||
$errors++
|
||||
Log " ERROR: $rel :: $($_.Exception.Message)"
|
||||
}
|
||||
if($i % 100 -eq 0){ Log " $i/$($items.Count) up=$uploaded skip=$skipped err=$errors big=$bigUp" }
|
||||
}
|
||||
$allDone = (-not $timedOut)
|
||||
Log "DONE up=$uploaded skip=$skipped err=$errors big=$bigUp total=$($items.Count) reachedEnd=$allDone"
|
||||
Write-Host "RESULT up=$uploaded skip=$skipped err=$errors big=$bigUp total=$($items.Count) reachedEnd=$allDone"
|
||||
Reference in New Issue
Block a user