Skip to content

Instantly share code, notes, and snippets.

@ConnorGriffin
Last active May 27, 2024 08:11
Show Gist options
  • Save ConnorGriffin/dc804357bb10ff7522d0e21ddfdf9398 to your computer and use it in GitHub Desktop.
Save ConnorGriffin/dc804357bb10ff7522d0e21ddfdf9398 to your computer and use it in GitHub Desktop.
GDrive Upload PowerShell Script
# Set the Google Auth parameters. Fill in your RefreshToken, ClientID, and ClientSecret
$params = @{
Uri = 'https://accounts.google.com/o/oauth2/token'
Body = @(
"refresh_token=$RefreshToken", # Replace $RefreshToken with your refresh token
"client_id=$ClientID", # Replace $ClientID with your client ID
"client_secret=$ClientSecret", # Replace $ClientSecret with your client secret
"grant_type=refresh_token"
) -join '&'
Method = 'Post'
ContentType = 'application/x-www-form-urlencoded'
}
$accessToken = (Invoke-RestMethod @params).access_token
# Change this to the file you want to upload
$SourceFile = 'C:\Path\To\File'
# Get the source file contents and details, encode in base64
$sourceItem = Get-Item $sourceFile
$sourceBase64 = [Convert]::ToBase64String([IO.File]::ReadAllBytes($sourceItem.FullName))
$sourceMime = [System.Web.MimeMapping]::GetMimeMapping($sourceItem.FullName)
# If uploading to a Team Drive, set this to 'true'
$supportsTeamDrives = 'false'
# Set the file metadata
$uploadMetadata = @{
originalFilename = $sourceItem.Name
name = $sourceItem.Name
description = $sourceItem.VersionInfo.FileDescription
#parents = @('teamDriveid or folderId') # Include to upload to a specific folder
#teamDriveId = ‘teamDriveId’ # Include to upload to a specific teamdrive
}
# Set the upload body
$uploadBody = @"
--boundary
Content-Type: application/json; charset=UTF-8
$($uploadMetadata | ConvertTo-Json)
--boundary
Content-Transfer-Encoding: base64
Content-Type: $sourceMime
$sourceBase64
--boundary--
"@
# Set the upload headers
$uploadHeaders = @{
"Authorization" = "Bearer $accessToken"
"Content-Type" = 'multipart/related; boundary=boundary'
"Content-Length" = $uploadBody.Length
}
# Perform the upload
$response = Invoke-RestMethod -Uri "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&supportsTeamDrives=$supportsTeamDrives" -Method Post -Headers $uploadHeaders -Body $uploadBody
@fabianbramptc
Copy link

Hello, I am wondering if you have any solution to overwrite existing files uploaded based on the file name. Thank you very much!

@ConnorGriffin
Copy link
Author

ConnorGriffin commented Mar 22, 2022

Hello, I am wondering if you have any solution to overwrite existing files uploaded based on the file name. Thank you very much!

You can check if your target file exists already, and delete it before uploading. Alternatively you can use the Patch method during upload to have Google Drive upload your file as a a new version of an existing file. You have to get the ID first, and it doesn't support the 'parents' parameter. Here's an excerpt from another piece of code where I have a -ConflictMode param that accepts Ignore, Overwrite, or Version as valid options.

# Check if the file exists already in Google Drive 
if ($ConflictMode -ne 'Ignore') {
    $newParams = $params
    $newParams += "q=trashed%3Dfalse and parents+in+'$parentId'"
    $r = Invoke-RestMethod -Uri "$baseUri/files?$($newParams -join '&')" -Method Get
    $targetFile = ($r.files | Where-Object {$_.name -eq $uploadMetadata['name']})

    if ($targetFile) {
        # If the file exists already, upload different based on conflict mode
        if ($ConflictMode -eq 'Version') {
            # Remove parents if uploading a version (parameter not supported) and set the upload parameters 
            $uploadMetadata.Remove('parents')
            $fileUploadUri = "$uploadUri/files/$($targetFile[0].id)?supportsAllDrives=$supportsAllDrives&uploadType=multipart"
            $fileUploadMethod = 'Patch'
        } elseif ($ConflictMode -eq 'Overwrite') {
            # Remove the existing file and specify that a normal upload should be performed 
            $r = Invoke-RestMethod -Uri "$baseUri/files/$($targetFile[0].id)?supportsAllDrives=$supportsAllDrives" -Method Delete
            $ConflictMode = 'Ignore'
        }
    } else {
        # Specify that a normal upload should be performed
        $ConflictMode = 'Ignore'
    }
}

# Using another If because I am changing ConflictMode in the above if block
if ($ConflictMode -eq 'Ignore') {
    # Set the upload parameters if ConflictMode is set to Ignore
    $fileUploadUri = "$uploadUri/files?supportsAllDrives=$supportsAllDrives&uploadType=multipart"
    $fileUploadMethod = 'Post'
} 

@fabianbramptc
Copy link

Thank you very much!

@Adipat99
Copy link

Adipat99 commented Aug 8, 2022

Hello Connor Griffin, I tried to upload multiple csv files but cannot, any help, thank you in-advance

@ConnorGriffin
Copy link
Author

Hello Connor Griffin, I tried to upload multiple csv files but cannot, any help, thank you in-advance

@Adipat99 You should be able to wrap this whole thing in a function, setting $SourceFile as a parameter, and then call it multiple times (via a loop, etc.) to upload multiple files.

