diff --git a/step-templates/liquibase-run-command.json b/step-templates/liquibase-run-command.json index ec36c5ce6..6a30851b0 100644 --- a/step-templates/liquibase-run-command.json +++ b/step-templates/liquibase-run-command.json @@ -3,7 +3,7 @@ "Name": "Liquibase - Run command", "Description": "Run Liqbuibase commands against a database. You can include Liquibase in the package itself or choose Download to download it during runtime.\n\nNote:\n- AWS EC2 IAM Authentication requires the AWS CLI to be installed.\n- Windows Authentication has been tested with \n - Microsoft SQL Server \n - PostgreSQL\n\nOnce the Liquibase commands have executed, the output is stored in an Octopus [output variable](https://octopus.com/docs/projects/variables/output-variables) called `LiquibaseCommandOutput` for use in subsequent Octopus deployment or runbook steps.", "ActionType": "Octopus.Script", - "Version": 24, + "Version": 25, "Author": "twerthi", "Packages": [ { @@ -21,7 +21,7 @@ ], "Properties": { "Octopus.Action.Script.ScriptSource": "Inline", - "Octopus.Action.Script.ScriptBody": "# Configure template\n\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows) {\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Fix ANSI Color on PWSH Core issues when displaying objects\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Set TLS\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12\n\n# Downloads and extracts liquibase to the work folder\nFunction Get-Liquibase {\n # Define parameters\n param ($Version) \n\n $repositoryName = \"liquibase/liquibase\"\n\n # Check to see if version wasn't specified\n if ([string]::IsNullOrEmpty($Version)) {\n # Get the latest version download url\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".zip\") })\n }\n else {\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $Version | Where-Object { $_.EndsWith(\".zip\") })\n }\n\n # Extract the downloaded file\n Expand-DownloadedFile -DownloadUrls $downloadUrl | Out-Null\n \n # Parse downloaded version\n if ($downloadUrl -is [array]) {\n $downloadedFileName = [System.IO.Path]::GetFileName($downloadUrl[0])\n }\n else {\n $downloadedFileName = [System.IO.Path]::GetFileName($downloadUrl)\n }\n\n # Return the downloaded version\n return $downloadedFileName.SubString($downloadedFileName.IndexOf(\"-\") + 1).Replace(\".zip\", \"\") \n}\n\n# Downloads the files\nFunction Expand-DownloadedFile {\n # Define parameters\n param (\n $DownloadUrls\n )\n \n # Loop through results\n foreach ($url in $DownloadUrls) {\n # Download the zip file\n $folderName = [System.IO.Path]::GetFileName(\"$PSScriptroot/$($url.Substring($url.LastIndexOf(\"/\")))\").Replace(\".zip\", \"\")\n $zipFile = \"$PSScriptroot/$folderName/$($url.Substring($url.LastIndexOf(\"/\")))\"\n Write-Host \"Downloading $zipFile from $url ...\"\n \n if ((Test-Path -Path \"$PSScriptroot/$folderName\") -eq $false) {\n # Create folder\n New-Item -Path \"$PSScriptroot/$folderName/\" -ItemType Directory\n }\n\n # Download the zip file\n Invoke-WebRequest -Uri $url -OutFile $zipFile -UseBasicParsing | Out-Null\n\n # Extract package\n Write-Host \"Extracting $zipFile ...\"\n Expand-Archive -Path $zipFile -DestinationPath \"$PSSCriptRoot/$folderName\" | Out-Null\n }\n}\n\n\n# Downloads and extracts Java to the work folder, then adds the location of java.exe to the $env:PATH variabble so it can be called\nFunction Get-Java {\n # Check to see if a folder needs to be created\n if ((Test-Path -Path \"$PSScriptRoot/jdk\") -eq $false) {\n # Create new folder\n New-Item -ItemType Directory -Path \"$PSSCriptRoot/jdk\"\n }\n\n # Download java\n Write-Output \"Downloading Java ... \"\n \n # Determine OS\n if ($IsWindows) {\n Invoke-WebRequest -Uri \"https://download.java.net/java/GA/jdk14.0.2/205943a0976c4ed48cb16f1043c5c647/12/GPL/openjdk-14.0.2_windows-x64_bin.zip\" -OutFile \"$PSScriptroot/jdk/openjdk-14.0.2_windows-x64_bin.zip\" -UseBasicParsing\n\n # Extract\n Write-Output \"Extracting Java ... \"\n Expand-Archive -Path \"$PSScriptroot\\jdk\\openjdk-14.0.2_windows-x64_bin.zip\" -DestinationPath \"$PSSCriptRoot/jdk\"\n\n # Get Java executable\n $javaExecutable = Get-ChildItem -Path \"$PSScriptRoot\\jdk\" -Recurse | Where-Object { $_.Name -eq \"java.exe\" }\n }\n \n if ($IsLinux) {\n Invoke-WebRequest -Uri \"https://download.java.net/openjdk/jdk14/ri/openjdk-14+36_linux-x64_bin.tar.gz\" -OutFile \"$PSScriptroot/jdk/openjdk-14+36_linux-x64_bin.tar.gz\" -UseBasicParsing\n\n # Extract\n Write-Output \"Extracting Java ... \"\n tar -xvzf \"$PSScriptroot/jdk/openjdk-14+36_linux-x64_bin.tar.gz\" --directory \"$PSScriptRoot/jdk\"\n\n # Get Java executable\n $javaExecutable = Get-ChildItem -Path \"$PSScriptRoot/jdk\" -Recurse | Where-Object { $_.Name -eq \"java\" } \n }\n \n # Add path to current session as first entry to bypass other versions of Java that may be installed.\n $env:PATH = \"$($javaExecutable.Directory)$([IO.Path]::PathSeparator)\" + $env:PATH\n \n}\n\nFunction Get-DriverAssets {\n # Define parameters\n param (\n $DownloadInfo\n )\n\n # Declare working variables\n $assetFilePath = \"\"\n\n # Check to see if there are multiple assets to download\n if ($DownloadInfo -is [array]) {\n # Declare local variables\n $assetFiles = @()\n\n # Loop through array\n foreach ($url in $DownloadInfo) {\n # Download the asset\n Write-Host \"Downloading asset from $url...\"\n $assetPath = \"$PSScriptroot/$($url.Substring($url.LastIndexOf(\"/\")))\"\n \n # Skip test assets\n if ($assetPath.EndsWith(\"tests.jar\")) {\n Write-Host \"Asset is for testing, skipping ...\"\n continue\n }\n \n Invoke-WebRequest -Uri $url -Outfile $assetPath -UseBasicParsing\n $assetFiles += $assetPath\n }\n\n # Assign paths\n $assetFilePath = $assetFiles -join \"$([IO.Path]::PathSeparator)\"\n }\n else {\n # Download asset\n Write-Host \"Downloading asset from $DownloadInfo ...\"\n $assetFilePath = \"$PSScriptroot/$($DownloadInfo.Substring($DownloadInfo.LastIndexOf(\"/\")))\"\n Invoke-WebRequest -Uri $DownloadInfo -Outfile $assetFilePath -UseBasicParsing\n }\n\n # Return path\n return $assetFilePath\n}\n\n# Gets download url of latest release with an asset\nFunction Get-LatestVersionDownloadUrl {\n # Define parameters\n param(\n $Repository,\n $Version\n )\n \n # Define local variables\n $releases = \"https://api.github.com/repos/$Repository/releases\"\n \n # Get latest version\n Write-Host \"Determining latest release of $Repository ...\"\n \n $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)\n \n if ($null -ne $Version) {\n # Get specific version\n $tags = ($tags | Where-Object { $_.name.EndsWith($Version) })\n\n # Check to see if nothing was returned\n if ($null -eq $tags) {\n # Not found\n Write-Host \"No release found matching version $Version, getting highest version using Major.Minor syntax...\"\n\n # Get the tags\n $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)\n\n # Parse the version number into a version object\n $parsedVersion = [System.Version]::Parse($Version)\n $partialVersion = \"$($parsedVersion.Major).$($parsedVersion.Minor)\"\n \n # Filter tags to ones matching only Major.Minor of version specified\n $tags = ($tags | Where-Object { $_.name.Contains(\"$partialVersion.\") -and $_.draft -eq $false })\n \n # Grab the latest\n if ($null -eq $tags)\n {\n \t# decrement minor version\n $minorVersion = [int]$parsedVersion.Minor\n $minorVersion --\n \n # return the urls\n return (Get-LatestVersionDownloadUrl -Repository $Repository -Version \"$($parsedVersion.Major).$($minorVersion)\")\n }\n }\n }\n\n # Find the latest version with a downloadable asset\n foreach ($tag in $tags) {\n if ($tag.assets.Count -gt 0) {\n return $tag.assets.browser_download_url\n }\n }\n\n # Return the version\n return $null\n}\n\n# Finds the specified changelog file\nFunction Get-ChangeLog {\n # Define parameters\n param ($FileName)\n \n # Find file\n $fileReference = (Get-ChildItem -Path $OctopusParameters[\"Octopus.Action.Package[liquibaseChangeSet].ExtractedPath\"] -Recurse | Where-Object { $_.Name -eq $FileName })\n\n # Check to see if something weas returned\n if ($null -eq $fileReference) {\n # Not found\n Write-Error \"$FileName was not found in $PSScriptRoot or subfolders.\"\n }\n\n # Return the reference\n return $fileReference\n}\n\n# Downloads the appropriate JDBC driver\nFunction Get-DatabaseJar {\n # Define parameters\n param ($DatabaseType)\n\n # Declare local variables\n $driverPath = \"\"\n\n # Check to see if a folder needs to be created\n if ((Test-Path -Path \"$PSScriptRoot/DatabaseDriver\") -eq $false) {\n # Create new folder\n New-Item -ItemType Directory -Path \"$PSSCriptRoot/DatabaseDriver\" | Out-Null\n }\n\n # Download the driver for the selected type\n switch ($DatabaseType) {\n \"Cassandra\" {\n\n\t\t\t# Get the release download\n Write-Host \"Downloading Cassandra JDBC driver bundle ...\"\n\t\t\t$downloadUrl = Get-LatestVersionDownloadUrl -Repository \"ing-bank/cassandra-jdbc-wrapper\"\n \n # Find driver\n $driverPath = (Get-DriverAssets -DownloadInfo $downloadUrl)\n\n # Set repo name\n $repositoryName = \"liquibase/liquibase-cassandra\"\n \n if ([string]::IsNullOrEmpty($liquibaseVersion)) {\n # Get the latest version for the extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n \t}\n else {\n # Download version matching extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object { $_.EndsWith(\".jar\") })\n } \n\n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n\n break\n }\n \"DB2\" {\n # Use built-in driver\n $driverPath = $null\n break\n }\n \"MariaDB\" {\n # Download MariaDB driver\n Write-Host \"Downloading MariaDB driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/mariadb-java-client-2.6.2.jar\"\n Invoke-WebRequest -Uri \"https://downloads.mariadb.com/Connectors/java/connector-java-2.6.2/mariadb-java-client-2.6.2.jar\" -OutFile $driverPath -UseBasicParsing\n \n break\n }\n \"MongoDB\" {\n # Download MongoDB driver\n Write-Host \"Downloading Maven MongoDB driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/mongo-java-driver-3.12.7.jar\"\n Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.12.7/mongo-java-driver-3.12.7.jar\" -Outfile $driverPath -UseBasicParsing\n \n # Check to see if they are using a licenced version\n if (![string]::IsNullOrWhitespace($liquibaseProLicenseKey)) {\n # Set the paid version url\n $mongoVersions = Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-commercial-mongodb\" -UseBasicParsing\n \n # Loop through links, look for ones that evaluate to version\n $versions = @()\n foreach ($link in $mongoVersions.Links) {\n Write-Verbose \"Evaluating: $link\"\n if (![string]::IsNullOrWhitespace($link.title)) {\n # Get the inner text\n $versionNumber = $link.title.Replace(\"/\", \"\")\n\n # Check to see if $versionNumber can be parsed as a versionNumber\n $versionOut = $null\n if ([System.Version]::TryParse($versionNumber, [ref]$versionOut)) {\n $versions += $versionOut\n }\n }\n }\n\n # Get the highest version number\n $info = ($versions | Measure-Object -Maximum)\n\n $downloadUrl = \"https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-commercial-mongodb/$($info.Maximum)/liquibase-commercial-mongodb-$($info.Maximum).jar\" \n }\n else {\n # Set repo name\n $repositoryName = \"liquibase/liquibase-mongodb\" \n \n # Download latest OSS version\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n }\n \n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n \n break\n }\n \"MySQL\" {\n # Download MariaDB driver\n Write-Host \"Downloading MySQL driver ...\"\n Invoke-WebRequest -Uri \"https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.28.zip\" -OutFile \"$PSScriptroot/DatabaseDriver/mysql-connector-java-8.0.28.zip\" -UseBasicParsing -UserAgent \"curl/7.8.3.1\"\n\n # Extract package\n Write-Host \"Extracting MySQL driver ...\"\n Expand-Archive -Path \"$PSScriptroot/DatabaseDriver/mysql-connector-java-8.0.28.zip\" -DestinationPath \"$PSSCriptRoot/DatabaseDriver\"\n\n # Find driver\n $driverPath = (Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mysql-connector-java-8.0.28.jar\" }).FullName\n\n break\n }\n \"Oracle\" {\n # Download Oracle driver\n Write-Host \"Downloading Oracle driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/ojdbc10.jar\"\n Invoke-WebRequest -Uri \"https://download.oracle.com/otn-pub/otn_software/jdbc/211/ojdbc11.jar\" -OutFile $driverPath -UseBasicParsing\n\n break\n }\n \"SqlServer\" {\n # Download Microsoft driver\n Write-Host \"Downloading Sql Server driver ...\"\n Invoke-WebRequest -Uri \"https://go.microsoft.com/fwlink/?linkid=2186163\" -OutFile \"$PSScriptroot/DatabaseDriver/sqljdbc_10.2.0.0_enu.zip\" -UseBasicParsing\n\n # Extract package\n Write-Host \"Extracting SqlServer driver ...\"\n Expand-Archive -Path \"$PSScriptroot/DatabaseDriver/sqljdbc_10.2.0.0_enu.zip\" -DestinationPath \"$PSSCriptRoot/DatabaseDriver\"\n\n # Find driver\n $driverPath = (Get-ChildItem -Path \"$PSSCriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc-10.2.0.jre11.jar\" }).FullName\n \n # Determine architecture\n if ([System.Environment]::Is64BitOperatingSystem) {\n # Locate auth dll\n $authDll = Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc_auth-10.2.0.x64.dll\" }\n }\n else {\n $authDll = Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc_auth-10.2.0.x86.dll\" }\n }\n \n # Add the dll to the path so it can find it.\n $env:PATH += \"$([IO.Path]::PathSeparator)$($authDll.Directory)\"\n \n break\n }\n \"PostgreSQL\" {\n # Download PostgreSQL driver\n Write-Host \"Downloading PostgreSQL driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/postgresql-42.2.12.jar\"\n Invoke-WebRequest -Uri \"https://jdbc.postgresql.org/download/postgresql-42.2.12.jar\" -OutFile $driverPath -UseBasicParsing\n \n # Download the WAFFLE jna driver for Windows Authentication\n $repositoryName = \"waffle/waffle\"\n \n # Latest version of Waffle (2.3.0) doesn't seem to work, can't find sspi method, specify version 1.9.0\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version \"1.9.0\" | Where-Object { $_.EndsWith(\".zip\") })\n Expand-DownloadedFile -DownloadUrls $downloadUrl | Out-Null\n \n # Get all waffle jars\n $waffleFolder = (Get-ChildItem -Path \"$PSScriptroot\" -Recurse | Where-Object { $_.PSIsContainer -and $_.Name -like \"Waffle*\" }) \n $waffleJars = (Get-ChildItem -Path $waffleFolder.FullName -Recurse | Where-Object { $_.Extension -eq \".jar\" })\n \n foreach ($jar in $waffleJars) {\n $driverPath += \"$([IO.Path]::PathSeparator)$($jar.FullName)\"\n }\n\n break\n }\n \"Snowflake\" {\n # Set repo name\n $repositoryName = \"liquibase/liquibase-snowflake\"\n\n # Download Snowflake driver\n Write-Host \"Downloading Snowflake driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/snowflake-jdbc-3.9.2.jar\"\n Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/net/snowflake/snowflake-jdbc/3.9.2/snowflake-jdbc-3.9.2.jar\" -OutFile $driverPath -UseBasicParsing\n\n if ([string]::IsNullOrEmpty($liquibaseVersion)) {\n # Get the latest version for the extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n \t}\n else {\n # Download version matching extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object { $_.EndsWith(\".jar\") })\n }\n \n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n\n\n break\n }\n default {\n # Display error\n Write-Error \"Unknown database type: $DatabaseType.\"\n }\n }\n\n # Return the driver location\n return $driverPath\n}\n\n# Returns the connection string formatted for the database type\nFunction Get-ConnectionUrl {\n # Define parameters\n param ($DatabaseType, \n $ServerPort, \n $ServerName, \n $DatabaseName, \n $QueryStringParameters)\n\n # Define local variables\n $connectionUrl = \"\"\n\n # Download the driver for the selected type\n switch ($DatabaseType) {\n \"Cassandra\" {\n #$connectionUrl = \"jdbc:cassandra://{0}:{1};DefaultKeyspace={2}\"\n $connectionUrl = \"jdbc:cassandra://{0}:{1}/{2}\"\n break\n }\n \"DB2\" {\n $connectionUrl = \"jdbc:db2://{0}:{1}/{2}\"\n break\n }\n \"MariaDB\" {\n $connectionUrl = \"jdbc:mariadb://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?integratedSecurity=true\"\n }\n \n break\n }\n \"MongoDB\" {\n $connectionUrl = \"mongodb://{0}:{1}/{2}\" \n break\n }\n \"MySQL\" {\n $connectionUrl = \"jdbc:mysql://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?integratedSecurity=true\"\n }\n \n break\n }\n \"Oracle\" {\n $connectionUrl = \"jdbc:oracle:thin:@{0}:{1}/{2}\"\n break\n }\n \"SqlServer\" {\n $connectionUrl = \"jdbc:sqlserver://{0}:{1};database={2};\"\n \n switch ($liquibaseAuthenticationMethod) {\n \"azuremanagedidentity\" {\n # Add querystring parameter\n $connectionUrl += \"Authentication=ActiveDirectoryMSI;\"\n break\n }\n \"windowsauthentication\" {\n # Add querysting parameter\n $connectionUrl += \"integratedSecurity=true;\"\n \t\n break\n }\n }\n \n break\n }\n \"PostgreSQL\" {\n $connectionUrl = \"jdbc:postgresql://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?gsslib=sspi\"\n }\n \n break\n }\n \"Snowflake\" {\n $connectionUrl = \"jdbc:snowflake://{0}.snowflakecomputing.com?db={2}\"\n break\n }\n default {\n # Display error\n Write-Error \"Unkonwn database type: $DatabaseType.\"\n }\n }\n\n if (![string]::IsNullOrWhitespace($QueryStringParameters)) { \t\n if ($connectionUrl.Contains(\"?\")) {\n \t# Replace the ? with & in connection string parameters\n $QueryStringParameters = $QueryStringParameters.Replace(\"?\", \"&\")\n }\n \n # Appen connecion string\n $connectionUrl += \"$QueryStringParameters\"\n }\n\n # Return the url\n return ($connectionUrl -f $ServerName, $ServerPort, $DatabaseName)\n}\n\n# Create array for arguments\n$liquibaseArguments = @()\n\n# Check to see if it's running on Windows\nif ($IsWindows) {\n # Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\n# Check for license key\nif (![string]::IsNullOrWhitespace($liquibaseProLicenseKey)) {\n # Add key to arguments\n $liquibaseArguments += \"--liquibaseProLicenseKey=$liquibaseProLicenseKey\"\n}\n\n# Find Change log\n$changeLogFile = (Get-ChangeLog -FileName $liquibaseChangeLogFileName)\n$liquibaseArguments += \"--changeLogFile=$($changeLogFile.Name)\"\n\n# Set the location to where the file is\nSet-Location -Path $changeLogFile.Directory\n\n# Check to see if it needs to be downloaed to machine\nif ($liquibaseDownload -eq $true) {\n # Download and extract liquibase - get the version for extensions that are version specific\n $liquibaseVersion = Get-Liquibase -Version $liquibaseVersion -DownloadFolder $workingFolder\n\n # Download and extract java and add it to PATH environment variable\n Get-Java\n\n # Get the driver\n $driverPath = Get-DatabaseJar -DatabaseType $liquibaseDatabaseType\n\n # Check to see if it's null\n if ($null -ne $driverPath) {\n # Create folder to hold jar files to override\n New-Item -Path \"$PWD/liquibase_libs/\" -ItemType Directory \n\n # Copy contents into liquibase_libs folder\n $driverPaths = $driverPath.Split([IO.Path]::PathSeparator)\n\n foreach ($driver in $driverPaths) {\n # Copy the items\n $files = Get-ChildItem -Path $driver\n\n foreach ($file in $files) {\n Write-Host \"Copying $($file.FullName) to $PWD/liquibase_libs/$($file.Name)\"\n Copy-Item -Path $file.FullName -Destination \"$PWD/liquibase_libs/$($file.Name)\"\n }\n }\n }\n}\nelse {\n if (![string]::IsNullOrEmpty($liquibaseClassPath)) {\n $liquibaseArguments += \"--classpath=$liquibaseClassPath\"\n }\n}\n\n# Check to see if liquibase path has been defined\nif ([string]::IsNullOrEmpty($liquibaseExecutablePath)) {\n # Assign root\n $liquibaseExecutablePath = $PSSCriptRoot\n}\n\n# Get the executable location\nif ($IsWindows) {\n $liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object { $_.Name -eq \"liquibase.bat\" }\n}\n\nif ($IsLinux) {\n $liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object { $_.Name -eq \"liquibase\" }\n}\n\n# Add path to current session\n$env:PATH += \"$([IO.Path]::PathSeparator)$($liquibaseExecutable.Directory)\"\n\n# Check to make sure it was found\nif ([string]::IsNullOrEmpty($liquibaseExecutable)) {\n # Could not find the executable\n Write-Error \"Unable to find liquibase.bat in $PSScriptRoot or subfolders.\"\n}\n\n# Get connection Url\n$connectionUrl = Get-ConnectionUrl -DatabaseType $liquibaseDatabaseType -ServerPort $liquibaseServerPort -ServerName $liquibaseServerName -DatabaseName $liquibaseDatabaseName -QueryStringParameters $liquibaseQueryStringParameters\n\n# Add username\n$liquibaseArguments += \"--username=$liquibaseUsername\"\n\n# Determine authentication method\nswitch ($liquibaseAuthenticationMethod) {\n \"azuremanagedidentity\" {\n # SQL Server driver doesn't assign password\n if ($liquibaseDatabaseType -ne \"SqlServer\") {\n # Get login token\n Write-Host \"Generating Azure Managed Identity token ...\"\n $token = Invoke-RestMethod -Method GET -Uri \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://ossrdbms-aad.database.windows.net\" -Headers @{\"MetaData\" = \"true\" } -UseBasicParsing\n\n $liquibasePassword = $token.access_token\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n }\n }\n \"awsiam\" {\n # Region is part of the RDS endpoint, extract\n $region = ($liquibaseServerName.Split(\".\"))[2]\n\n Write-Host \"Generating AWS IAM token ...\"\n $liquibasePassword = (aws rds generate-db-auth-token --hostname $liquibaseServerName --region $region --port $liquibaseServerPort --username $liquibaseUsername)\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n\n break\n }\n \"gcpserviceaccount\" {\n # Define header\n $header = @{ \"Metadata-Flavor\" = \"Google\" }\n\n # Retrieve service accounts\n $serviceAccounts = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/\" -Headers $header -UseBasicParsing\n\n # Results returned in plain text format, get into array and remove empty entries\n $serviceAccounts = $serviceAccounts.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)\n\n # Retreive the specific service account assigned to the VM\n $serviceAccount = $serviceAccounts | Where-Object { $_.Contains(\"iam.gserviceaccount.com\") }\n\n Write-Host \"Generating GCP IAM token ...\"\n # Retrieve token for account\n $token = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$serviceAccount/token\" -Headers $header -UseBasicParsing\n \n $liquibasePassword = $token.access_token\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n }\n \"usernamepassword\" {\n # Add password\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n \n break\n }\n}\n\n# Add connection url\n$liquibaseArguments += \"--url=`\"$connectionUrl`\"\"\n\n# Determine if the output variable needs to be set\nif ($liquibaseCommand.EndsWith(\"SQL\")) {\n # Add the output variable as the command name\n $liquibaseArguments += \"--outputFile=`\"$PSScriptRoot/artifacts/$($liquibaseCommand).sql`\"\"\n \n # Create the folder\n if ((Test-Path -Path \"$PSScriptRoot/artifacts\") -eq $false) {\n New-Item -Path \"$PSScriptRoot/artifacts\" -ItemType \"Directory\"\n }\n}\n\n\n# Add the additional switches\nforeach ($liquibaseSwitch in $liquibaseAdditionalSwitches) {\n $liquibaseArguments += $liquibaseSwitch\n}\n\nswitch ($liquibaseCommandStyle) {\n \"legacy\" {\n # Add the command to execute\n $liquibaseArguments += $liquibaseCommand\n }\n \"modern\" {\n # Insert the command at the beginning\n $liquibaseArguments = @($liquibaseCommand) + $liquibaseArguments\n }\n}\n\n# Add command arguments\n$liquibaseArguments += $liquibaseCommandArguments\n\n# Display what's going to be run\nif (![string]::IsNullOrWhitespace($liquibasePassword)) {\n $liquibaseDisplayArguments = $liquibaseArguments.PSObject.Copy()\n for ($i = 0; $i -lt $liquibaseDisplayArguments.Count; $i++) {\n if ($null -ne $liquibaseDisplayArguments[$i]) {\n if ($liquibaseDisplayArguments[$i].Contains($liquibasePassword)) {\n $liquibaseDisplayArguments[$i] = $liquibaseDisplayArguments[$i].Replace($liquibasePassword, \"****\")\n }\n }\n }\n \n Write-Host \"Executing the following command: $($liquibaseExecutable.FullName) $liquibaseDisplayArguments\"\n}\nelse {\n Write-Host \"Executing the following command: $($liquibaseExecutable.FullName) $liquibaseArguments\"\n}\n\n# Declare variable to hold output from Tee-Object\n$liquibaseCommandOutput;\n\n# Redirection of stderr to stdout is done different on Windows versus Linux\nif ($IsWindows) {\n $liquibaseArguments += \"2>&1\"\n # Execute Liquibase\n & $liquibaseExecutable.FullName $liquibaseArguments | Tee-Object -Variable liquibaseCommandOutput\n}\n\nif ($IsLinux) {\n # Execute Liquibase\n & $liquibaseExecutable.FullName $liquibaseArguments 2>&1 | Tee-Object -Variable liquibaseCommandOutput\n}\n\nSet-OctopusVariable -name \"LiquibaseCommandOutput\" -value $liquibaseCommandOutput\n\n# Check exit code\nif ($lastExitCode -ne 0) {\n # Fail the step\n Write-Error \"Execution of Liquibase failed!\"\n}\n\n# Check to see if there were any files output\nif ((Test-Path -Path \"$PSScriptRoot/artifacts\") -eq $true) {\n # Loop through items\n foreach ($item in (Get-ChildItem -Path \"$PSScriptRoot/artifacts\")) {\n New-OctopusArtifact -Path $item.FullName -Name $item.Name\n }\n}", + "Octopus.Action.Script.ScriptBody": "# Configure template\n\n# Check to see if $IsWindows is available\nif ($null -eq $IsWindows) {\n Write-Host \"Determining Operating System...\"\n $IsWindows = ([System.Environment]::OSVersion.Platform -eq \"Win32NT\")\n $IsLinux = ([System.Environment]::OSVersion.Platform -eq \"Unix\")\n}\n\n# Fix ANSI Color on PWSH Core issues when displaying objects\nif ($PSEdition -eq \"Core\") {\n $PSStyle.OutputRendering = \"PlainText\"\n}\n\n# Set TLS\n[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls11 -bor [System.Net.SecurityProtocolType]::Tls12\n\n# Downloads and extracts liquibase to the work folder\nFunction Get-Liquibase {\n # Define parameters\n param ($Version) \n\n $repositoryName = \"liquibase/liquibase\"\n\n # Check to see if version wasn't specified\n if ([string]::IsNullOrEmpty($Version)) {\n # Get the latest version download url\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".zip\") })\n }\n else {\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $Version | Where-Object { $_.EndsWith(\".zip\") })\n }\n\n # Extract the downloaded file\n Expand-DownloadedFile -DownloadUrls $downloadUrl | Out-Null\n \n # Parse downloaded version\n if ($downloadUrl -is [array]) {\n $downloadedFileName = [System.IO.Path]::GetFileName($downloadUrl[0])\n }\n else {\n $downloadedFileName = [System.IO.Path]::GetFileName($downloadUrl)\n }\n\n # Return the downloaded version\n return $downloadedFileName.SubString($downloadedFileName.IndexOf(\"-\") + 1).Replace(\".zip\", \"\") \n}\n\n# Downloads the files\nFunction Expand-DownloadedFile {\n # Define parameters\n param (\n $DownloadUrls\n )\n \n # Loop through results\n foreach ($url in $DownloadUrls) {\n # Download the zip file\n $folderName = [System.IO.Path]::GetFileName(\"$PSScriptroot/$($url.Substring($url.LastIndexOf(\"/\")))\").Replace(\".zip\", \"\")\n $zipFile = \"$PSScriptroot/$folderName/$($url.Substring($url.LastIndexOf(\"/\")))\"\n Write-Host \"Downloading $zipFile from $url ...\"\n \n if ((Test-Path -Path \"$PSScriptroot/$folderName\") -eq $false) {\n # Create folder\n New-Item -Path \"$PSScriptroot/$folderName/\" -ItemType Directory\n }\n\n # Download the zip file\n Invoke-WebRequest -Uri $url -OutFile $zipFile -UseBasicParsing | Out-Null\n\n # Extract package\n Write-Host \"Extracting $zipFile ...\"\n Expand-Archive -Path $zipFile -DestinationPath \"$PSSCriptRoot/$folderName\" | Out-Null\n }\n}\n\n\n# Downloads and extracts Java to the work folder, then adds the location of java.exe to the $env:PATH variabble so it can be called\nFunction Get-Java {\n # Check to see if a folder needs to be created\n if ((Test-Path -Path \"$PSScriptRoot/jdk\") -eq $false) {\n # Create new folder\n New-Item -ItemType Directory -Path \"$PSSCriptRoot/jdk\"\n }\n\n # Download java\n Write-Output \"Downloading Java ... \"\n \n # Determine OS\n if ($IsWindows) {\n Invoke-WebRequest -Uri \"https://download.java.net/java/GA/jdk14.0.2/205943a0976c4ed48cb16f1043c5c647/12/GPL/openjdk-14.0.2_windows-x64_bin.zip\" -OutFile \"$PSScriptroot/jdk/openjdk-14.0.2_windows-x64_bin.zip\" -UseBasicParsing\n\n # Extract\n Write-Output \"Extracting Java ... \"\n Expand-Archive -Path \"$PSScriptroot\\jdk\\openjdk-14.0.2_windows-x64_bin.zip\" -DestinationPath \"$PSSCriptRoot/jdk\"\n\n # Get Java executable\n $javaExecutable = Get-ChildItem -Path \"$PSScriptRoot\\jdk\" -Recurse | Where-Object { $_.Name -eq \"java.exe\" }\n }\n \n if ($IsLinux) {\n Invoke-WebRequest -Uri \"https://download.java.net/openjdk/jdk14/ri/openjdk-14+36_linux-x64_bin.tar.gz\" -OutFile \"$PSScriptroot/jdk/openjdk-14+36_linux-x64_bin.tar.gz\" -UseBasicParsing\n\n # Extract\n Write-Output \"Extracting Java ... \"\n tar -xvzf \"$PSScriptroot/jdk/openjdk-14+36_linux-x64_bin.tar.gz\" --directory \"$PSScriptRoot/jdk\"\n\n # Get Java executable\n $javaExecutable = Get-ChildItem -Path \"$PSScriptRoot/jdk\" -Recurse | Where-Object { $_.Name -eq \"java\" } \n }\n \n # Add path to current session as first entry to bypass other versions of Java that may be installed.\n $env:PATH = \"$($javaExecutable.Directory)$([IO.Path]::PathSeparator)\" + $env:PATH\n \n}\n\nFunction Get-DriverAssets {\n # Define parameters\n param (\n $DownloadInfo\n )\n\n # Declare working variables\n $assetFilePath = \"\"\n\n # Check to see if there are multiple assets to download\n if ($DownloadInfo -is [array]) {\n # Declare local variables\n $assetFiles = @()\n\n # Loop through array\n foreach ($url in $DownloadInfo) {\n # Download the asset\n Write-Host \"Downloading asset from $url...\"\n $assetPath = \"$PSScriptroot/$($url.Substring($url.LastIndexOf(\"/\")))\"\n \n # Skip test assets\n if ($assetPath.EndsWith(\"tests.jar\")) {\n Write-Host \"Asset is for testing, skipping ...\"\n continue\n }\n \n Invoke-WebRequest -Uri $url -Outfile $assetPath -UseBasicParsing\n $assetFiles += $assetPath\n }\n\n # Assign paths\n $assetFilePath = $assetFiles -join \"$([IO.Path]::PathSeparator)\"\n }\n else {\n # Download asset\n Write-Host \"Downloading asset from $DownloadInfo ...\"\n $assetFilePath = \"$PSScriptroot/$($DownloadInfo.Substring($DownloadInfo.LastIndexOf(\"/\")))\"\n Invoke-WebRequest -Uri $DownloadInfo -Outfile $assetFilePath -UseBasicParsing\n }\n\n # Return path\n return $assetFilePath\n}\n\n# Gets download url of latest release with an asset\nFunction Get-LatestVersionDownloadUrl {\n # Define parameters\n param(\n $Repository,\n $Version\n )\n \n # Define local variables\n $releases = \"https://api.github.com/repos/$Repository/releases\"\n \n # Get latest version\n Write-Host \"Determining latest release of $Repository ...\"\n \n $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)\n \n if ($null -ne $Version) {\n # Get specific version\n $tags = ($tags | Where-Object { $_.name.EndsWith($Version) })\n\n # Check to see if nothing was returned\n if ($null -eq $tags) {\n # Not found\n Write-Host \"No release found matching version $Version, getting highest version using Major.Minor syntax...\"\n\n # Get the tags\n $tags = (Invoke-WebRequest $releases -UseBasicParsing | ConvertFrom-Json)\n\n # Parse the version number into a version object\n $parsedVersion = [System.Version]::Parse($Version)\n $partialVersion = \"$($parsedVersion.Major).$($parsedVersion.Minor)\"\n \n # Filter tags to ones matching only Major.Minor of version specified\n $tags = ($tags | Where-Object { $_.name.Contains(\"$partialVersion.\") -and $_.draft -eq $false })\n \n # Grab the latest\n if ($null -eq $tags)\n {\n \t# decrement minor version\n $minorVersion = [int]$parsedVersion.Minor\n $minorVersion --\n \n # return the urls\n return (Get-LatestVersionDownloadUrl -Repository $Repository -Version \"$($parsedVersion.Major).$($minorVersion)\")\n }\n }\n }\n\n # Find the latest version with a downloadable asset\n foreach ($tag in $tags) {\n if ($tag.assets.Count -gt 0) {\n return $tag.assets.browser_download_url\n }\n }\n\n # Return the version\n return $null\n}\n\n# Finds the specified changelog file\nFunction Get-ChangeLog {\n # Define parameters\n param ($FileName)\n \n # Find file\n $fileReference = (Get-ChildItem -Path $OctopusParameters[\"Octopus.Action.Package[liquibaseChangeSet].ExtractedPath\"] -Recurse | Where-Object { $_.Name -eq $FileName })\n\n # Check to see if something weas returned\n if ($null -eq $fileReference) {\n # Not found\n Write-Error \"$FileName was not found in $PSScriptRoot or subfolders.\"\n }\n\n # Return the reference\n return $fileReference\n}\n\n# Downloads the appropriate JDBC driver\nFunction Get-DatabaseJar {\n # Define parameters\n param ($DatabaseType)\n\n # Declare local variables\n $driverPath = \"\"\n\n # Check to see if a folder needs to be created\n if ((Test-Path -Path \"$PSScriptRoot/DatabaseDriver\") -eq $false) {\n # Create new folder\n New-Item -ItemType Directory -Path \"$PSSCriptRoot/DatabaseDriver\" | Out-Null\n }\n\n # Download the driver for the selected type\n switch ($DatabaseType) {\n \"Cassandra\" {\n\n\t\t\t# Get the release download\n Write-Host \"Downloading Cassandra JDBC driver bundle ...\"\n\t\t\t$downloadUrl = Get-LatestVersionDownloadUrl -Repository \"ing-bank/cassandra-jdbc-wrapper\"\n \n # Find driver\n $driverPath = (Get-DriverAssets -DownloadInfo $downloadUrl)\n\n # Set repo name\n $repositoryName = \"liquibase/liquibase-cassandra\"\n \n if ([string]::IsNullOrEmpty($liquibaseVersion)) {\n # Get the latest version for the extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n \t}\n else {\n # Download version matching extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object { $_.EndsWith(\".jar\") })\n } \n\n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n\n break\n }\n \"DB2\" {\n # Use built-in driver\n $driverPath = $null\n break\n }\n \"MariaDB\" {\n # Download MariaDB driver\n Write-Host \"Downloading MariaDB driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/mariadb-java-client-2.6.2.jar\"\n Invoke-WebRequest -Uri \"https://downloads.mariadb.com/Connectors/java/connector-java-2.6.2/mariadb-java-client-2.6.2.jar\" -OutFile $driverPath -UseBasicParsing\n \n break\n }\n \"MongoDB\" {\n # Download MongoDB driver\n Write-Host \"Downloading Maven MongoDB driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/mongo-java-driver-3.12.7.jar\"\n Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/org/mongodb/mongo-java-driver/3.12.7/mongo-java-driver-3.12.7.jar\" -Outfile $driverPath -UseBasicParsing\n \n # Check to see if they are using a licenced version\n if (![string]::IsNullOrWhitespace($liquibaseProLicenseKey)) {\n # Set the paid version url\n $mongoVersions = Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-commercial-mongodb\" -UseBasicParsing\n \n # Loop through links, look for ones that evaluate to version\n $versions = @()\n foreach ($link in $mongoVersions.Links) {\n Write-Verbose \"Evaluating: $link\"\n if (![string]::IsNullOrWhitespace($link.title)) {\n # Get the inner text\n $versionNumber = $link.title.Replace(\"/\", \"\")\n\n # Check to see if $versionNumber can be parsed as a versionNumber\n $versionOut = $null\n if ([System.Version]::TryParse($versionNumber, [ref]$versionOut)) {\n $versions += $versionOut\n }\n }\n }\n\n # Get the highest version number\n $info = ($versions | Measure-Object -Maximum)\n\n $downloadUrl = \"https://repo1.maven.org/maven2/org/liquibase/ext/liquibase-commercial-mongodb/$($info.Maximum)/liquibase-commercial-mongodb-$($info.Maximum).jar\" \n }\n else {\n # Set repo name\n $repositoryName = \"liquibase/liquibase-mongodb\" \n \n # Download latest OSS version\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n }\n \n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n \n break\n }\n \"MySQL\" {\n # Download MariaDB driver\n Write-Host \"Downloading MySQL driver ...\"\n Invoke-WebRequest -Uri \"https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-8.0.28.zip\" -OutFile \"$PSScriptroot/DatabaseDriver/mysql-connector-java-8.0.28.zip\" -UseBasicParsing -UserAgent \"curl/7.8.3.1\"\n\n # Extract package\n Write-Host \"Extracting MySQL driver ...\"\n Expand-Archive -Path \"$PSScriptroot/DatabaseDriver/mysql-connector-java-8.0.28.zip\" -DestinationPath \"$PSSCriptRoot/DatabaseDriver\"\n\n # Find driver\n $driverPath = (Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mysql-connector-java-8.0.28.jar\" }).FullName\n\n break\n }\n \"Oracle\" {\n # Download Oracle driver\n Write-Host \"Downloading Oracle driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/ojdbc10.jar\"\n Invoke-WebRequest -Uri \"https://download.oracle.com/otn-pub/otn_software/jdbc/211/ojdbc11.jar\" -OutFile $driverPath -UseBasicParsing\n\n break\n }\n \"SqlServer\" {\n # Download Microsoft driver\n Write-Host \"Downloading Sql Server driver ...\"\n Invoke-WebRequest -Uri \"https://go.microsoft.com/fwlink/?linkid=2186163\" -OutFile \"$PSScriptroot/DatabaseDriver/sqljdbc_10.2.0.0_enu.zip\" -UseBasicParsing\n\n # Extract package\n Write-Host \"Extracting SqlServer driver ...\"\n Expand-Archive -Path \"$PSScriptroot/DatabaseDriver/sqljdbc_10.2.0.0_enu.zip\" -DestinationPath \"$PSSCriptRoot/DatabaseDriver\"\n\n # Find driver\n $driverPath = (Get-ChildItem -Path \"$PSSCriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc-10.2.0.jre11.jar\" }).FullName\n \n # Determine architecture\n if ([System.Environment]::Is64BitOperatingSystem) {\n # Locate auth dll\n $authDll = Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc_auth-10.2.0.x64.dll\" }\n }\n else {\n $authDll = Get-ChildItem -Path \"$PSScriptRoot/DatabaseDriver\" -Recurse | Where-Object { $_.Name -eq \"mssql-jdbc_auth-10.2.0.x86.dll\" }\n }\n \n # Add the dll to the path so it can find it.\n $env:PATH += \"$([IO.Path]::PathSeparator)$($authDll.Directory)\"\n \n break\n }\n \"PostgreSQL\" {\n # Download PostgreSQL driver\n Write-Host \"Downloading PostgreSQL driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/postgresql-42.2.12.jar\"\n Invoke-WebRequest -Uri \"https://jdbc.postgresql.org/download/postgresql-42.2.12.jar\" -OutFile $driverPath -UseBasicParsing\n \n # Download the WAFFLE jna driver for Windows Authentication\n $repositoryName = \"waffle/waffle\"\n \n # Latest version of Waffle (2.3.0) doesn't seem to work, can't find sspi method, specify version 1.9.0\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version \"1.9.0\" | Where-Object { $_.EndsWith(\".zip\") })\n Expand-DownloadedFile -DownloadUrls $downloadUrl | Out-Null\n \n # Get all waffle jars\n $waffleFolder = (Get-ChildItem -Path \"$PSScriptroot\" -Recurse | Where-Object { $_.PSIsContainer -and $_.Name -like \"Waffle*\" }) \n $waffleJars = (Get-ChildItem -Path $waffleFolder.FullName -Recurse | Where-Object { $_.Extension -eq \".jar\" })\n \n foreach ($jar in $waffleJars) {\n $driverPath += \"$([IO.Path]::PathSeparator)$($jar.FullName)\"\n }\n\n break\n }\n \"Snowflake\" {\n # Set repo name\n $repositoryName = \"liquibase/liquibase-snowflake\"\n\n # Download Snowflake driver\n Write-Host \"Downloading Snowflake driver ...\"\n $driverPath = \"$PSScriptroot/DatabaseDriver/snowflake-jdbc-3.9.2.jar\"\n Invoke-WebRequest -Uri \"https://repo1.maven.org/maven2/net/snowflake/snowflake-jdbc/3.9.2/snowflake-jdbc-3.9.2.jar\" -OutFile $driverPath -UseBasicParsing\n\n if ([string]::IsNullOrEmpty($liquibaseVersion)) {\n # Get the latest version for the extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName | Where-Object { $_.EndsWith(\".jar\") })\n \t}\n else {\n # Download version matching extension\n $downloadUrl = (Get-LatestVersionDownloadUrl -Repository $repositoryName -Version $liquibaseVersion | Where-Object { $_.EndsWith(\".jar\") })\n }\n \n $extensionPath = Get-DriverAssets -DownloadInfo $downloadUrl\n \n # Make driver path null\n $driverPath = \"$driverPath$([IO.Path]::PathSeparator)$extensionPath\"\n\n\n break\n }\n default {\n # Display error\n Write-Error \"Unknown database type: $DatabaseType.\"\n }\n }\n\n # Return the driver location\n return $driverPath\n}\n\n# Returns the connection string formatted for the database type\nFunction Get-ConnectionUrl {\n # Define parameters\n param ($DatabaseType, \n $ServerPort, \n $ServerName, \n $DatabaseName, \n $QueryStringParameters)\n\n # Define local variables\n $connectionUrl = \"\"\n\n # Download the driver for the selected type\n switch ($DatabaseType) {\n \"Cassandra\" {\n #$connectionUrl = \"jdbc:cassandra://{0}:{1};DefaultKeyspace={2}\"\n $connectionUrl = \"jdbc:cassandra://{0}:{1}/{2}\"\n break\n }\n \"DB2\" {\n $connectionUrl = \"jdbc:db2://{0}:{1}/{2}\"\n break\n }\n \"MariaDB\" {\n $connectionUrl = \"jdbc:mariadb://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?integratedSecurity=true\"\n }\n \n break\n }\n \"MongoDB\" { \n $connectionUrl = \"mongodb://{0}:{1}/{2}\" \n break\n }\n \"MySQL\" {\n \n $connectionUrl = \"jdbc:mysql://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?integratedSecurity=true\"\n }\n \n break\n }\n \"Oracle\" {\n $connectionUrl = \"jdbc:oracle:thin:@{0}:{1}/{2}\"\n break\n }\n \"SqlServer\" {\n $connectionUrl = \"jdbc:sqlserver://{0}:{1};database={2};\"\n \n switch ($liquibaseAuthenticationMethod) {\n \"azuremanagedidentity\" {\n # Add querystring parameter\n $connectionUrl += \"Authentication=ActiveDirectoryMSI;\"\n break\n }\n \"windowsauthentication\" {\n # Add querysting parameter\n $connectionUrl += \"integratedSecurity=true;\"\n \t\n break\n }\n }\n \n break\n }\n \"PostgreSQL\" {\n $connectionUrl = \"jdbc:postgresql://{0}:{1}/{2}\"\n \n # Check for Windows Authentication type\n if ($liquibaseAuthenticationMethod -eq \"windowsauthentication\") {\n # Add querysting parameter\n $connectionUrl += \"?gsslib=sspi\"\n }\n \n break\n }\n \"Snowflake\" {\n $connectionUrl = \"jdbc:snowflake://{0}.snowflakecomputing.com?db={2}\"\n break\n }\n default {\n # Display error\n Write-Error \"Unkonwn database type: $DatabaseType.\"\n }\n }\n\n if (![string]::IsNullOrWhitespace($QueryStringParameters)) { \t\n if ($connectionUrl.Contains(\"?\")) {\n \t# Replace the ? with & in connection string parameters\n $QueryStringParameters = $QueryStringParameters.Replace(\"?\", \"&\")\n }\n \n # Appen connecion string\n $connectionUrl += \"$QueryStringParameters\"\n }\n\n # Return the url\n return ($connectionUrl -f $ServerName, $ServerPort, $DatabaseName)\n}\n\n# Create array for arguments\n$liquibaseArguments = @()\n\n# Check to see if it's running on Windows\nif ($IsWindows) {\n # Disable the progress bar so downloading files via Invoke-WebRequest are faster\n $ProgressPreference = 'SilentlyContinue'\n}\n\n# Check for license key\nif (![string]::IsNullOrWhitespace($liquibaseProLicenseKey)) {\n # Add key to arguments\n $liquibaseArguments += \"--liquibaseProLicenseKey=$liquibaseProLicenseKey\"\n}\n\n# Find Change log\n$changeLogFile = (Get-ChangeLog -FileName $liquibaseChangeLogFileName)\n$liquibaseArguments += \"--changeLogFile=$($changeLogFile.Name)\"\n\n# Set the location to where the file is\nSet-Location -Path $changeLogFile.Directory\n\n# Check to see if it needs to be downloaed to machine\nif ($liquibaseDownload -eq $true) {\n # Download and extract liquibase - get the version for extensions that are version specific\n $liquibaseVersion = Get-Liquibase -Version $liquibaseVersion -DownloadFolder $workingFolder\n\n # Download and extract java and add it to PATH environment variable\n Get-Java\n\n # Get the driver\n $driverPath = Get-DatabaseJar -DatabaseType $liquibaseDatabaseType\n\n # Check to see if it's null\n if ($null -ne $driverPath) {\n # Create folder to hold jar files to override\n New-Item -Path \"$PWD/liquibase_libs/\" -ItemType Directory \n\n # Copy contents into liquibase_libs folder\n $driverPaths = $driverPath.Split([IO.Path]::PathSeparator)\n\n foreach ($driver in $driverPaths) {\n # Copy the items\n $files = Get-ChildItem -Path $driver\n\n foreach ($file in $files) {\n Write-Host \"Copying $($file.FullName) to $PWD/liquibase_libs/$($file.Name)\"\n Copy-Item -Path $file.FullName -Destination \"$PWD/liquibase_libs/$($file.Name)\"\n }\n }\n }\n}\nelse {\n if (![string]::IsNullOrEmpty($liquibaseClassPath)) {\n $liquibaseArguments += \"--classpath=$liquibaseClassPath\"\n }\n}\n\n# Check to see if liquibase path has been defined\nif ([string]::IsNullOrWhitespace($liquibaseExecutablePath)) {\n\n\tif ($env:IsContainer)\n {\n \t$liquibaseExecutablePath = \"/\"\t\n }\n else\n {\n \t# Assign root\n \t$liquibaseExecutablePath = $PSSCriptRoot\n }\n}\n\n# Get the executable location\nif ($IsWindows) {\n $liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object { $_.Name -eq \"liquibase.bat\" }\n}\n\nif ($IsLinux) {\n $liquibaseExecutable = Get-ChildItem -Path $liquibaseExecutablePath -Recurse | Where-Object { $_.Name -eq \"liquibase\" }\n}\n\n# Add path to current session\n$env:PATH += \"$([IO.Path]::PathSeparator)$($liquibaseExecutable.Directory)\"\n\n# Check to make sure it was found\nif ([string]::IsNullOrEmpty($liquibaseExecutable)) {\n # Could not find the executable\n Write-Error \"Unable to find liquibase.bat in $PSScriptRoot or subfolders.\"\n}\n\n# Get connection Url\n$connectionUrl = Get-ConnectionUrl -DatabaseType $liquibaseDatabaseType -ServerPort $liquibaseServerPort -ServerName $liquibaseServerName -DatabaseName $liquibaseDatabaseName -QueryStringParameters $liquibaseQueryStringParameters\n\n# Add username\n$liquibaseArguments += \"--username=$liquibaseUsername\"\n\n# Determine authentication method\nswitch ($liquibaseAuthenticationMethod) {\n \"azuremanagedidentity\" {\n # SQL Server driver doesn't assign password\n if ($liquibaseDatabaseType -ne \"SqlServer\") {\n # Get login token\n Write-Host \"Generating Azure Managed Identity token ...\"\n $token = Invoke-RestMethod -Method GET -Uri \"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://ossrdbms-aad.database.windows.net\" -Headers @{\"MetaData\" = \"true\" } -UseBasicParsing\n\n $liquibasePassword = $token.access_token\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n }\n }\n \"awsiam\" {\n # Region is part of the RDS endpoint, extract\n $region = ($liquibaseServerName.Split(\".\"))[2]\n\n Write-Host \"Generating AWS IAM token ...\"\n $liquibasePassword = (aws rds generate-db-auth-token --hostname $liquibaseServerName --region $region --port $liquibaseServerPort --username $liquibaseUsername)\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n\n break\n }\n \"gcpserviceaccount\" {\n # Define header\n $header = @{ \"Metadata-Flavor\" = \"Google\" }\n\n # Retrieve service accounts\n $serviceAccounts = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/\" -Headers $header -UseBasicParsing\n\n # Results returned in plain text format, get into array and remove empty entries\n $serviceAccounts = $serviceAccounts.Split([Environment]::NewLine, [StringSplitOptions]::RemoveEmptyEntries)\n\n # Retreive the specific service account assigned to the VM\n $serviceAccount = $serviceAccounts | Where-Object { $_.Contains(\"iam.gserviceaccount.com\") }\n\n Write-Host \"Generating GCP IAM token ...\"\n # Retrieve token for account\n $token = Invoke-RestMethod -Method Get -Uri \"http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/$serviceAccount/token\" -Headers $header -UseBasicParsing\n \n $liquibasePassword = $token.access_token\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n }\n \"usernamepassword\" {\n # Add password\n $liquibaseArguments += \"--password=`\"$liquibasePassword`\"\"\n \n break\n }\n}\n\n# Add connection url\n$liquibaseArguments += \"--url=`\"$connectionUrl`\"\"\n\n# Determine if the output variable needs to be set\nif ($liquibaseCommand.EndsWith(\"SQL\")) {\n # Add the output variable as the command name\n $liquibaseArguments += \"--outputFile=`\"$PSScriptRoot/artifacts/$($liquibaseCommand).sql`\"\"\n \n # Create the folder\n if ((Test-Path -Path \"$PSScriptRoot/artifacts\") -eq $false) {\n New-Item -Path \"$PSScriptRoot/artifacts\" -ItemType \"Directory\"\n }\n}\n\n\n# Add the additional switches\nforeach ($liquibaseSwitch in $liquibaseAdditionalSwitches) {\n $liquibaseArguments += $liquibaseSwitch\n}\n\nswitch ($liquibaseCommandStyle) {\n \"legacy\" {\n # Add the command to execute\n $liquibaseArguments += $liquibaseCommand\n }\n \"modern\" {\n # Insert the command at the beginning\n $liquibaseArguments = @($liquibaseCommand) + $liquibaseArguments\n }\n}\n\n# Add command arguments\n$liquibaseArguments += $liquibaseCommandArguments\n\n# Display what's going to be run\nif (![string]::IsNullOrWhitespace($liquibasePassword)) {\n $liquibaseDisplayArguments = $liquibaseArguments.PSObject.Copy()\n for ($i = 0; $i -lt $liquibaseDisplayArguments.Count; $i++) {\n if ($null -ne $liquibaseDisplayArguments[$i]) {\n if ($liquibaseDisplayArguments[$i].Contains($liquibasePassword)) {\n $liquibaseDisplayArguments[$i] = $liquibaseDisplayArguments[$i].Replace($liquibasePassword, \"****\")\n }\n }\n }\n \n Write-Host \"Executing the following command: $($liquibaseExecutable.FullName) $liquibaseDisplayArguments\"\n}\nelse {\n Write-Host \"Executing the following command: $($liquibaseExecutable.FullName) $liquibaseArguments\"\n}\n\n\n# Check to see if it's running in a container (this variable is provided by the build of the container itself)\nif ($env:IsContainer)\n{\n\t# Download any additional drivers based on the database technology being deployed to\n $driverPath = Get-DatabaseJar -DatabaseType $liquibaseDatabaseType\n\n # Check to see if it's null\n if ($null -ne $driverPath) {\n # Create folder to hold jar files to override\n New-Item -Path \"$PWD/liquibase_libs/\" -ItemType Directory \n\n # Copy contents into liquibase_libs folder\n $driverPaths = $driverPath.Split([IO.Path]::PathSeparator)\n\n foreach ($driver in $driverPaths) {\n # Copy the items\n $files = Get-ChildItem -Path $driver\n\n foreach ($file in $files) {\n Write-Host \"Copying $($file.FullName) to $PWD/liquibase_libs/$($file.Name)\"\n Copy-Item -Path $file.FullName -Destination \"$PWD/liquibase_libs/$($file.Name)\"\n }\n }\n }\n}\n\n\n\n# Declare variable to hold output from Tee-Object\n$liquibaseCommandOutput;\n\n# Redirection of stderr to stdout is done different on Windows versus Linux\nif ($IsWindows) {\n $liquibaseArguments += \"2>&1\"\n # Execute Liquibase\n & $liquibaseExecutable.FullName $liquibaseArguments | Tee-Object -Variable liquibaseCommandOutput\n}\n\nif ($IsLinux) {\n # Execute Liquibase\n & $liquibaseExecutable.FullName $liquibaseArguments 2>&1 | Tee-Object -Variable liquibaseCommandOutput\n}\n\nSet-OctopusVariable -name \"LiquibaseCommandOutput\" -value $liquibaseCommandOutput\n\n# Check exit code\nif ($lastExitCode -ne 0) {\n # Fail the step\n Write-Error \"Execution of Liquibase failed!\"\n}\n\n# Check to see if there were any files output\nif ((Test-Path -Path \"$PSScriptRoot/artifacts\") -eq $true) {\n # Loop through items\n foreach ($item in (Get-ChildItem -Path \"$PSScriptRoot/artifacts\")) {\n New-OctopusArtifact -Path $item.FullName -Name $item.Name\n }\n}", "Octopus.Action.Script.Syntax": "PowerShell" }, "Parameters": [