POSH-GitLab-Registry.psm1
# ## Created by: lucas.cueff[at]lucas-cueff.com # ## released on 01/2021 # # v1.0.1 : first public release - beta version # v1.1.0 : beta version : # - add encryption management to config file, # - fix validation pattern for set-GitLabNugetRepository, # - change location default path for import/export-GitLabNugetRepository for linux compatibility ($home instead of $env:programdata) # - fix remove-GitLabNugetRepository # v1.1.1 : last release - beta version : # - add basic auth header for publish api (nuget) => gitlab.com has changed its behavior and does not accept 'PRIVATE-TOKEN' header anymore # #'(c) 2020-2021 lucas-cueff.com - Distributed under Artistic Licence 2.0 (https://opensource.org/licenses/artistic-license-2.0).' <# .SYNOPSIS PowerShell Module managing package list / download from a Package Registry (NuGet format) from a Gitlab repository .DESCRIPTION PowerShell Module managing package list / download from a Package Registry (NuGet format) from a Gitlab repository Functions available : - Register your Package Registry info locally (ProjectID, API Key...) - List all packages available in your Package Registry - Get info from a specific package (files, metadata) - Download a NuGet Package from your Package Registry and extract it locally .EXAMPLE Set a new Package Registry source PS C:\> New-GitLabNugetRepository -SourceName MySource -APIKey "123456789azerty" -ProjectID "12345" -ServerName "Mygitlabci.tld" -APIKeyName "MyUserAccountORAPIKeyName" .EXAMPLE List all packages available from your source PS C:\> Get-GitLabRepositoryPackage -Action list -PackageSource MySource .EXAMPLE Get information for a package in a specific version PS C:\> Get-GitLabRepositoryPackage -Action info -PackageName MyPackage -PackageVersion 1.0.0 .EXAMPLE Install a package from your source PS C:\> Get-GitLabRepositoryPackage -Action install -PackageName MyPackage -OutputDirectory $env:USERPROFILE\desktop #> Function Get-ScriptDirectory { [cmdletbinding()] Param () if ($psISE) { $ScriptPath = Split-Path -Parent $psISE.CurrentFile.FullPath } elseif($PSVersionTable.PSVersion.Major -gt 3) { $ScriptPath = $PSScriptRoot } else { $ScriptPath = split-path -parent $MyInvocation.MyCommand.Path } $ScriptPath } Function Get-GitLabNugetRepository { <# .SYNOPSIS Get info from an existing GitLab Package Registry Source / Repository. .DESCRIPTION Get info from an existing GitLab Package Registry Source / Repository. .PARAMETER SourceName -SourceName [string] SourceName of your project .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Get-GitLabNugetRepository -SourceName MySource Get repository info for MySource .EXAMPLE Get-GitLabNugetRepository Get all repositories info #> [cmdletbinding()] param( [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$SourceName ) process { if (!($global:GitLabNugetConfig)) { throw "please import or create a new source repository using Import-GitLabNugetRepository or New-GitLabNugetRepository cmdlets" } if ($SourceName) { if ($global:GitLabNugetConfig.RepositoryName -contains $SourceName) { return $global:GitLabNugetConfig | Where-Object {$_.RepositoryName -eq $SourceName} } else { throw "nuget repository $($SourceName) is not defined, please use New-GitLabNugetRepository" } } else { return $global:GitLabNugetConfig } } } Function Clear-GitLabNugetRepository { <# .SYNOPSIS Clear all GitLab Package Registry Sources / Repositories set .DESCRIPTION Clear all GitLab Package Registry Sources / Repositories set .OUTPUTS None .EXAMPLE Clear-GitLabNugetRepository Remove all Gitlab Package Registry / repository set locally #> [cmdletbinding()] param() process { if (!($global:GitLabNugetConfig)) { throw "please import or create a new source repository using Import-GitLabNugetRepository or New-GitLabNugetRepository cmdlets" } else { Remove-Variable GitLabNugetConfig -Force -Scope Global } } } Function New-GitLabNugetRepository { <# .SYNOPSIS Create a new GitLab Package Registry Source / Repository .DESCRIPTION Create or add a new GitLab Package Registry Source / Repository. This is a prerequisite to use the other cmdlets like Get-GitLabNugetRepositoryPackage .PARAMETER SourceName -SourceName [string] SourceName of your project .PARAMETER ServerName -ServerName [string] Gitlab Server FQDN, if gitlab.com is used, use 'gitlab.com' value. .PARAMETER APIKey -APIKey [string] GitLab API Key / Access Token (mandatory to access GitLab project repository and package registry). Require API Access : read_api, read_repository, read_registry .PARAMETER APIKeyName -APIKeyName [string] GitLab API Key Name / Access Token Name. Require for Basic Auth with several nuget service (publish). if a personal access token is used, this value must be the account name. .PARAMETER ProjectID -ProjectID [string] ProjectID of your GitLab project .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE New-GitLabNugetRepository -SourceName MySource -APIKey "123456789azerty" -ProjectID "12345" -ServerName "Mygitlabci.tld" -APIKeyName "MyUserAccountORAPIKeyName" Register new repository MySource #> [cmdletbinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$SourceName, [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$ServerName, [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$APIKey, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$APIKeyName, [parameter(Mandatory=$true)] [ValidatePattern("^\d*$")] [string]$ProjectID ) process { if (!($APIKeyName)) { $APIKeyName = "gitlab-ci-token" } if ($global:GitLabNugetConfig) { if ($global:GitLabNugetConfig.RepositoryName -notcontains $SourceName) { $global:GitLabNugetConfig += @{"APIKey" = $APIKey; "APIKeyName" = $APIKeyName ;"ProjectID" = $ProjectID; "RepositoryName" = $SourceName; "Server" = $ServerName} } else { throw "nuget repository $($SourceName) is already defined" } } else { $global:GitLabNugetConfig = [System.Collections.ArrayList]@(@{"APIKey" = $APIKey ; "APIKeyName" = $APIKeyName ; "ProjectID" = $ProjectID; "RepositoryName" = $SourceName; "Server" = $ServerName}) } return $global:GitLabNugetConfig } } Function Set-GitLabNugetRepository { <# .SYNOPSIS Edit an existing GitLab Package Registry Source / Repository .DESCRIPTION Edit an existing GitLab Package Registry Source / Repository. .PARAMETER SourceName -SourceName [string] SourceName of your project .PARAMETER ServerName -ServerName [string] Gitlab Server FQDN, if gitlab.com is used, use 'gitlab.com' value. .PARAMETER APIKey -APIKey [string] GitLab API Key / Access Token (mandatory to access GitLab project repository and package registry). Require API Access : read_api, read_repository, read_registry .PARAMETER APIKeyName -APIKeyName [string] GitLab API Key Name / Access Token Name. Require for Basic Auth with several nuget service (publish). if a personal access token is used, this value must be the account name. .PARAMETER ProjectID -ProjectID [string] ProjectID of your GitLab project .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Set-GitLabNugetRepository -SourceName MySource -APIKey "123456789azerty" -ProjectID "12345" -ServerName "Mygitlabci.tld" -APIKeyName "MyUserAccountORAPIKeyName" Update repository MySource #> [cmdletbinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$SourceName, [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$ServerName, [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$APIKey, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$APIKeyName, [parameter(Mandatory=$true)] [ValidatePattern("^\d*$")] [string]$ProjectID ) process { if (!($global:GitLabNugetConfig)) { throw "please import or create a new source repository using Import-GitLabNugetRepository or New-GitLabNugetRepository cmdlets" } if (!($APIKeyName)) { $APIKeyName = "gitlab-ci-token" } if ($global:GitLabNugetConfig.RepositoryName -contains $SourceName) { $tmpRepository = $global:GitLabNugetConfig | Where-Object {$_.RepositoryName -eq $SourceName} $tmpRepository.ProjectID = $ProjectID $tmpRepository.APIKey = $APIKey $tmpRepository.APIKeyName = $APIKeyName } else { throw "nuget repository $($SourceName) is not defined, please use New-GitLabNugetRepository" } return $global:GitLabNugetConfig } } Function Remove-GitLabNugetRepository { <# .SYNOPSIS Remove an existing GitLab Package Registry Source / Repository. .DESCRIPTION Remove an existing GitLab Package Registry Source / Repository. .PARAMETER SourceName -SourceName [string] SourceName of your project .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Remove-GitLabNugetRepository -SourceName MySource remove repository for MySource #> [cmdletbinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$SourceName ) process { if (!($global:GitLabNugetConfig)) { throw "please import or create a new source repository using Import-GitLabNugetRepository or New-GitLabNugetRepository cmdlets" } $script:tmpGitLabNugetConfig = {$global:GitLabNugetConfig}.Invoke() if ($script:tmpGitLabNugetConfig.RepositoryName -contains $SourceName) { for ($i=0;$i -le $script:tmpGitLabNugetConfig.count;$i++) { if ($script:tmpGitLabNugetConfig[$i].RepositoryName -eq $SourceName) { $script:tmpGitLabNugetConfig.remove($script:tmpGitLabNugetConfig[$i]) break } } } else { throw "nuget repository $($SourceName) is not defined, please use New-GitLabNugetRepository" } $global:GitLabNugetConfig = $script:tmpGitLabNugetConfig return $global:GitLabNugetConfig } } Function Import-GitLabNugetRepository { <# .SYNOPSIS Import a GitLab Package Registry Source / Repository from a configuration file .DESCRIPTION Import a GitLab Package Registry Source / Repository from a configuration file. This is a prerequisite to use the other cmdlets like Get-GitLabNugetRepositoryPackage .PARAMETER XMLFolderPath -XMLFolderPath [string] Folder path where from your XML config file will be imported. If not set, $home\.PoshGitLab will be used .PARAMETER EncryptKeyInLocalFile -EncryptKeyInLocalFile [switch] encrypt apikey with password provided in MasterPassword parameter .PARAMETER MasterPassword -MasterPassword [securestring] password used to encrypt your API Keys .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Import-GitLabNugetRepository Import your configuration from default folder $home\.PoshGitLab .EXAMPLE Import-GitLabNugetRepository -XMLFolderPath c:\MyFolder import your configuration from c:\MyFolder .EXAMPLE Import-GitLabNugetRepository -XMLFolderPath c:\MyFolder -EncryptKeyInLocalFile -MasterPassword (ConvertTo-SecureString -String "YourP@ssw0rd" -AsPlainText -Force) import your encrypted configuration from c:\MyFolder #> [cmdletbinding()] param( [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$XMLFolderPath, [parameter(Mandatory=$false)] [switch]$EncryptKeyInLocalFile, [parameter(Mandatory=$false)] [securestring]$MasterPassword ) process { if (!$home) { $global:home = $env:userprofile } if (!($XMLFolderPath)) { $XMLFolderPath = join-path $global:home ".PoshGitLab" } $XMLFile = join-path $XMLFolderPath "GitlabRepository.xml" if (!(test-path $XMLFile)) { throw "config file $($XMLFile) does not exist" } if ($EncryptKeyInLocalFile.IsPresent) { If (!$MasterPassword) { throw "Please provide a valid Master Password to protect the API Key storage on disk and a valid API Key" } else { $script:tmpGitLabNugetConfig = Import-Clixml -Path $XMLFile $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList 'user', $MasterPassword for ($i=0;$i -le ($script:tmpGitLabNugetConfig.count -1);$i++) { if ($script:tmpGitLabNugetConfig[$i].apikey -and $script:tmpGitLabNugetConfig[$i].Salt) { try { $Rfc2898Deriver = New-Object System.Security.Cryptography.Rfc2898DeriveBytes -ArgumentList $Credentials.GetNetworkCredential().Password, $script:tmpGitLabNugetConfig[$i].Salt $KeyBytes = $Rfc2898Deriver.GetBytes(32) $SecString = ConvertTo-SecureString -Key $KeyBytes $script:tmpGitLabNugetConfig[$i].apikey $SecureStringToBSTR = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($SecString) $APIKey = [Runtime.InteropServices.Marshal]::PtrToStringAuto($SecureStringToBSTR) $script:tmpGitLabNugetConfig[$i].apikey = $APIKey $script:tmpGitLabNugetConfig[$i].remove('Salt') } catch { throw "Not able to set correctly your API Key, your passphrase my be incorrect" } } } $global:GitLabNugetConfig = $script:tmpGitLabNugetConfig.clone() } } else { $global:GitLabNugetConfig = Import-Clixml -Path $XMLFile } return $global:GitLabNugetConfig } } Function Export-GitLabNugetRepository { <# .SYNOPSIS export a GitLab Package Registry Source / Repository to a configuration file .DESCRIPTION export a GitLab Package Registry Source / Repository to a configuration file .PARAMETER XMLFolderPath -XMLFolderPath [string] Folder path where from your XML config file will be imported. If not set, $home\.PoshGitLab will be used .PARAMETER EncryptKeyInLocalFile -EncryptKeyInLocalFile [switch] encrypt apikey with password provided in MasterPassword parameter .PARAMETER MasterPassword -MasterPassword [securestring] password used to encrypt your API Keys .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Export-GitLabNugetRepository Export your configuration to default folder $home\.PoshGitLab .EXAMPLE Export-GitLabNugetRepository -XMLFolderPath c:\MyFolder Export your configuration to c:\MyFolder .EXAMPLE Export-GitLabNugetRepository -XMLFolderPath c:\MyFolder -EncryptKeyInLocalFile -MasterPassword (ConvertTo-SecureString -String "YourP@ssw0rd" -AsPlainText -Force) Export and encrypt your configuration to c:\MyFolder #> [cmdletbinding()] param( [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$XMLFolderPath, [parameter(Mandatory=$false)] [switch]$EncryptKeyInLocalFile, [parameter(Mandatory=$false)] [securestring]$MasterPassword ) process { if (!($global:GitLabNugetConfig)) { throw "please import or create a new source repository using Import-GitLabNugetRepository or New-GitLabNugetRepository cmdlets" } if (!$home) { $global:home = $env:userprofile } if (!($XMLFolderPath)) { $XMLFolderPath = join-path $global:home ".PoshGitLab" write-verbose $XMLFolderPath $XMLFile = join-path $XMLFolderPath "GitlabRepository.xml" if (!(test-path $XMLFolderPath)) { New-Item -ItemType Directory -Path $XMLFolderPath -Force | out-null } } else { $XMLFile = join-path $XMLFolderPath "GitlabRepository.xml" } if ($EncryptKeyInLocalFile.IsPresent) { If (!$MasterPassword) { throw "Please provide a valid Master Password to protect the API Key storage on disk and a valid API Key" } else { $script:tmpGitLabNugetConfig = $global:GitLabNugetConfig.clone() for ($i=0;$i -le ($script:tmpGitLabNugetConfig.count -1);$i++) { if ($script:tmpGitLabNugetConfig[$i].apikey) { [Security.SecureString]$SecureKeyString = ConvertTo-SecureString -String $script:tmpGitLabNugetConfig[$i].apikey -AsPlainText -Force $SaltBytes = New-Object byte[] 32 $RNG = New-Object System.Security.Cryptography.RNGCryptoServiceProvider $RNG.GetBytes($SaltBytes) $Credentials = New-Object System.Management.Automation.PSCredential -ArgumentList 'user', $MasterPassword $Rfc2898Deriver = New-Object System.Security.Cryptography.Rfc2898DeriveBytes -ArgumentList $Credentials.GetNetworkCredential().Password, $SaltBytes $KeyBytes = $Rfc2898Deriver.GetBytes(32) $EncryptedString = $SecureKeyString | ConvertFrom-SecureString -key $KeyBytes $script:tmpGitLabNugetConfig[$i].add('Salt',$SaltBytes) $script:tmpGitLabNugetConfig[$i].APIKey = $EncryptedString } } try { Export-Clixml -InputObject $tmpGitLabNugetConfig -Path $XMLFile -Force Clear-GitLabNugetRepository Import-GitLabNugetRepository @PSBoundParameters } catch { throw "invalid file XML file path" } } } else { try { Export-Clixml -InputObject $global:GitLabNugetConfig -Path $XMLFile -Force return $global:GitLabNugetConfig } catch { throw "invalid file XML file path" } } } } Function Test-GitLabNugetRepository { <# .SYNOPSIS Test if your GitLab Package Registry Source / Repository is correctly set locally .DESCRIPTION Test if your GitLab Package Registry Source / Repository is correctly set locally .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE test your repository source configuration C:\PS> Test-GitLabNugetRepository #> [cmdletbinding()] param() process { if (!($global:GitLabNugetConfig)) { throw "No GitLab Nuget Config loaded, please use Import-GitLabNugetRepository or New-GitLabNugetRepository first" } else { return $global:GitLabNugetConfig } } } Function Invoke-GitlabAPI { [cmdletbinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$SourceName, [parameter(Mandatory=$false)] [ValidateSet("download","metadata","query", "publish","delete")] [string]$NugetAPI, [parameter(Mandatory=$false)] [ValidateSet("list","files","metadata","delete")] [string]$PackageAPI, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$PackageName, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$PackageVersion, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$OutputDirectory, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$PackageID, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$PackageSearch, [parameter(Mandatory=$false)] [ValidateNotNullorempty()] [string]$PackageFilePath ) process { Test-GitLabNugetRepository | Out-Null $tempFilePath = [System.IO.Path]::GetTempFileName() $Repository = $global:GitLabNugetConfig | Where-Object {$_.RepositoryName -eq $SourceName} if (!($Repository)) { throw "repository not found, please use Import-GitLabNugetRepository or New-GitLabNugetRepository first" } $Headers = @{"PRIVATE-TOKEN" = $Repository.APIKey} $BaseGitLabURI = "https://$($Repository.server)/api/v4/projects/$($Repository.ProjectID)/packages" $params = @{ "Headers" = $Headers "UserAgent" = "NuGet Command Line/5.8.0 (Microsoft Windows NT $([System.Environment]::OSVersion.Version.tostring()))" "UseBasicParsing" = $true } if ($NugetAPI) { switch ($NugetAPI) { "download" { if (!($PackageName) -and !($PackageVersion) -and !($OutputDirectory)) { throw "please use PackageName, PackageVersion, OutputDirectory parameters when using NugetAPI Download parameters" } if (!(test-path $OutputDirectory)) { throw "please set an existing target folder as OutputDirectory when using NugetAPI Download parameters" } $URI = $BaseGitLabURI + "/nuget/download/$($PackageName)/$($PackageVersion)/$($PackageName).$($PackageVersion).nupkg" } "metadata" { if (!($PackageName)) { throw "please use PackageName parameter when using NugetAPI metadata parameter" } $URI = $BaseGitLabURI + "/nuget/metadata/$($PackageName)/index.json" } "query" { if (!($PackageSearch)) { throw "please use PackageSearch parameter when using NugetAPI query parameter" } $URI = $BaseGitLabURI + "/nuget/query?q=$([System.Web.HTTPUtility]::UrlEncode($PackageSearch))&prerelease=true" } "publish" { if (!($PackageFilePath)) { throw "please use PackageFilePath parameter when using NugetAPI publish parameter" } $URI = $BaseGitLabURI + "/nuget/" $convertedinfo = Convert-GitLabNugetRepositoryPackage -PackageFilePath $PackageFilePath $params.add("Infile",$convertedinfo.Infile) $params.add("ContentType",$convertedinfo.contenttype) $params.add("method","Put") $Headers.add("Accept-Encoding","gzip, deflate") $Headers.add("Authorization","Basic "+ [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes("$($Repository.APIKeyName):$($Repository.APIKey)"))) } "delete" { if (!($PackageID) -or !($PackageVersion)) { throw "please use PackageID and PackageVersion parameters when using NugetAPI delete parameter" } $URI = $BaseGitLabURI + "/nuget/$($PackageID)/$($PackageVersion)" $params.add("method","delete") } } $params.add("URI",$URI) } elseif ($PackageAPI) { switch ($PackageAPI) { "list" { $URI = $BaseGitLabURI } "files" { if (!($PackageID)) { throw "please use PackageID parameter when using PackageAPI files parameter" } $URI = $BaseGitLabURI + "/$($PackageID)/package_files" } "metadata" { if (!($PackageID)) { throw "please use PackageID parameter when using PackageAPI metadata parameter" } $URI = $BaseGitLabURI + "/$($PackageID)" } "delete" { if (!($PackageID)) { throw "please use PackageID parameter when using PackageAPI metadata parameter" } $URI = $BaseGitLabURI + "/$($PackageID)" $params.add("Method","Delete") } } $params.add("URI",$URI) } if ($OutputDirectory) { try { $result = Invoke-WebRequest -Uri $URI -Headers $Headers -UserAgent "NuGet Command Line/5.8.0 (Microsoft Windows NT $([System.Environment]::OSVersion.Version.tostring()))" -OutFile $tempFilePath } catch { write-error -message "Not able to connect to GitLab API" write-verbose -message "Error Type: $($_.Exception.GetType().FullName)" write-verbose -message "Error Message: $($_.Exception.Message)" write-verbose -message "HTTP error code:$($_.Exception.Response.StatusCode.Value__)" write-verbose -message "HTTP error message:$($_.Exception.Response.StatusDescription)" } if ($tempFilePath) { $newdirectory = "$($packagename).$($packageversion)" $newoutputdirectory = join-path $OutputDirectory $newdirectory if (!(test-path $newoutputdirectory)) { new-item -ItemType Directory -Path $newoutputdirectory -Force | Out-Null } $ziptempfile = "$((get-item -path $tempFilePath).basename).zip" $ziptempfullpath = join-path (get-item $tempFilePath).Directory $ziptempfile move-item -path $tempFilePath -Destination $ziptempfullpath -Force | out-null expand-archive -Path $ziptempfullpath -DestinationPath $newoutputdirectory -Force | out-null Remove-Item -path $ziptempfullpath -Force | Out-Null if (test-path (join-path $newoutputdirectory "_rels")) { remove-item -path (join-path $newoutputdirectory "_rels") -force -Recurse | out-null } if (test-path (join-path $newoutputdirectory "package")) { remove-item -path (join-path $newoutputdirectory "package") -force -Recurse | out-null } if (test-path (join-path $newoutputdirectory "``[Content_Types``].xml")) { remove-item -path (join-path $newoutputdirectory "``[Content_Types``].xml") -force | out-null } } } else { try { $result = Invoke-WebRequest @params if ($result.content) { write-verbose -message $result.content } } catch { write-error -message "Not able to connect to GitLab API" write-verbose -message "Error Type: $($_.Exception.GetType().FullName)" write-verbose -message "Error Message: $($_.Exception.Message)" write-verbose -message "HTTP error code:$($_.Exception.Response.StatusCode.Value__)" write-verbose -message "HTTP error message:$($_.Exception.Response.StatusDescription)" } if ($result) { return ($result | ConvertFrom-Json) } } } } Function Get-GitLabNugetRepositoryPackage { <# .SYNOPSIS Request package information, list packages available, download / install package from a GitLab Package Repository .DESCRIPTION Request package information, list packages available, download / install package from a GitLab Package Repository .PARAMETER Action -Action [string] Validate Set : "list","info","install" list : list all packages available from repository / package registry info : get information for a package and a version install : download / install locally a package in a specific version (last version by default) .PARAMETER PackageName -PackageName [string] name of the package To be used with Action parameter "info" and "install" .PARAMETER PackageSource -PackageSource [string] Name of your repository .PARAMETER PackageVersion -PackageVersion [switch] version of the package To be used with Action parameter "info" and "install" .PARAMETER OutputDirectory -OutputDirectory [string] install folder where package will be downloaded and extracted. If not set, current folder will be used To be used with Action parameter "install" .PARAMETER PackageSearchQuery -PackageSearchQuery [string] Nuget search query to find a package based on NuGet criteria. To be used with Action paramter "search" Nuget Search Query info : https://docs.microsoft.com/en-us/nuget/consume-packages/finding-and-choosing-packages#search-syntax .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Get-GitLabRepositoryPackage -Action list List all packages available from repository / package registry .EXAMPLE Get-GitLabRepositoryPackage -Action info -PackageName myPackage -PackageVersion 1.0.0 Get information about a package in a specific version .EXAMPLE Get-GitLabRepositoryPackage -Action install -PackageName myPackage -PackageVersion 1.0.0 -OutputDirectory c:\PackageInstall Install a package in a specific version .EXAMPLE Get-GitLabRepositoryPackage -Action search -PackageSearchQuery Sysmon Search for a package with a name like sysmon #> [cmdletbinding()] param( [parameter(Mandatory=$true,Position=0)] [ValidateSet("list","info","install","search")] [string]$Action, [parameter(Mandatory=$false,Position=1)] [ValidateNotNullOrEmpty()] [string]$PackageName, [parameter(Mandatory=$false,Position=3)] [ValidateNotNullOrEmpty()] [string]$PackageSource, [parameter(Mandatory=$false,Position=2)] [ValidateNotNullOrEmpty()] [string]$PackageVersion, [parameter(Mandatory=$false,Position=4)] [ValidateNotNullOrEmpty()] [string]$OutputDirectory, [parameter(Mandatory=$false,Position=5)] [ValidateNotNullOrEmpty()] [string]$PackageSearchQuery ) process { Test-GitLabNugetRepository | out-null if (!($PackageSource) -and ($global:GitLabNugetConfig.count -gt 1)) { throw "Please provide a valid Package Source using PackageSource Parameter" } elseif (!($PackageSource) -and ($global:GitLabNugetConfig.count -eq 1)) { $PackageSource = $global:GitLabNugetConfig.repositoryname } if (!($PackageVersion) -and $PackageName) { $AllPackageversion = Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI list | where-object {$_.name -eq $PackageName} $temppackageversion = $AllPackageversion[0].version $PackageVersion = (Invoke-GitlabAPI -SourceName $PackageSource -NugetAPI metadata -PackageName $PackageName -PackageVersion $temppackageversion).items.upper if (!($PackageVersion)) { throw "Not able to find your Package version. Please Provide a valid Package Name and Version using PackageName and PackageVersion parameters" } } if ($PackageName -and $PackageVersion) { $PackageID = (Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI list | where-object {($_.name -eq $PackageName) -and ($_.version -eq $PackageVersion)}).id if (!($PackageID)) { throw "Not able to find your Package ID. Please Provide a valid Package Name and Version using PackageName and PackageVersion parameters" } } switch ($Action) { "list" { Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI list } "info" { Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI metadata -PackageID $PackageID -PackageVersion $PackageVersion Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI files -PackageID $PackageID -PackageVersion $PackageVersion } "install" { if (!($OutputDirectory)) { $OutputDirectory = Get-ScriptDirectory } Invoke-GitlabAPI -SourceName $PackageSource -NugetAPI download -PackageName $PackageName -PackageVersion $PackageVersion -OutputDirectory $OutputDirectory } "search" { if (!($PackageSearchQuery)) { throw "Please use PackageSearchQuery parameter when using Search option of Action parameter" } $result = Invoke-GitlabAPI -SourceName $PackageSource -NugetAPI query -PackageSearch $PackageSearchQuery if ($result.totalHits -gt 0) { $result.data } } } } } Function Convert-GitLabNugetRepositoryPackage { [cmdletbinding()] param( [parameter(Mandatory=$true)] [ValidateNotNullorempty()] [string]$PackageFilePath ) process { if (!(test-path $PackageFilePath)) { throw "please provide a path to an existing nupkg file" } if ((get-item -Path $PackageFilePath).extension -ne ".nupkg") { throw "please provide a valid nupkg file" } $boundary = [Guid]::NewGuid().ToString() $bodyfileheader = @( "--$($boundary)", "Content-Type: application/octet-stream", "Content-Disposition: form-data; name=package; filename=package.nupkg; filename*=utf-8''package.nupkg", "`r`n" ) $bodyfilefooter = "`r`n--$($boundary)--" $requestInFile = [System.IO.Path]::GetTempFileName() try { $fileStream = (New-Object -TypeName 'System.IO.FileStream' -ArgumentList ($requestInFile, [IO.FileMode]'Create', [IO.FileAccess]'Write')) $bytes = [Text.Encoding]::UTF8.GetBytes(($bodyfileheader -join "`r`n")) $fileStream.Write($bytes, 0, $bytes.Length) $bytes = [IO.File]::ReadAllBytes($PackageFilePath) $fileStream.Write($bytes, 0, $bytes.Length) $bytes = [Text.Encoding]::UTF8.GetBytes($bodyfilefooter) $fileStream.Write($bytes, 0, $bytes.Length) } catch { "not able to convert $($PackageFilePath) into a compliant 'multipart/form-data' with boundary $($boundary)" } $fileStream.Close() return @{ "InFile" = $requestInFile "ContentType" = "multipart/form-data; boundary=`"{0}`"" -f $boundary } } } Function Publish-GitLabNugetRepositoryPackage { <# .SYNOPSIS Publish a new NuGet Package to a GitLab Package Repository .DESCRIPTION Publish a new NuGet Package to a GitLab Package Repository .PARAMETER PackageFile -PackageFile [string] full file path of the NuGet package to publish File format : .nupkg .PARAMETER PackageSource -PackageSource [string] Name of your repository .OUTPUTS TypeName : System.Collections.Hashtable .EXAMPLE Publish-GitLabNugetRepositoryPackage -PackageFile C:\MyPackage\MyPackage.1.0.0.nupkg Publish Nuget Package C:\MyPackage\MyPackage.1.0.0.nupkg to the default Gitlab Package Registry #> [cmdletbinding()] param( [parameter(Mandatory=$true,Position=1)] [ValidateNotNullOrEmpty()] [string]$PackageFile, [parameter(Mandatory=$false,Position=2)] [ValidateNotNullOrEmpty()] [string]$PackageSource ) process { Test-GitLabNugetRepository | out-null if (!($PackageSource) -and ($global:GitLabNugetConfig.count -gt 1)) { throw "Please provide a valid Package Source using PackageSource Parameter" } elseif (!($PackageSource) -and ($global:GitLabNugetConfig.count -eq 1)) { $PackageSource = $global:GitLabNugetConfig.repositoryname } Invoke-GitlabAPI -SourceName $PackageSource -NugetAPI publish -PackageFilePath $PackageFile } } Function Remove-GitLabNugetRepositoryPackage { <# .SYNOPSIS Remove a new NuGet Package from a GitLab Package Repository .DESCRIPTION Remove a new NuGet Package from a GitLab Package Repository .PARAMETER PackageName -PackageName [string] name of the package .PARAMETER PackageSource -PackageSource [string] Name of your repository .PARAMETER PackageVersion -PackageVersion [switch] version of the package .OUTPUTS TypeName : None .EXAMPLE Remove-GitLabNugetRepositoryPackage -PackageName MyPackage -PackageVersion 1.0.0 Remove NuGet package MyPackage in version 1.0.0 from the default Gitlab Package Registry #> [cmdletbinding()] param( [parameter(Mandatory=$true,Position=1)] [ValidateNotNullOrEmpty()] [string]$PackageName, [parameter(Mandatory=$true,Position=2)] [ValidateNotNullOrEmpty()] [string]$PackageVersion, [parameter(Mandatory=$false,Position=2)] [ValidateNotNullOrEmpty()] [string]$PackageSource ) process { Test-GitLabNugetRepository | out-null if (!($PackageSource) -and ($global:GitLabNugetConfig.count -gt 1)) { throw "Please provide a valid Package Source using PackageSource Parameter" } elseif (!($PackageSource) -and ($global:GitLabNugetConfig.count -eq 1)) { $PackageSource = $global:GitLabNugetConfig.repositoryname } $AllPackages = Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI list $PackagesRemoved = $AllPackages | Where-Object {($_.name -eq $PackageName) -and ($_.version -eq $PackageVersion)} if ($PackagesRemoved) { write-verbose -Message "Package Source : $($PackageSource)" write-verbose -Message "Package ID : $($PackagesRemoved.id)" Invoke-GitlabAPI -SourceName $PackageSource -PackageAPI delete -PackageID $PackagesRemoved.id } else { write-warning "No package found with Name $($PackageName) and Version $($PackageVersion)" } } } New-Alias -name nuget -Value Get-GitLabNugetRepositoryPackage Export-ModuleMember -Function Import-GitLabNugetRepository, New-GitLabNugetRepository, Test-GitLabNugetRepository, Invoke-GitlabAPI, Get-GitLabNugetRepositoryPackage, Convert-GitLabNugetRepositoryPackage, Publish-GitLabNugetRepositoryPackage, Remove-GitLabNugetRepositoryPackage, Export-GitLabNugetRepository, Clear-GitLabNugetRepository, Set-GitLabNugetRepository, Get-GitLabNugetRepository, Remove-GitLabNugetRepository Export-ModuleMember -Alias nuget |