obj/gitlabconnect.ps1
#requires -Version 5 enum HTTPMethod { Get = 1 Post = 2 Put = 3 Delete = 4 } class GitLabConnect { [string]$hostname [string]$username [securestring]$token <# Contructor with api-token #> GitLabConnect ([string]$hostname,[string]$token) { #region check token $header = @{ 'PRIVATE-TOKEN' = $token } $userurl = "$hostname/api/v3/user" $errorprop = $null $result = $null try { $result = Invoke-RestMethod -Uri $userurl -Headers $header $errorprop = $null } catch [System.Net.WebException] { switch -Wildcard ($_.exception.Message) { '*Could not create SSL/TLS secure channel.*' { $errorprop = @{ message = "could not reach server at $userurl" category = 'ConnectionError' } } '*401*' { $errorprop = @{ message = "(401)token not valid for server $userurl" category = 'AuthenticationError' } } '*500*' { $errorprop = @{ message = "(500)Server error at $userurl" category = 'AuthenticationError' } } } } catch { { $errorprop = @{ message = $_.exception.message category = $_.categoryinfo.category } } } finally { if($errorprop) { Write-Error @errorprop -ErrorAction Stop } } #endregion $this.hostname = $hostname $this.token = ConvertTo-SecureString $token -AsPlainText -Force $this.username = $result.username } <# Contructor with credentials with password as api-token #> GitlabConnect ([string]$hostname,[pscredential]$User) { $header = @{ 'PRIVATE-TOKEN' = $User.GetNetworkCredential().Password } $userurl = "$hostname/api/v3/user" $errorprop = $null $result = $null try { $result = Invoke-RestMethod -Uri $userurl -Headers $header $errorprop = $null } catch [System.Net.WebException] { switch -Wildcard ($_.exception.Message) { '*Could not create SSL/TLS secure channel.*' { $errorprop = @{ message = "could not reach server at $userurl" category = 'ConnectionError' } } '*401*' { $errorprop = @{ message = "(401)token not valid for server $userurl" category = 'AuthenticationError' } } '*500*' { $errorprop = @{ message = "(500)Server error at $userurl" category = 'AuthenticationError' } } } } catch { { $errorprop = @{ message = $_.exception.message category = $_.categoryinfo.category } } } finally { if($errorprop) { Write-Error @errorprop -ErrorAction Stop } } #endregion $this.hostname = $hostname $this.token = $User.password $this.username = $result.username } <# Helper function to resolve webrequest headers #> Hidden [pscustomobject] resolvelinkheader ([string]$linksString) { #one string multiple links $resultobj = @{} $LinkStrings = $linksString -split ',' #multiple strings one string per link foreach($linkstring in $LinkStrings) { $linkrel = $null $linkprop = $linkstring -split ';' $linkargurl = $linkprop[0].trim(' ','<','>') $linkparamsstring = @($linkargurl.Split('?'))[1].split('&') $linkparams = @{} foreach($paramstring in $linkparamsstring) { $key = $paramstring.split('=')[0] $urlvalue = $paramstring.split('=')[1] $value = [uri]::UnescapeDataString($urlvalue) $linkparams.$key = $value } $linkarg = $linkparams Invoke-Expression -Command ('$link' + $linkprop[1].trim()) $resultobj.$linkrel = $linkarg } return [pscustomobject]$resultobj } <# Main function overload to resolve API calls withoud parameters #> [psobject] callapi ([string]$apiurl,[HTTPMethod]$HTTPmethod) { $result = $this.callapi($apiurl,$HTTPmethod,[hashtable]::new()) return $result } <# Main function overload to resolve API calls withoud body #> [psobject] callapi ([string]$apiurl,[HTTPMethod]$HTTPmethod,[hashtable]$parameters) { $result = $this.callapi($apiurl,$HTTPmethod,$parameters,[hashtable]::new()) return $result } <# Main function overload to resolve API calls withoud outfile #> [psobject] callapi ([string]$apiurl,[HTTPMethod]$HTTPmethod,[hashtable]$parameters,[hashtable]$body) { $result = $this.callapi($apiurl,$HTTPmethod,$parameters,$body,[string]::Empty) return $result } <# Main function overload to resolve API calls withoud outfile #> [psobject] callapi ([string]$apiurl,[HTTPMethod]$HTTPmethod,[hashtable]$parameters,[string]$OutFile) { $result = $this.callapi($apiurl,$HTTPmethod,$parameters,[hashtable]::new(),$OutFile) return $result } <# Main function to resolve API call with #> [psobject] callapi ([string]$apiurl,[HTTPMethod]$HTTPmethod,[hashtable]$parameters,[hashtable]$body,[string]$OutFile) { #create object for webrequest parameters $webrequestparams = @{} #create header $gitlabuser = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $this.username, $this.token $header = @{ 'PRIVATE-TOKEN' = $gitlabuser.GetNetworkCredential().Password } $webrequestparams.headers = $header #create parameter string for url $parameteruristring = $null if($parameters.count -gt 0) { $parameteruristrings = @() foreach($key in $parameters.keys) { $encodeparameter = [uri]::EscapeDataString($key) $encodeargument = [uri]::EscapeDataString([string]$parameters.$key) $parameteruristrings += "$encodeparameter=$encodeargument" } $parameteruristring = '?' + ($parameteruristrings -join '&') } #cleanup url $apiurl = $apiurl.TrimStart('/') $userurl = "$($this.hostname)/api/v3/$apiurl$parameteruristring" $errorprop = $null $resultobj = $null $httpresult = $null $webrequestparams.Uri = $userurl #test outfile if($OutFile) { $Container = Split-Path $OutFile -Parent $ContainerExists = Test-Path $Container if(-not $ContainerExists) { $ErrorMessage = "OutFile location invalid. Folder [$Container] does not exists. " Write-Error -Message $ErrorMessage -Category ResourceUnavailable -ErrorAction Stop } $Leaf = Split-Path $OutFile -Leaf $LeafExists = Test-Path $OutFile if($LeafExists) { $ErrorMessage = "OutFile location invalid. [$Leaf] already exists at [$Container]" } $webrequestparams.OutFile = $OutFile } #set body parameter $webrequestparams.body = $body #send request try { switch($HTTPmethod){ 'get' { $httpresult = Invoke-WebRequest @webrequestparams -Method Get -UseBasicParsing } 'post' { $httpresult = Invoke-WebRequest @webrequestparams -Method Post -UseBasicParsing } 'put' { $httpresult = Invoke-WebRequest @webrequestparams -Method Put -UseBasicParsing } 'delete' { $httpresult = Invoke-WebRequest @webrequestparams -Method Delete -UseBasicParsing } default { Write-Error -Message 'no valid method specified' -ErrorAction Stop } } } catch { Write-Error -Message $_.ErrorDetails.Message -Category $_.CategoryInfo.Category -ErrorAction Stop } finally { } if(-not $OutFile) { #parse result $isResultJson = $httpresult.headers.'Content-Type' -eq 'application/json' if (-not $isResultJson) { Write-Error -Message "Result from api call is not json, check if $($this.hostname) is a gitlab server and supports api v3" -Category InvalidData -ErrorAction Stop } $resultobj = ConvertFrom-Json -InputObject $httpresult.Content #if passed page is not the last page $links = @{} if ($httpresult.Headers.Link) { $links = $this.resolvelinkheader($httpresult.Headers.Link) } if($links.next) { #get link for next page $links = $this.resolvelinkheader($httpresult.Headers.Link) foreach($key in $links.next.keys) { $parameters.$key = $links.next.$key } #get results from next page $resultobj += $this.callapi($apiurl,$HTTPmethod,$parameters) } } return $resultobj } } |