We are finally finishing the migration of GitHub Enterprise to TFS. While doing so, we wanted to programmatically make sure we had all of the source code off of our old Github server. Including those that belonged to individual users, including those that had left. Unfortunately Github doesn't make a utility for this. So I set out to do it on my own. Since we are Windows shop and I'm wanting to get my PowerShell skills better, I set out to do it in PowerShell.

The trick was getting the list of repositories from Github. Turns out it's not that hard.

  1. Create a personal access token for an admin of the server, assign all permissions, then make the request to http(s)://<server>/api/v3/repositories?visibility=all.

The tricky part was that this is a paged list and the url to the next page is in a Link header. This may work on regular GitHub, but that wasn't my use-case so I don't know.

Any ways, here's my script that will download all repositories from GitHub Enterprise and put them in the c:\development folder using the layout <ORG/USER>\<REPOSITORY>:

$token = "token <<PAT IN GITHUB>>"
$baseurl = "https://<<SERVER>>/api/v3/"
cls
function getRepos() {
    $link = $baseurl + "repositories?visibility=all"
    $repos = New-Object System.Collections.Generic.List[string]

    while ($link -ne "") {

        $result = Invoke-WebRequest -Headers @{ "Authorization" = $token} -Uri $link
        if ($result.Headers.ContainsKey("Link") -and $result.Headers["Link"].Contains("rel=""next""")) {
            $link = $result.Headers["Link"] | Select-String -Pattern "<(.*?)>"
            $link = $link.Matches[0].Groups[1].Captures[0].Value
        }
        else {
            $link = ""
        }

        write-host "link: $link"

        $jsonRepos = ConvertFrom-Json $result.Content

        foreach ($repo in $jsonRepos){
            write-host $repo.full_name
            $repos.Add($repo.full_name)
        }
    }
    
    return $repos
}

function downloadRepos([System.Collections.Generic.List[string]] $repos) {
    foreach ($repo in $repos) {
        cd \Development\GitHubEnterprise
        $repoParts = $repo.Split("/", 2)
        $org = $repoParts[0]
        $repoName = $repoParts[1]
        if ((Test-Path $org) -eq $false) {
            mkdir $org
        }
        cd $org
        if ((Test-Path $repoName) -eq $true) {
            write-error $repoName already exists!
        }
        else {
            write-host $repo-name
            $gitUrl = "git@<<SERVER>>:$repo.git"
            & git clone "$gitUrl"
        }
    }
}

$repos = getrepos
downloadRepos $repos