OneDrive Upload script and documentation issue
My powershell script is below. Basically, the script successfully loops through a large file, right until the end, where the final content range fails to upload with an error.
function Start-UploadFolderToOneDrive {
param (
$baseDirectory, # = "C:\Path\To\Local\Folder"
$oneDriveUser, # = "******@example.com.au"
$accessToken # Ensure you pass the correct access token
)
$headers = @{
Authorization = "Bearer $accessToken"
"Content-Type" = "application/json"
}
## Get all subdirectories
$directories = Get-ChildItem -Path $baseDirectory -Recurse -Directory
## Create all the folders on OneDrive first
foreach ($directory in $directories) {
$relativePath = $directory.FullName.Substring($baseDirectory.Length).TrimStart('\').Replace('\', '/')
$createFolderURL = "https://graph.microsoft.com/v1.0/users/$($oneDriveUser)/drive/root:/$($relativePath):/children"
$folderName = $directory.Name
$uploadFolderRequestBody = @{
name = "$folderName"
folder = @{}
"@microsoft.graph.conflictBehavior" = "fail"
} | ConvertTo-Json
Write-Host "URI: $createFolderURL"
Invoke-RestMethod -Headers $headers -Method Post -Body $uploadFolderRequestBody -ContentType "application/json" -Uri $createFolderURL
}
## Upload the files
$files = Get-ChildItem -Path $baseDirectory -Recurse -File
foreach ($file in $files) {
$relativePath = $file.FullName.Substring($baseDirectory.Length).TrimStart('\').Replace('\', '/')
$uploadSessionURL = "https://graph.microsoft.com/v1.0/users/$($oneDriveUser)/drive/root:/$($relativePath):/createUploadSession"
Write-Host "Upload URL: $uploadSessionURL"
$uploadSession = (Invoke-RestMethod -Uri $uploadSessionURL -Headers $headers -Method Post).uploadUrl
Write-Host "Upload Session: $uploadSession"
## Upload files in chunks
$ChunkSize = 62259200 # 60 MB
$fileStream = [System.IO.File]::OpenRead($file.FullName)
$buffer = New-Object -TypeName Byte[] -ArgumentList $ChunkSize
$position = 0
$moreData = $true
while ($moreData) {
$bytesRead = $fileStream.Read($buffer, 0, $buffer.Length)
if ($bytesRead -ne $buffer.Length) {
$moreData = $false
$output = $buffer[0..($bytesRead - 1)]
} else {
$output = $buffer
}
$contentLength = $output.Length
$Header = @{
'Content-Length' = $contentLength
'Content-Range' = "bytes $position-$($position + $output.Length - 1)/$($fileStream.Length)"
}
Write-Host "Uploading bytes $position-$($position + $output.Length - 1) of $($fileStream.Length)"
try {
Invoke-RestMethod -Method Put -Uri $uploadSession -Body $output -Headers $Header
}
catch {
Write-Host "Content Length: $contentLength"
Write-Host "Content Range: bytes $position-$($position + $output.Length - 1)/$($fileStream.Length)"
Write-Error "Failed to upload chunk at position $position : $_"
break
}
$position += $output.Length
}
$fileStream.Close()
}
}
At the last loop of uploading a file that exceeds 60MB in size, I get this error:
Log: Uploading bytes 62259200-99412612 of 99412613
Log: Content Length: 37153413
Log: Content Range: bytes 62259200-99412612/99412613
Error:
Start-UploadFolderToOneDrive : Failed to upload chunk at position 62259200 : Bytes to be written to the stream exceed the Content-Length bytes size specified.
I've checked and the file stream appears to be 37153413, which I think it correct.
Can someone sense check this for me?
Also, there appears to be a potential misprint in the "Completing a file" section of
https://learn.microsoft.com/en-us/graph/api/driveitem-createuploadsession?view=graph-rest-1.0
The example provided is:
PUT https://sn3302.up.1drv.com/up/fe6987415ace7X4e1eF866337
Content-Length: 21
Content-Range: bytes 101-127/128
But I'm wondering if that content length should actually be 27? In any case, the whole article appears to use a confusing combination of byte-size, kilobyte-size and VHD-example size references.
Thanks.