nexuslib.ps1 Powershell library for uploading files to Nexus raw repository

After a few days’ worth of research, I have finally settled on the way I can upload files to a Nexus repository of type raw.

This function accepts multiple ways to pass in authentication: either the prebuilt header, or a regular Powershell credentials object, or just username and password.

And yes, this function depends on credlib.ps1.

# Filename: nexuslib.ps1
# Location: \\rdputil1\e$\scripts\Functions\
# Author: bgstack15
# Startdate: 2020-06-09
# Title: Upload files to a Nexus raw repository
# Purpose: Upload arbitrary files to Nexus
# History:
#    I originally tried http://blog.majcica.com/2016/03/31/uploading-artifacts-into-nexus-via-powershell/ but it must be out of date.
# Usage:
#    . nexuslib.ps1
#    Upload-File-To-Nexus Upload-File-To-Nexus -File "C:\Users\bgstack15\Downloads\input1.zip" -Repository "raw" -Directory "/somewhere" -FileName "output.zip" -Credential $hubtestCredential
# References:
#    curl.exe -v -X POST -F "raw.directory=example/raw/dir/" -F "raw.asset1=@C:\Users\bgstack15\Downloads\example.zip" -F "raw.asset1.filename=example.zip" -u bgstack15:SOMETHINGHERE https://hubtest.example.com/service/rest/v1/components?repository=raw --trace-ascii outputfile.txt
#    https://help.sonatype.com/repomanager3/rest-and-integration-api/components-api#ComponentsAPI-Raw
#    https://stackoverflow.com/questions/22491129/how-to-send-multipart-form-data-with-powershell-invoke-restmethod/48580319#48580319
# Improve:
#    Upload maven2 files? That use case will probably not come up here.
# Documentation:
# Dependencies:
#    \\rdputil1\e$\scripts\Functions\credlib.ps1

Function Upload-File-To-Nexus {
	[CmdletBinding()]
	Param(
		[Parameter(Mandatory=$True )][ValidateNotNullOrEmpty()][string]$File, # aka File
		[Parameter(Mandatory=$False)][string]$Server = "hubtest.benefitfocus.com",
		[Parameter(Mandatory=$False)][string]$Username,
		[Parameter(Mandatory=$False)][string]$Password,
		[Parameter(Mandatory=$False)][Hashtable]$AuthHeaders,
		[Parameter(Mandatory=$False)][System.Management.Automation.PSCredential]$Credential,
		[parameter(Mandatory=$True )][ValidateNotNullOrEmpty()][string]$Repository,
		[parameter(Mandatory=$True )][ValidateNotNullOrEmpty()][string]$Directory,
		[Parameter(Mandatory=$False)][ValidateNotNullOrEmpty()][string]$FileName # destination filename, which can be derived from uploaded file
	)

	Begin {
		If (!($AuthHeaders -ne $Null)) {
			If (!($Credential -ne $Null)) {
				If ($Username -ne $null -And $Password -ne $Null -And $Username -ne "" -And $Password -ne "") {
					$secret = $password | ConvertTo-SecureString -AsPlainText -Force
					$Credential = New-Object -TypeName "System.Management.Automation.PSCredential" -ArgumentList ${username}, ${secret}
				} Else {
					Throw "Need one of: -AuthHeaders or -Credential, or both -Username and -Password. Aborted."
				}
			}
			# transform credential to authheader format
			. \\rdputil1\e$\scripts\Functions\credlib.ps1
			$AuthHeaders = Get-Basic-Base64-Auth-Headers -Credential $Credential
		}
		$Uri = "https://${Server}/service/rest/v1/components?repository=${Repository}"
		$boundary = [System.Guid]::NewGuid().ToString()
		$LF = "`r`n"
	}

	Process {
		If (!($FileName -ne $Null -And $FileName -ne "")) {
			# if filename is null, then just use the filename from the input file
			$FileName = Split-Path $File -Leaf
		}
		Try { $fileBin = [System.IO.File]::ReadAlltext($File) }
		Catch { Throw "Unable to read file $File. Aborted." }
		$bodyLines = (
			"--${boundary}",
			"Content-Disposition: form-data; name=`"raw.directory`"",
			"",
			"${Directory}",
			"--${boundary}",
			"Content-Disposition: form-data; name=`"raw.asset1`"; filename=`"${FileName}`"",
			"Content-Type: application/octet-stream",
			"",
			$fileBin,
			"",
			"--${boundary}",
			"Content-Disposition: form-data; name=`"raw.asset1.filename`"",
			"",
			"${FileName}",
			"--${boundary}--",
			""
		) -join $LF
		$Response = Invoke-WebRequest -Uri $Uri -Method "POST" -Headers $AuthHeaders -ContentType "multipart/form-data; boundary=`"$boundary`"" -Body $bodyLines
		If ($Response.StatusCode -ge 200 -And $Response.StatusCode -lt 300) {
			$Output = "https://${Server}/repository/${repository}/${directory}/${FileName}" -Replace "//","/"
			Write-Output $Output
		} Else {
			Write-Output $Response
		}
	}
}

References

Weblinks

  1. Components API | Sonatype Nexus documentation
  2. curl – How to send multipart/form-data with PowerShell Invoke-RestMethod – Stack Overflow

Alternate reading

  1. This page attempts to explain how to upload a file to Nexus, but it must be out of date or otherwise invalid. And the official Sonatype documentation even linked to it at one point somewhere! Uploading artifacts into Nexus via PowerShell – Mummy’s blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.