ITnewbie
ITnewbie

Reputation: 520

PowerShell to download Zip file from GitHub API

I would like to write a PowerShell script to download the GitHub repo in ZIP format by following this instruction: https://docs.github.com/en/rest/reference/repos#contents

$Token = 'MyUserName:MyPAT'
$Base64Token = [System.Convert]::ToBase64String([char[]]$Token)

$Headers = @{
    "Authorization" = 'Basic {0}' -f $Base64Token;
    "accept" = "application/vnd.github.v3+json"
    }

$Uri = "https://api.github.com/repos/{owner}/{repo}/zipball"
$r = Invoke-WebRequest -Headers $Headers -Uri $Uri -Method Get | Out-File "D:\MyRepo.zip"

The code did download the zip file but I got this error message when I tried to open the zip file:

D:\MyRepo.zip
The archive is either in unknown format or damaged

I am very new to PowerShell, any help is appreciated!

Upvotes: 3

Views: 2828

Answers (1)

Rich Moss
Rich Moss

Reputation: 2384

You may need to look more closely at download-a-repository-archive-zip instructions. It says the response will have a 302 redirect to the URL for downloading. Invoke-WebRequest will not automatically redirect, but it will provide the response headers.

If you change your last line to be:

$response = Invoke-WebRequest -Headers $Headers -Uri $Uri -Method Get 

you can review the $response object's Headers and issue another Invoke-WebRequest with the same headers and the 302 Uri:

$RedirectedResponse = Invoke-WebRequest -Headers $Headers -Uri $RedirectedURI -Method Get 

$RedirectedResponse.Content will have the encoded file contents that you can decode and write to your local filesystem.

EDIT: I got to a system where I had GitHub access and tested the script. I found that the first response had a byte array with the zip file contents. This functionality is too useful not to share! Here's a script that works to download a repo:

$user = 'bjorkstromm'
$repo = 'depends'
$uri = "https://api.github.com/repos/$user/$repo/zipball/"
if(!$cred){$cred = Get-Credential -Message 'Provide GitHub credentials' -UserName $user}
$headers = @{
  "Authorization" = "Basic " + [convert]::ToBase64String([char[]] ($cred.GetNetworkCredential().UserName + ':' + $cred.GetNetworkCredential().Password)) 
  "Accept" = "application/vnd.github.v3+json"
}
$response = Invoke-WebRequest -Method Get -Headers $headers -Uri $uri
$filename = $response.headers['content-disposition'].Split('=')[1]

Set-Content -Path (join-path "$HOME\Desktop" $filename) -Encoding byte -Value $response.Content 

Upvotes: 4

Related Questions