public/Add-GoogleDriveFile.ps1
|
<#
.SYNOPSIS Uploads a file to Google Drive in a specified folder. .DESCRIPTION Uploads a file to Google Drive, places it in the "Open Live Writer" subfolder, preserves the original filename. .PARAMETER FilePath The local path to the file to upload. .PARAMETER FileName Optional custom name for the file. If not specified, uses the original filename. .PARAMETER Force If specified, will overwrite an existing file with the same name in the target folder. If not specified and the file already exists, it will return the existing file's metadata. .EXAMPLE Add-GoogleDriveFile -FilePath "C:\images\photo.jpg" #> function Add-GoogleDriveFile { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [ValidateScript({ Test-Path -Path $_ -PathType Leaf })] [string]$FilePath, [Parameter()] [string]$FileName, [Parameter()] [string]$TargetFolderName = "PSBlogger", [Parameter()] [switch]$Force ) $sourceItem = Get-Item (Resolve-Path $FilePath) Write-Verbose "Add-GoogleDriveFile: Uploading file: $($sourceItem.FullName) to Google Drive" if (-not $FileName) { $FileName = $sourceItem.Name } # First, find or create the upload folder in Google Drive Write-Verbose "Add-GoogleDriveFile: Verifying target folder: $TargetFolderName" $folder = Get-GoogleDriveItems -ResultType "Folders" -Title $TargetFolderName if (-not $folder) { # Create the folder if it doesn't exist Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' not found. Creating new folder." $folder = Add-GoogleDriveFolder -Name $TargetFolderName } else { # Get the first folder if multiple exist Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' found." $folder = $folder | Select-Object -First 1 } # Determine if the file already exists in the target folder Write-Verbose "Add-GoogleDriveFile: Checking if file '$FileName' already exists in folder '$TargetFolderName'" $existingFile = Get-GoogleDriveItems -ResultType "Files" -Title $FileName -ParentId $folder.id if ($existingFile) { if (-not $Force) { # use existing file return New-GoogleDriveMetadata -id $existingFile.id -name $existingFile.name } # address multiple file issue # todo: evaluate additional meta-data of the file to ensure it's not deleted $existingFile = $existingFile | Select-Object -First 1 } $sourceMime = Get-ImageMimeType -Extension $sourceItem.Extension # Prepare metadata for the file $metadata = @{ name = $FileName parents = @($folder.id) } | ConvertTo-Json -Compress $fileContent = [System.IO.File]::ReadAllBytes($sourceItem.FullName) $fileContentBase64 = [Convert]::ToBase64String($fileContent) # Create multipart body $boundary = "boundary_" + [System.Guid]::NewGuid().ToString() $body = @( # Metadata part "--$boundary" "Content-Type: application/json; charset=UTF-8" "" $metadata "--$boundary" # File content part "Content-Type: $sourceMime" "Content-Transfer-Encoding: base64" "" $fileContentBase64 "--$boundary--" ) -join "`r`n" $additionalHeaders = @{ "Content-Type" = "multipart/related; boundary=$boundary" } try { if ($existingFile) { # If the file exists and Force is specified, update it $uri = "https://www.googleapis.com/upload/drive/v3/files/$($existingFile.id)?uploadType=media" $method = "PATCH" "Add-GoogleDriveFile: $Method $uri" | Write-Verbose $uploadResult = Invoke-GApi -uri $uri -InFile $sourceItem.FullName -method $method -ContentType $sourceMime -Verbose:$false } else { $uri = "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" $method = "POST" "Add-GoogleDriveFile: $Method $uri" | Write-Verbose $uploadResult = Invoke-GApi -uri $uri -body $body -method $method -ContentType "multipart/related; boundary=$boundary" -AdditionalHeaders $additionalHeaders -Verbose:$false } # Return the file information with public URL return New-GoogleDriveMetadata -id $uploadResult.id -name $uploadResult.name } catch { Write-Error "Failed to upload file to Google Drive: $($_.Exception.Message). $($_.ErrorDetails | ConvertTo-Json -Depth 10)" -ErrorAction Stop } } <# .SYNOPSIS Gets the MIME type for common image file extensions. .DESCRIPTION Returns the appropriate MIME type for image files. Falls back to application/octet-stream for unknown types. .PARAMETER Extension The file extension (including the dot). .EXAMPLE Get-ImageMimeType -Extension ".jpg" #> function Get-ImageMimeType { [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Extension ) $mimeTypes = @{ '.jpg' = 'image/jpeg' '.jpeg' = 'image/jpeg' '.png' = 'image/png' '.gif' = 'image/gif' '.bmp' = 'image/bmp' '.webp' = 'image/webp' '.svg' = 'image/svg+xml' '.ico' = 'image/x-icon' '.tiff' = 'image/tiff' '.tif' = 'image/tiff' } $normalizedExtension = $Extension.ToLower() if ($mimeTypes.ContainsKey($normalizedExtension)) { return $mimeTypes[$normalizedExtension] } else { return 'application/octet-stream' } } function New-GoogleDriveMetadata { param( [string]$id, [string]$name ) $publicUrl = "https://lh3.googleusercontent.com/d/$id" return [PSCustomObject]@{ Id = $id Name = $name PublicUrl = $publicUrl DriveUrl = "https://drive.google.com/file/d/$id/view" } } |