PrivateFunctions/Upload-LargeFileToSharePointOnline.ps1

<#
.SYNOPSIS
    This function uploads a file larger than 4MB, but smaller than 60MB, in size to SharePoint Online.
.DESCRIPTION
    This function uploads a file larger than 4MB, but smaller than 60MB, in size to SharePoint Online.
    It makes use of the OneDrive "Upload large files" REST endpoint:
    https://docs.microsoft.com/en-us/OneDrive/developer/rest-api/api/driveitem_createuploadsession?view=odsp-graph-online
#>

function Upload-LargeFileToSharePointOnline {
    [CmdletBinding(PositionalBinding=$false)]
    [OutputType([Bool])]
    param (
        # The path to the file on the local machine.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$filePath,

        # The path of the destination file in SharePoint Online.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$destinationFilePath,

        # The User Principal Name of the user whose SharePoint Online account will receive the file.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$siteUrl,

        # The Microsoft Graph authentication token.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$token,

        # Select the stream where the messages will be directed.
        [Parameter(Mandatory=$false)]
        [ValidateSet("Information", "Warning", "Error")]
        [String]$outputStream = "Error"
    )

    # Verify that the file exists on the local machine
    if (!(Test-Path -Path $filePath -ErrorAction SilentlyContinue)) {
        Write-OutputMessage "The file '$($filePath)' on the local machine cannot be found." -OutputStream $outputStream -ReturnMessage:$false
        return $false
    }

    # Remove any "\" or "/" at the start of the SharePoint Online destination path
    if ($destinationFilePath.StartsWith("\")) {
        $destinationFilePath = $destinationFilePath.TrimStart("\")
    }
    if ($destinationFilePath.StartsWith("/")) {
        $destinationFilePath = $destinationFilePath.TrimStart("/")
    }

    # Verify that the siteUrl is valid
    if (!(Test-DomainValidity -Domain $siteUrl)) {
        Write-OutputMessage "The siteUrl '$($siteUrl)' is not valid." -OutputStream $outputStream -ReturnMessage:$false
        return $false
    }

    # Construct a POST request to get the upload url
    Write-Information "Retrieving the large file upload URL."
    try {
        $invokeRestMethodParams = @{
            Uri     = "https://graph.microsoft.com/v1.0/sites/$($siteUrl)/drive/root:/$($destinationFilePath):/createUploadSession"
            Method  = "POST"
            Headers = @{
                Accept         = "application/json"
                "Content-Type" = "text/plain"
                Authorization  = "bearer $($token)"
            }
        }
        $response = Invoke-RestMethod @invokeRestMethodParams
        if (!$response -or [String]::IsNullOrWhiteSpace($response.uploadUrl)) {
            Write-OutputMessage "Failed to get the link to upload the file '$($filePath)' to SharePoint Online." -OutputStream $outputStream -ReturnMessage:$false
            return $false
        }
    }
    catch {
        Write-OutputMessage "Exception occurred while getting the link to upload the file '$($filePath)' to SharePoint Online.`r`n$($_.Exception.Message)" -OutputStream $outputStream -ReturnMessage:$false
        return $false
    }

    # Get the upload url
    $uploadUrl = $response.uploadUrl

    # Convert the file into ascii code and get the file size in bytes
    $fileInBytes = [System.IO.File]::ReadAllBytes($filePath)
    $fileInAscii = [System.Text.Encoding]::ASCII.GetString($fileInBytes)
    $fileLength = $fileInAscii.Length

    # Upload the file to SharePoint Online
    Write-Information "Uploading the file '$($filePath)' to SharePoint Online."
    try {
        $invokeRestMethodParams = @{
            Uri     = $uploadUrl
            Method  = "PUT"
            Headers = @{
                Accept           = "application/json"
                "Content-Type"   = "text/plain"
                Authorization    = "bearer $($token)"
                "Content-Length" = $fileLength
                "Content-Range"  =  "bytes 0-$($fileLength-1)/$($fileLength)"
            }
            Body = $fileInAscii
        }
        $response = Invoke-RestMethod @invokeRestMethodParams
        if (!$response -or [String]::IsNullOrWhiteSpace($response.id)) {
            Write-OutputMessage "Failed to upload the file '$($filePath)' to SharePoint Online." -OutputStream $outputStream -ReturnMessage:$false
            return $false
        }
    }
    catch{
        Write-OutputMessage "Exception occurred while uploading the file '$($filePath)' to SharePoint Online.`r`n$($_.Exception.Message)" -OutputStream $outputStream -ReturnMessage:$false
        return $false
    }

    # Successfully uploaded the file
    return $true
}