functions/Get/Get-FromGithub.ps1

function Get-FromGithub {
    <#
    .SYNOPSIS
        This function retrieves the specified repository on GitHub to a local directory with authentication.
 
    .DESCRIPTION
        This function retrieves the specified repository on GitHub to a local directory with authentication, being a single file, a complete folder, or the entire repository.
 
    .PARAMETER Owner
        Owner of the repository you want to download from.
 
    .PARAMETER Repository
        The repository name you want to download from.
 
    .PARAMETER FileName
        The path inside the repository you want to download from.
        If empty, the function will iterate the whole repository.
        Alternatively you can specify a single file.
 
    .PARAMETER Destination
        The local folder you want to download the repository to.
 
    .PARAMETER Ref
        The name of the commit/branch/tag. Default: the repository’s default branch (usually master)
 
    .PARAMETER AsZip
        Uses github zipball to download whole repository
 
 
    .EXAMPLE
        PS C:\> Get-FromGithub -Owner "test" -Repository "SomeRepo" -Path YYY/InternalFolder/test.ps1" -Destination "C:/MyDownloadedRepository" -Ref 'feature/test'
    #>


    Param(
        [Parameter(Mandatory = $false)]
        [string]$Owner = 'lineupsystems',
        [Parameter(Mandatory = $true)]
        [string]$Repository,
        [Parameter(Mandatory = $true, ParameterSetName = 'File')]
        [AllowEmptyString()]
        [string]$FileName,
        [Parameter(Mandatory = $true, ParameterSetName = 'ZipFile')]
        [string]$OutFile,
        [Parameter(Mandatory = $false, ParameterSetName = 'File')]
        [Parameter(Mandatory = $false, ParameterSetName = 'ZipFile')]
        [string]$Destination,
        [Parameter(Mandatory = $false)]
        [string]$Ref,
        [Parameter(Mandatory = $false)]
        [switch]$AsZip
    )

    begin { 
        [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

        $baseUri = "https://api.github.com";

        $PAT = Get-CustomerConfig -XPath "//credential[@name='GithubPAT']//@value"

        $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($PAT):x-oauth-basic"))
        $headers = @{ 
            Authorization = "Basic $encodedCreds" 
        }

        # If Ref is not passed then load it from customer config
        if($null -eq $Ref -or $Ref -eq ''){
            $Ref = Get-CustomerConfig -XPath "//branch[@name='defaulBranch']//@value"
            if($null -eq $Ref -or $Ref -eq ''){
                $Ref = 'master'
            }
        }
    }
    process {
        # REST Building
        if ($AsZip) {
            $argsUri = "repos/$Owner/$Repository/zipball/$Ref"

            if ($PSBoundParameters.ContainsKey('OutFile')) {

                if ($PSBoundParameters.ContainsKey('Destination') -and (Test-Path $Destination)) {
                    Invoke-WebRequest -Uri "$baseUri/$argsUri" -Headers $headers -OutFile "$Destination\$OutFile" -ErrorAction Stop
                }
                else { 
                    Invoke-WebRequest -Uri "$baseUri/$argsUri" -Headers $headers -OutFile $OutFile -ErrorAction Stop
                }
            }
            else { 
                Invoke-WebRequest -Uri "$baseUri/$argsUri" -Headers $headers -ErrorAction Stop | Select-Object -Expand Content
            }
        }
        else { 
            $argsUri = "repos/$Owner/$Repository/contents/$($FileName)?ref=$Ref"
            $response = Invoke-WebRequest -Uri ("$baseUri/$argsUri") -Headers $headers -UseBasicParsing

            # Data Handler
            $objects = $response.Content | ConvertFrom-Json
            $files = $objects | Where-Object { $_.type -eq "file" } | Select-Object -exp download_url
            $directories = $objects | Where-Object { $_.type -eq "dir" }
            
            # Iterate Directories
            $directories | ForEach-Object { 
                Get-FromGithub -Owner $Owner -Repository $Repository -FileName $_.path -Destination "$($Destination)/$($_.name)" -Ref:$Ref
            }

            if ($PSBoundParameters.ContainsKey('Destination') -and -not (Test-Path $Destination)) {
                New-Item -Path $Destination -ItemType Directory -ErrorAction Stop
            }

            foreach ($file in $files) {
                if ($PSBoundParameters.ContainsKey('Destination')) {
                    $outputFilename = (Join-Path $Destination (Split-Path $file -Leaf)) -replace '\?.*', ''
                    Invoke-WebRequest -Uri $file -OutFile $outputFilename -ErrorAction Stop    
                }
                else { 
                    Invoke-WebRequest -Uri $file -ErrorAction Stop | Select-Object -Expand Content
                }
            }
        }
    }
}