@nnchandru
Copy link

I tried with powershell 3.0.. I get the below error
unable to cast object of type 'system.int32' to type 'system.string'
Any modification required?

@ConnorGriffin
Copy link
Author

@nnchandru I'm not sure, I tried the example code as-is with PowerShell 3.0 and it ran successfully. Can you post the error message and the context?

@nnchandru
Copy link

nnchandru commented Sep 11, 2022

I was able to fix the error after updating the powershell version to 5.0..

@Niksin9
Copy link

Niksin9 commented Aug 1, 2023

@ConnorGriffin I am getting this below error: -
invoke-restmethod:the underlying connection was closed:an unexpected error occured on send
Any idea what I am doing wrong here?

@ConnorGriffin
Copy link
Author

@Niksin9 You may need to force PowerShell to use TLS 1.2.

Try running this at the start:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

@Niksin9
Copy link

Niksin9 commented Aug 7, 2023

@ConnorGriffin
I tried running this at the start but no luck:
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

Still getting the same error.
Do I need to install the newer version of DOTNET? Currently my DOTNET version is 4.0

@Pheggas
Copy link

Pheggas commented Sep 3, 2023

Hey. I've got issues while uploading filenames like Korn - Live At Big Day Out 1999 (Full Show) 720p 50fps Remaster [e_PYpc4KT6k].webm

Is there a quick fix for such filenames?
PS: It uploads filenames like test.txt with no issues at all

@ConnorGriffin
Copy link
Author

ConnorGriffin commented Sep 3, 2023

@Pheggas Could you post an error maybe? I am guessing it has something to do with needing to escape some characters in $sourceItem.Name, but I'm not setup to test right now.

@Pheggas
Copy link

Pheggas commented Sep 3, 2023

@ConnorGriffin Thank you for quick response. In any way, i fixed it by specifying -LiteralPath in Get-Item command so it wouldn't grap square brackets in filename as wildcard.

@Pheggas
Copy link

Pheggas commented Sep 4, 2023

Hey, it's me again. I'm currently having issues with uploading files to folders that are shared with me, instead of folders that i own. In my drive, it is okay and upload is successful but as soon as i want to upload to folder that is shared with me, it throws 404, file not found:

Invoke-RestMethod : {
  "error": {
    "code": 404,
    "message": "File not found: 13To6qyCukFwe0G9[redacted]KG9Fn.",
    "errors": [
      {
        "message": "File not found: 13To6qyCukFwe0G9[redacted]KG9Fn.",
        "domain": "global",
        "reason": "notFound",
        "location": "fileId",
        "locationType": "parameter"
      }
    ]
  }
}
At C:\Users\Pheggas\Desktop\yt-dlp\test.ps1:58 char:13
+ $response = Invoke-RestMethod -Uri "https://www.googleapis.com/upload ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

@ConnorGriffin
Copy link
Author

ConnorGriffin commented Sep 4, 2023

@Pheggas I can't really say what's going on. If you provided the parentId in the upload metadata, and you have rights to upload to that folder, then I'm not sure.

I wrapped up some of the code from this Gist in to a module, you can poke around the code in there and see if anything is different. I still use this in some stuff occasionally, but I haven't looked at the code in long time. https://github.com/ConnorGriffin/PS-GDrive/blob/master/PS-GDrive/Public/New-GDriveItem.ps1

$uploadMetadata = @{
    originalFilename = $sourceItem.Name
    parents = @($parentId)
    description = $sourceItem.VersionInfo.FileDescription
    useContentAsIndexableText = $UseContentAsIndexableText
}

@1e0nn
Copy link

1e0nn commented Sep 14, 2023

Hey, it's me again. I'm currently having issues with uploading files to folders that are shared with me, instead of folders that i own. In my drive, it is okay and upload is successful but as soon as i want to upload to folder that is shared with me, it throws 404, file not found:

Invoke-RestMethod : {
  "error": {
    "code": 404,
    "message": "File not found: 13To6qyCukFwe0G9[redacted]KG9Fn.",
    "errors": [
      {
        "message": "File not found: 13To6qyCukFwe0G9[redacted]KG9Fn.",
        "domain": "global",
        "reason": "notFound",
        "location": "fileId",
        "locationType": "parameter"
      }
    ]
  }
}
At C:\Users\Pheggas\Desktop\yt-dlp\test.ps1:58 char:13
+ $response = Invoke-RestMethod -Uri "https://www.googleapis.com/upload ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-RestMethod], WebExc
   eption
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeRestMethodCommand

Hello, i noticed the same thing. When you are in your shared folder, you need to take the ID in the end of the URL https://drive.google.com/drive/folders/1GeOflixv5rTkMUnwMmcD and paste it here:

$uploadMetadata = @{
originalFilename = $sourceItem.Name
name = $sourceItem.Name
description = $sourceItem.VersionInfo.FileDescription
parents = @(1GeOflixv5rTkMUnwMmcD) #the id which is in the end of the url
}

@danmer8888
Copy link

Hello,
Faced the problem uploading large file >2g

The error information returned by PowerShell is: 'Exception calling "ToBase64String" with "1" argument(s): "Exception of type 'System.OutOfMemoryException' was thrown
as i understand problem caused by using 'ReadAllBytes'

Thanks a lot)
with small files this code works well

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment