Get-FromGithub.ps1

<#PSScriptInfo
 
.VERSION 1.0.2
 
.GUID 6214b037-c72c-479a-8904-b8e468ee9c72
 
.AUTHOR TomasBouda
 
.DESCRIPTION Helper Script used to fetch files from github private repository
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS
 
.LICENSEURI
 
.PROJECTURI
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
#>


function Get-CustomerConfig{
    <#
    .SYNOPSIS
        This function retrieves the specified configuration value from default or given customer config file.
 
    .DESCRIPTION
        This function retrieves the specified configuration value from default or given customer config file.
 
    .PARAMETER XPath
        Xpath to configuration you want to return
 
    .PARAMETER ConfigFilePath
        Path to customer configuration file.
 
    .EXAMPLE
        PS C:\> Get-CustomerConfig -Xpath "//credential[@name='GithubPAT']"
    #>


    param(
        [Parameter(Mandatory = $true)]
        [string]$XPath,
        [Parameter(Mandatory = $false)]
        [string]$ConfigFilePath = 'C:\inetpub\approot\_Install\_Tools\customer.config'
    )

    begin{ 
        if(-not (Test-Path $ConfigFilePath)){
            $ConfigFilePath = 'C:\inetpub\approot\_Install\_Tools\customer.config'
            New-Item -Path $ConfigFilePath -Force | Out-Null

            $configTemplate = @'
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <credentials>
        <credential name="GithubPAT" value="{0}" />
    </credentials>
</configuration>
'@


            do{ 
                $token = Read-Host 'Enter Github Personal Access Token(PAT)'
                $token = $token.Trim()
            }
            while([string]::IsNullOrEmpty($token) -or $token.Length -lt 10)

            Set-Content -Path $ConfigFilePath -Value ($configTemplate -f $token)
        }
    }
    process{ 
        [xml]$config = Get-Content $ConfigFilePath
        $config | Select-XML -XPath $XPath | Select-Object -ExpandProperty Node | Select-Object -ExpandProperty Value
    }
}

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 = 'master',
        [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" 
        }
    }
    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-FilesFromGithub -User $User -Token $Token -Owner $Owner -Repository $Repository -Path $_.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
                }
            }
        }
    }
}