diff --git a/step-templates/ssis-deploy-ispac-from-package-parameter.json b/step-templates/ssis-deploy-ispac-from-package-parameter.json index a3c879890..b5a8b2d1f 100644 --- a/step-templates/ssis-deploy-ispac-from-package-parameter.json +++ b/step-templates/ssis-deploy-ispac-from-package-parameter.json @@ -3,7 +3,7 @@ "Name": "Deploy ispac SSIS project from a Package parameter", "Description": "This step template will deploy SSIS ispac projects to SQL Server Integration Services Catalog. The template uses a referenced package and is Worker compatible.\n\nThis template will install the Nuget package provider if it is not present on the machine it is running on.\n\nNOTE: The SqlServer PowerShell module this template utilizes removed the assemblies necessary to interface with SSIS as of version 22.0.59. Version 21.1.18256 has been pinned and will be used if the SqlServer PowerShell module is not installed.", "ActionType": "Octopus.Script", - "Version": 6, + "Version": 7, "Author": "twerthi", "Packages": [ { @@ -21,7 +21,7 @@ ], "Properties": { "Octopus.Action.Script.Syntax": "PowerShell", - "Octopus.Action.Script.ScriptBody": "#region Functions\n\n# Define functions\nfunction Get-SqlModuleInstalled\n{\n # Define parameters\n param(\n $PowerShellModuleName\n )\n\n # Check to see if the module is installed\n if ($null -ne (Get-Module -ListAvailable -Name $PowerShellModuleName))\n {\n # It is installed\n return $true\n }\n else\n {\n # Module not installed\n return $false\n }\n}\n\nfunction Get-NugetPackageProviderNotInstalled\n{\n\t# See if the nuget package provider has been installed\n return ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n}\n\nfunction Install-SqlServerPowerShellModule\n{\n # Define parameters\n param(\n $PowerShellModuleName,\n $LocalModulesPath\n )\n\n\t# Check to see if the package provider has been installed\n if ((Get-NugetPackageProviderNotInstalled) -ne $false)\n {\n \t# Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n \n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n\t# Save the module in the temporary location\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force -RequiredVersion \"21.1.18256\"\n\n\t# Display\n Write-Output \"Importing module $PowerShellModuleName ...\"\n\n # Import the module\n Import-Module -Name $PowerShellModuleName\n}\n\nFunction Load-SqlServerAssmblies\n{\n\t# Declare parameters\n \n\t# Get the folder where the SqlServer module ended up in\n\t$sqlServerModulePath = [System.IO.Path]::GetDirectoryName((Get-Module SqlServer).Path)\n \n # Loop through the assemblies\n foreach($assemblyFile in (Get-ChildItem -Path $sqlServerModulePath -Exclude msv*.dll | Where-Object {$_.Extension -eq \".dll\"}))\n {\n # Load the assembly\n [Reflection.Assembly]::LoadFile($assemblyFile.FullName) | Out-Null\n } \n}\n\n#region Get-Catalog\nFunction Get-Catalog\n{\n # define parameters\n Param ($CatalogName)\n # NOTE: using $integrationServices variable defined in main\n \n # define working varaibles\n $Catalog = $null\n # check to see if there are any catalogs\n if($integrationServices.Catalogs.Count -gt 0 -and $integrationServices.Catalogs[$CatalogName])\n {\n \t# get reference to catalog\n \t$Catalog = $integrationServices.Catalogs[$CatalogName]\n }\n else\n {\n \tif((Get-CLREnabled) -eq 0)\n \t{\n \t\tif(-not $EnableCLR)\n \t\t{\n \t\t\t# throw error\n \t\t\tthrow \"SQL CLR is not enabled.\"\n \t\t}\n \t\telse\n \t\t{\n \t\t\t# display sql clr isn't enabled\n \t\t\tWrite-Warning \"SQL CLR is not enabled on $($sqlConnection.DataSource). This feature must be enabled for SSIS catalogs.\"\n \n \t\t\t# enablign SQLCLR\n \t\t\tWrite-Host \"Enabling SQL CLR ...\"\n \t\t\tEnable-SQLCLR\n \t\t\tWrite-Host \"SQL CLR enabled\"\n \t\t}\n \t}\n \n \t# Provision a new SSIS Catalog\n \tWrite-Host \"Creating SSIS Catalog ...\"\n \n \t$Catalog = New-Object \"$ISNamespace.Catalog\" ($integrationServices, $CatalogName, $OctopusParameters['SSIS.Template.CatalogPwd'])\n \t$Catalog.Create()\n \n \n }\n \n # return the catalog\n return $Catalog\n}\n#endregion\n\n#region Get-CLREnabled\nFunction Get-CLREnabled\n{\n # define parameters\n # Not using any parameters, but am using $sqlConnection defined in main\n \n # define working variables\n $Query = \"SELECT * FROM sys.configurations WHERE name = 'clr enabled'\"\n \n # execute script\n $CLREnabled = Invoke-Sqlcmd -ServerInstance $sqlConnection.DataSource -Database \"master\" -Query $Query | Select value\n \n # return value\n return $CLREnabled.Value\n}\n#endregion\n\n#region Enable-SQLCLR\nFunction Enable-SQLCLR\n{\n $QueryArray = \"sp_configure 'show advanced options', 1\", \"RECONFIGURE\", \"sp_configure 'clr enabled', 1\", \"RECONFIGURE \"\n # execute script\n \n foreach($Query in $QueryArray)\n {\n \tInvoke-Sqlcmd -ServerInstance $sqlConnection.DataSource -Database \"master\" -Query $Query\n }\n \n # check that it's enabled\n if((Get-CLREnabled) -ne 1)\n {\n \t# throw error\n \tthrow \"Failed to enable SQL CLR\"\n }\n}\n#endregion\n\n#region Get-Folder\nFunction Get-Folder\n{\n # parameters\n Param($FolderName, $Catalog)\n \n $Folder = $null\n # try to get reference to folder\n \n if(!($Catalog.Folders -eq $null))\n {\n \t$Folder = $Catalog.Folders[$FolderName]\n }\n \n # check to see if $Folder has a value\n if($Folder -eq $null)\n {\n \t# display\n \tWrite-Host \"Folder $FolderName doesn't exist, creating folder...\"\n \n \t# create the folder\n \t$Folder = New-Object \"$ISNamespace.CatalogFolder\" ($Catalog, $FolderName, $FolderName) \n \t$Folder.Create() \n }\n \n # return the folde reference\n return $Folder\n}\n#endregion\n\n#region Get-Environment\nFunction Get-Environment\n{\n # define parameters\n Param($Folder, $EnvironmentName)\n \n $Environment = $null\n # get reference to Environment\n if(!($Folder.Environments -eq $null) -and $Folder.Environments.Count -gt 0)\n {\n \t$Environment = $Folder.Environments[$EnvironmentName]\n }\n \n # check to see if it's a null reference\n if($Environment -eq $null)\n {\n \t# display\n \tWrite-Host \"Environment $EnvironmentName doesn't exist, creating environment...\"\n \n \t# create environment\n \t$Environment = New-Object \"$ISNamespace.EnvironmentInfo\" ($Folder, $EnvironmentName, $EnvironmentName)\n \t$Environment.Create() \n }\n \n # return the environment\n return $Environment\n}\n#endregion\n\n#region Set-EnvironmentReference\nFunction Set-EnvironmentReference\n{\n # define parameters\n Param($Project, $Environment, $Folder)\n \n # get reference\n $Reference = $null\n \n if(!($Project.References -eq $null))\n {\n \t$Reference = $Project.References[$Environment.Name, $Folder.Name]\n \n }\n \n # check to see if it's a null reference\n if($Reference -eq $null)\n {\n \t# display\n \tWrite-Host \"Project does not reference environment $($Environment.Name), creating reference...\"\n \n \t# create reference\n \t$Project.References.Add($Environment.Name, $Folder.Name)\n \t$Project.Alter() \n }\n}\n#endregion\n\n#region Set-ProjectParametersToEnvironmentVariablesReference\nFunction Set-ProjectParametersToEnvironmentVariablesReference\n{\n # define parameters\n Param($Project, $Environment)\n \n $UpsertedVariables = @()\n\n if($Project.Parameters -eq $null)\n {\n Write-Host \"No project parameters exist\"\n return\n }\n\n # loop through project parameters\n foreach($Parameter in $Project.Parameters)\n {\n # skip if the parameter is included in custom filters\n if ($UseCustomFilter) \n {\n if ($Parameter.Name -match $CustomFilter)\n {\n Write-Host \"- $($Parameter.Name) skipped due to CustomFilters.\" \n continue\n }\n }\n\n # Add variable to list of variable\n $UpsertedVariables += $Parameter.Name\n\n $Variable = $null\n if(!($Environment.Variables -eq $null))\n {\n \t # get reference to variable\n \t $Variable = $Environment.Variables[$Parameter.Name]\n }\n \n \t# check to see if variable exists\n \tif($Variable -eq $null)\n \t{\n \t\t# add the environment variable\n \t\tAdd-EnvironmentVariable -Environment $Environment -Parameter $Parameter -ParameterName $Parameter.Name\n \n \t\t# get reference to the newly created variable\n \t\t$Variable = $Environment.Variables[$Parameter.Name]\n \t}\n \n \t# set the environment variable value\n \tSet-EnvironmentVariableValue -Variable $Variable -Parameter $Parameter -ParameterName $Parameter.Name\n }\n \n # alter the environment\n $Environment.Alter()\n $Project.Alter()\n\n return $UpsertedVariables\n}\n#endregion\n\nFunction Set-PackageVariablesToEnvironmentVariablesReference\n{\n # define parameters\n Param($Project, $Environment)\n\n $Variables = @()\n $UpsertedVariables = @()\n\n # loop through packages in project in order to store a temp collection of variables\n foreach($Package in $Project.Packages)\n {\n \t# loop through parameters of package\n \tforeach($Parameter in $Package.Parameters)\n \t{\n \t\t# add to the temporary variable collection\n \t\t$Variables += $Parameter.Name\n \t}\n }\n\n # loop through packages in project\n foreach($Package in $Project.Packages)\n {\n \t# loop through parameters of package\n \tforeach($Parameter in $Package.Parameters)\n \t{\n if ($UseFullyQualifiedVariableNames)\n {\n # Set fully qualified variable name\n $ParameterName = $Parameter.ObjectName.Replace(\".dtsx\", \"\")+\".\"+$Parameter.Name\n }\n else\n {\n # check if exists a variable with the same name\n $VariableNameOccurrences = $($Variables | Where-Object { $_ -eq $Parameter.Name }).count\n $ParameterName = $Parameter.Name\n \n if ($VariableNameOccurrences -gt 1)\n {\n $ParameterName = $Parameter.ObjectName.Replace(\".dtsx\", \"\")+\".\"+$Parameter.Name\n }\n }\n \n if ($UseCustomFilter)\n {\n if ($ParameterName -match $CustomFilter)\n {\n Write-Host \"- $($Parameter.Name) skipped due to CustomFilters.\" \n continue\n }\n }\n\n # get reference to variable\n \t\t$Variable = $Environment.Variables[$ParameterName]\n\n # Add variable to list of variable\n $UpsertedVariables += $ParameterName\n\n # check to see if the parameter exists\n \t\tif(!$Variable)\n \t\t{\n \t\t\t# add the environment variable\n \t\t\tAdd-EnvironmentVariable -Environment $Environment -Parameter $Parameter -ParameterName $ParameterName\n \n \t\t\t# get reference to the newly created variable\n \t\t\t$Variable = $Environment.Variables[$ParameterName]\n \t\t}\n \n \t\t# set the environment variable value\n \t\tSet-EnvironmentVariableValue -Variable $Variable -Parameter $Parameter -ParameterName $ParameterName\n \t}\n \n \t# alter the package\n \t$Package.Alter()\n }\n \n # alter the environment\n $Environment.Alter()\n\n return $UpsertedVariables\n}\n\nFunction Sync-EnvironmentVariables\n{\n # define parameters\n Param($Environment, $VariablesToPreserveInEnvironment)\n\n foreach($VariableToEvaluate in $Environment.Variables)\n {\n if ($VariablesToPreserveInEnvironment -notcontains $VariableToEvaluate.Name)\n {\n Write-Host \"- Removing environment variable: $($VariableToEvaluate.Name)\"\n $VariableToRemove = $Environment.Variables[$VariableToEvaluate.Name]\n $Environment.Variables.Remove($VariableToRemove) | Out-Null\n }\n }\n\n # alter the environment\n $Environment.Alter()\n}\n\n#region Add-EnvironmentVariable\nFunction Add-EnvironmentVariable\n{\n # define parameters\n Param($Environment, $Parameter, $ParameterName)\n \n # display \n Write-Host \"- Adding environment variable $($ParameterName)\"\n \n # check to see if design default value is emtpy or null\n if([string]::IsNullOrEmpty($Parameter.DesignDefaultValue))\n {\n \t# give it something\n \t$DefaultValue = \"\" # sensitive variables will not return anything so when trying to use the property of $Parameter.DesignDefaultValue, the Alter method will fail.\n }\n else\n {\n \t# take the design\n \t$DefaultValue = $Parameter.DesignDefaultValue\n }\n \n # add variable with an initial value\n $Environment.Variables.Add($ParameterName, $Parameter.DataType, $DefaultValue, $Parameter.Sensitive, $Parameter.Description)\n}\n#endregion\n\n#region Set-EnvironmentVariableValue\nFunction Set-EnvironmentVariableValue\n{\n # define parameters\n Param($Variable, $Parameter, $ParameterName)\n\n # check to make sure variable value is available\n if($OctopusParameters -and $OctopusParameters.ContainsKey($ParameterName))\n {\n # display \n Write-Host \"- Updating environment variable $($ParameterName)\"\n\n \t# set the variable value\n \t$Variable.Value = $OctopusParameters[\"$($ParameterName)\"]\n }\n else\n {\n \t# warning\n \tWrite-Host \"**- OctopusParameters collection is empty or $($ParameterName) not in the collection -**\"\n }\n \n # Set reference\n $Parameter.Set([Microsoft.SqlServer.Management.IntegrationServices.ParameterInfo+ParameterValueType]::Referenced, \"$($ParameterName)\")\n}\n#endregion\n\n# Define PowerShell Modules path\n$LocalModules = (New-Item \"$PSScriptRoot\\Modules\" -ItemType Directory -Force).FullName\n$env:PSModulePath = \"$LocalModules;$env:PSModulePath\"\n\n# Check to see if SqlServer module is installed\nif ((Get-SqlModuleInstalled -PowerShellModuleName \"SqlServer\") -ne $true)\n{\n\t# Display message\n Write-Output \"PowerShell module SqlServer not present, downloading temporary copy ...\"\n\n\t#Enable TLS 1.2 as default protocol\n\t[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12\n\n # Download and install temporary copy\n Install-SqlServerPowerShellModule -PowerShellModuleName \"SqlServer\" -LocalModulesPath $LocalModules\n \n}\nelse\n{\n\t# Import the module\n Import-Module -Name SqlServer\n}\n\n#region Dependent assemblies\nLoad-SqlServerAssmblies \n\n#endregion\n\n# Store the IntegrationServices Assembly namespace to avoid typing it every time\n$ISNamespace = \"Microsoft.SqlServer.Management.IntegrationServices\"\n\n#endregion\n\n#region Main\ntry\n{ \n # ensure all boolean variables are true booleans\n $EnableCLR = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.EnableCLR'])\")\n $UseEnvironment = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseEnvironment'])\")\n $ReferenceProjectParametersToEnvironmentVairables = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.ReferenceProjectParametersToEnvironmentVairables'])\")\n \n $ReferencePackageParametersToEnvironmentVairables = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.ReferencePackageParametersToEnvironmentVairables'])\")\n $UseFullyQualifiedVariableNames = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseFullyQualifiedVariableNames'])\")\n $SyncEnvironment = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.SyncEnvironment'])\")\n # custom names for filtering out the excluded variables by design\n $UseCustomFilter = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseCustomFilter'])\")\n $CustomFilter = [System.Convert]::ToString(\"$($OctopusParameters['SSIS.Template.CustomFilter'])\")\n # list of variables names to keep in target environment\n $VariablesToPreserveInEnvironment = @()\n $ssisPackageId = $OctopusParameters['SSIS.Template.ssisPackageId']\n \n\t# Get the extracted path\n\t$DeployedPath = $OctopusParameters[\"Octopus.Action.Package[$ssisPackageId].ExtractedPath\"]\n \n\t# Get all .ispac files from the deployed path\n\t$IsPacFiles = Get-ChildItem -Recurse -Path $DeployedPath | Where {$_.Extension.ToLower() -eq \".ispac\"}\n\n\t# display number of files\n\tWrite-Host \"$($IsPacFiles.Count) .ispac file(s) found.\"\n\n\tWrite-Host \"Connecting to server ...\"\n\n\t# Create a connection to the server\n $sqlConnectionString = \"Data Source=$($OctopusParameters['SSIS.Template.ServerName']);Initial Catalog=SSISDB;\"\n \n if (![string]::IsNullOrEmpty($OctopusParameters['SSIS.Template.sqlAccountUsername']) -and ![string]::IsNullOrEmpty($OctopusParameters['SSIS.Template.sqlAccountPassword']))\n {\n \t# Add username and password to connection string\n $sqlConnectionString += \"User ID=$($OctopusParameters['SSIS.Template.sqlAccountUsername']); Password=$($OctopusParameters['SSIS.Template.sqlAccountPassword']);\"\n }\n else\n {\n \t# Use integrated\n $sqlConnectionString += \"Integrated Security=SSPI;\"\n }\n \n \n # Create new connection object with connection string\n $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString\n\n\t# create integration services object\n\t$integrationServices = New-Object \"$ISNamespace.IntegrationServices\" $sqlConnection\n\n\t# get reference to the catalog\n\tWrite-Host \"Getting reference to catalog $($OctopusParameters['SSIS.Template.CataLogName'])\"\n\t$Catalog = Get-Catalog -CatalogName $OctopusParameters['SSIS.Template.CataLogName']\n\n\t# get folder reference\n\t$Folder = Get-Folder -FolderName $OctopusParameters['SSIS.Template.FolderName'] -Catalog $Catalog\n\n\t# loop through ispac files\n\tforeach($IsPacFile in $IsPacFiles)\n\t{\n\t\t# read project file\n\t\t$ProjectFile = [System.IO.File]::ReadAllBytes($IsPacFile.FullName)\n $ProjectName = $IsPacFile.Name.SubString(0, $IsPacFile.Name.LastIndexOf(\".\"))\n\n\t\t# deploy project\n\t\tWrite-Host \"Deploying project $($IsPacFile.Name)...\"\n\t\t$Folder.DeployProject($ProjectName, $ProjectFile) | Out-Null\n\n\t\t# get reference to deployed project\n\t\t$Project = $Folder.Projects[$ProjectName]\n\n\t\t# check to see if they want to use environments\n\t\tif($UseEnvironment)\n\t\t{\n\t\t\t# get environment reference\n\t\t\t$Environment = Get-Environment -Folder $Folder -EnvironmentName $OctopusParameters['SSIS.Template.EnvironmentName']\n\n\t\t\t# set environment reference\n\t\t\tSet-EnvironmentReference -Project $Project -Environment $Environment -Folder $Folder\n\n\t\t\t# check to see if the user wants to convert project parameters to environment variables\n\t\t\tif($ReferenceProjectParametersToEnvironmentVairables)\n\t\t\t{\n\t\t\t\t# set environment variables\n\t\t\t\tWrite-Host \"Referencing Project Parameters to Environment Variables...\"\n\t\t\t\t$VariablesToPreserveInEnvironment += Set-ProjectParametersToEnvironmentVariablesReference -Project $Project -Environment $Environment\n\t\t\t}\n\n\t\t\t# check to see if the user wants to convert the package parameters to environment variables\n\t\t\tif($ReferencePackageParametersToEnvironmentVairables)\n\t\t\t{\n\t\t\t\t# set package variables\n\t\t\t\tWrite-Host \"Referencing Package Parameters to Environment Variables...\"\n\t\t\t\t$VariablesToPreserveInEnvironment += Set-PackageVariablesToEnvironmentVariablesReference -Project $Project -Environment $Environment\n\t\t\t}\n \n # Removes all unused variables from the environment\n if ($SyncEnvironment)\n {\n Write-Host \"Sync package environment variables...\"\n Sync-EnvironmentVariables -Environment $Environment -VariablesToPreserveInEnvironment $VariablesToPreserveInEnvironment\n }\n\t\t}\n\t}\n}\n\nfinally\n{\n\t# check to make sure sqlconnection isn't null\n\tif($sqlConnection)\n\t{\n\t\t# check state of sqlconnection\n\t\tif($sqlConnection.State -eq [System.Data.ConnectionState]::Open)\n\t\t{\n\t\t\t# close the connection\n\t\t\t$sqlConnection.Close()\n\t\t}\n\n\t\t# cleanup\n\t\t$sqlConnection.Dispose()\n\t}\n}\n#endregion\n", + "Octopus.Action.Script.ScriptBody": "function Add-TemporaryPinnedSqlServerModule\n{\n # Define parameters\n param(\n $LocalModulesPath\n )\n\n $PowerShellModuleName = \"SqlServer\"\n $RequiredVersion = [version]'21.1.18256'\n\n # Check to see if the package provider has been installed\n if ($null -eq (Get-PackageProvider -ListAvailable -Name Nuget -ErrorAction SilentlyContinue))\n {\n # Display that we need the nuget package provider\n Write-Host \"Nuget package provider not found, installing ...\"\n\n # Install Nuget package provider\n Install-PackageProvider -Name Nuget -Force\n }\n\n # Save the module in the temporary location\n Save-Module -Name $PowerShellModuleName -Path $LocalModulesPath -Force -RequiredVersion $RequiredVersion -Repository \"PSGallery\"\n\n # Display\n Write-Output \"Saved module $PowerShellModuleName v$RequiredVersion to $LocalModulesPath\"\n\n # Import the module\n Import-Module -Name $PowerShellModuleName\n}\n\nFunction Remove-TemporaryPinnedSqlServerModule\n{\n param(\n [Parameter(Mandatory = $true)][string]$LocalModulesPath,\n [Parameter(Mandatory = $true)][version]$PinnedVersion\n )\n\n try { Remove-Module SqlServer -Force -ErrorAction SilentlyContinue } catch {}\n\n $moduleRoot = Join-Path $LocalModulesPath 'SqlServer'\n $pinnedPath = Join-Path $moduleRoot $PinnedVersion.ToString()\n\n if (Test-Path $pinnedPath)\n {\n Write-Host \"Removing temporary pinned SqlServer module folder: $pinnedPath\"\n Remove-Item -Path $pinnedPath -Recurse -Force -ErrorAction SilentlyContinue\n }\n\n # Optional: remove parent if empty\n if (Test-Path $moduleRoot)\n {\n $remaining = Get-ChildItem -Path $moduleRoot -Force -ErrorAction SilentlyContinue\n if (-not $remaining)\n {\n Remove-Item -Path $moduleRoot -Force -ErrorAction SilentlyContinue\n }\n }\n}\n\nFunction Test-IntegrationServicesTypeAvailable\n{\n # True if the IntegrationServices type resolves in this PowerShell session, else false\n $typeName = 'Microsoft.SqlServer.Management.IntegrationServices.IntegrationServices'\n $aqn = \"$typeName, Microsoft.SqlServer.Management.IntegrationServices\"\n\n try\n {\n if ([Type]::GetType($aqn, $false)) { return $true }\n }\n catch {}\n\n # Try to load assembly (strong name), may fail on some boxes\n try { [void][Reflection.Assembly]::Load('Microsoft.SqlServer.Management.IntegrationServices') } catch {}\n\n try\n {\n if ([Type]::GetType($aqn, $false)) { return $true }\n }\n catch {}\n\n # Fall back to explicit GAC path load (LoadFrom) if present\n $gacRoot = Join-Path $env:windir 'Microsoft.NET\\assembly\\GAC_MSIL\\Microsoft.SqlServer.Management.IntegrationServices'\n if (Test-Path $gacRoot)\n {\n $gacDll = Get-ChildItem -Path $gacRoot -Recurse -Filter 'Microsoft.SqlServer.Management.IntegrationServices.dll' -File -ErrorAction SilentlyContinue |\n Sort-Object FullName -Descending |\n Select-Object -First 1\n\n if ($gacDll)\n {\n try\n {\n $asm = [Reflection.Assembly]::LoadFrom($gacDll.FullName)\n if ($asm.GetType('Microsoft.SqlServer.Management.IntegrationServices.IntegrationServices', $false)) { return $true }\n }\n catch {}\n }\n }\n\n try\n {\n if ([Type]::GetType($aqn, $false)) { return $true }\n }\n catch {}\n\n return $false\n}\n\nFunction Load-SqlServerAssemblies\n{\n # Get the folder where the SqlServer module ended up in\n $sqlServerModulePath = [System.IO.Path]::GetDirectoryName((Get-Module SqlServer).Path)\n\n # Loop through the assemblies\n foreach($assemblyFile in (Get-ChildItem -Path $sqlServerModulePath -Exclude msv*.dll | Where-Object {$_.Extension -eq \".dll\"}))\n {\n try\n {\n # Only load managed .NET assemblies (native DLLs will throw)\n [void][System.Reflection.AssemblyName]::GetAssemblyName($assemblyFile.FullName)\n\n # Load the managed assembly\n [Reflection.Assembly]::LoadFrom($assemblyFile.FullName) | Out-Null\n }\n catch [System.BadImageFormatException]\n {\n # Native DLL (or wrong format), skip\n }\n }\n}\n\nFunction Initialize-SsisDeploymentRuntime\n{\n param(\n [Parameter(Mandatory = $true)][string]$LocalModulesPath,\n [Parameter(Mandatory = $true)][version]$PinnedSqlServerVersion\n )\n\n # Define PowerShell Modules path\n $env:PSModulePath = \"$LocalModulesPath;$env:PSModulePath\"\n\n $runtime = [pscustomobject]@{\n UsedPinnedSqlServerModule = $false\n SsisTypeAvailable = $false\n }\n\n # First preference: use SSIS assemblies already available on the machine/session\n $runtime.SsisTypeAvailable = Test-IntegrationServicesTypeAvailable\n\n if ($runtime.SsisTypeAvailable)\n {\n Write-Host \"SSIS IntegrationServices type is already available.\"\n\n # Only need a SqlServer module for cmdlets such as Invoke-Sqlcmd\n if ($null -ne (Get-Module -ListAvailable -Name \"SqlServer\"))\n {\n Import-Module -Name SqlServer -ErrorAction Stop\n }\n else\n {\n Write-Output \"PowerShell module SqlServer not present, downloading temporary pinned copy for cmdlets ...\"\n [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12\n\n Add-TemporaryPinnedSqlServerModule -LocalModulesPath $LocalModulesPath\n\n $manifestPath = Join-Path (Join-Path (Join-Path $LocalModulesPath 'SqlServer') $PinnedSqlServerVersion.ToString()) 'SqlServer.psd1'\n Write-Host \"Importing pinned SqlServer module from: $manifestPath\"\n Import-Module -Name $manifestPath -Force -DisableNameChecking -ErrorAction Stop\n\n $runtime.UsedPinnedSqlServerModule = $true\n }\n\n # SSIS type already resolved, no need to bulk-load module assemblies\n return $runtime\n }\n\n # Second preference: fall back to pinned SqlServer module that still contains SSIS assemblies\n Write-Output \"SSIS IntegrationServices type not available via installed components. Downloading pinned SqlServer module $PinnedSqlServerVersion temporarily ...\"\n [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12\n\n $manifestPath = Join-Path (Join-Path (Join-Path $LocalModulesPath 'SqlServer') $PinnedSqlServerVersion.ToString()) 'SqlServer.psd1'\n if (-not (Test-Path $manifestPath))\n {\n Add-TemporaryPinnedSqlServerModule -LocalModulesPath $LocalModulesPath\n }\n\n Write-Host \"Importing pinned SqlServer module from: $manifestPath\"\n Import-Module -Name $manifestPath -Force -DisableNameChecking -ErrorAction Stop\n Load-SqlServerAssemblies\n\n $runtime.UsedPinnedSqlServerModule = $true\n $runtime.SsisTypeAvailable = Test-IntegrationServicesTypeAvailable\n\n return $runtime\n}\n\nFunction Get-Catalog\n{\n # define parameters\n Param ($CatalogName)\n # NOTE: using $integrationServices variable defined in main\n\n # define working variables\n $Catalog = $null\n # check to see if there are any catalogs\n if($integrationServices.Catalogs.Count -gt 0 -and $integrationServices.Catalogs[$CatalogName])\n {\n # get reference to catalog\n $Catalog = $integrationServices.Catalogs[$CatalogName]\n }\n else\n {\n if((Get-CLREnabled) -eq 0)\n {\n if(-not $EnableCLR)\n {\n # throw error\n throw \"SQL CLR is not enabled.\"\n }\n else\n {\n # display sql clr isn't enabled\n Write-Warning \"SQL CLR is not enabled on $($sqlConnection.DataSource). This feature must be enabled for SSIS catalogs.\"\n\n # enabling SQLCLR\n Write-Host \"Enabling SQL CLR ...\"\n Enable-SQLCLR\n Write-Host \"SQL CLR enabled\"\n }\n }\n\n # Provision a new SSIS Catalog\n Write-Host \"Creating SSIS Catalog ...\"\n\n $Catalog = New-Object \"$ISNamespace.Catalog\" ($integrationServices, $CatalogName, $OctopusParameters['SSIS.Template.CatalogPwd'])\n $Catalog.Create()\n }\n\n # return the catalog\n return $Catalog\n}\n\nFunction Get-CLREnabled\n{\n # define parameters\n # Not using any parameters, but am using $sqlConnection defined in main\n\n # define working variables\n $Query = \"SELECT * FROM sys.configurations WHERE name = 'clr enabled'\"\n\n # execute script\n $CLREnabled = Invoke-Sqlcmd -ServerInstance $sqlConnection.DataSource -Database \"master\" -Query $Query | Select value\n\n # return value\n return $CLREnabled.Value\n}\n\nFunction Enable-SQLCLR\n{\n $QueryArray = \"sp_configure 'show advanced options', 1\", \"RECONFIGURE\", \"sp_configure 'clr enabled', 1\", \"RECONFIGURE \"\n # execute script\n\n foreach($Query in $QueryArray)\n {\n Invoke-Sqlcmd -ServerInstance $sqlConnection.DataSource -Database \"master\" -Query $Query\n }\n\n # check that it's enabled\n if((Get-CLREnabled) -ne 1)\n {\n # throw error\n throw \"Failed to enable SQL CLR\"\n }\n}\n\nFunction Get-Folder\n{\n # parameters\n Param($FolderName, $Catalog)\n\n $Folder = $null\n # try to get reference to folder\n\n if(!($Catalog.Folders -eq $null))\n {\n $Folder = $Catalog.Folders[$FolderName]\n }\n\n # check to see if $Folder has a value\n if($Folder -eq $null)\n {\n # display\n Write-Host \"Folder $FolderName doesn't exist, creating folder...\"\n\n # create the folder\n $Folder = New-Object \"$ISNamespace.CatalogFolder\" ($Catalog, $FolderName, $FolderName)\n $Folder.Create()\n }\n\n # return the folder reference\n return $Folder\n}\n\nFunction Get-Environment\n{\n # define parameters\n Param($Folder, $EnvironmentName)\n\n $Environment = $null\n # get reference to Environment\n if(!($Folder.Environments -eq $null) -and $Folder.Environments.Count -gt 0)\n {\n $Environment = $Folder.Environments[$EnvironmentName]\n }\n\n # check to see if it's a null reference\n if($Environment -eq $null)\n {\n # display\n Write-Host \"Environment $EnvironmentName doesn't exist, creating environment...\"\n\n # create environment\n $Environment = New-Object \"$ISNamespace.EnvironmentInfo\" ($Folder, $EnvironmentName, $EnvironmentName)\n $Environment.Create()\n }\n\n # return the environment\n return $Environment\n}\n\nFunction Set-EnvironmentReference\n{\n # define parameters\n Param($Project, $Environment, $Folder)\n\n # get reference\n $Reference = $null\n\n if(!($Project.References -eq $null))\n {\n $Reference = $Project.References[$Environment.Name, $Folder.Name]\n }\n\n # check to see if it's a null reference\n if($Reference -eq $null)\n {\n # display\n Write-Host \"Project does not reference environment $($Environment.Name), creating reference...\"\n\n # create reference\n $Project.References.Add($Environment.Name, $Folder.Name)\n $Project.Alter()\n }\n}\n\nFunction Set-ProjectParametersToEnvironmentVariablesReference\n{\n # define parameters\n Param($Project, $Environment)\n\n $UpsertedVariables = @()\n\n if($Project.Parameters -eq $null)\n {\n Write-Host \"No project parameters exist\"\n return\n }\n\n # loop through project parameters\n foreach($Parameter in $Project.Parameters)\n {\n # skip if the parameter is included in custom filters\n if ($UseCustomFilter)\n {\n if ($Parameter.Name -match $CustomFilter)\n {\n Write-Host \"- $($Parameter.Name) skipped due to CustomFilters.\"\n continue\n }\n }\n\n # Add variable to list of variable\n $UpsertedVariables += $Parameter.Name\n\n $Variable = $null\n if(!($Environment.Variables -eq $null))\n {\n # get reference to variable\n $Variable = $Environment.Variables[$Parameter.Name]\n }\n\n # check to see if variable exists\n if($Variable -eq $null)\n {\n # add the environment variable\n Add-EnvironmentVariable -Environment $Environment -Parameter $Parameter -ParameterName $Parameter.Name\n\n # get reference to the newly created variable\n $Variable = $Environment.Variables[$Parameter.Name]\n }\n\n # set the environment variable value\n Set-EnvironmentVariableValue -Variable $Variable -Parameter $Parameter -ParameterName $Parameter.Name\n }\n\n # alter the environment\n $Environment.Alter()\n $Project.Alter()\n\n return $UpsertedVariables\n}\n\nFunction Set-PackageVariablesToEnvironmentVariablesReference\n{\n # define parameters\n Param($Project, $Environment)\n\n $Variables = @()\n $UpsertedVariables = @()\n\n # loop through packages in project in order to store a temp collection of variables\n foreach($Package in $Project.Packages)\n {\n # loop through parameters of package\n foreach($Parameter in $Package.Parameters)\n {\n # add to the temporary variable collection\n $Variables += $Parameter.Name\n }\n }\n\n # loop through packages in project\n foreach($Package in $Project.Packages)\n {\n # loop through parameters of package\n foreach($Parameter in $Package.Parameters)\n {\n if ($UseFullyQualifiedVariableNames)\n {\n # Set fully qualified variable name\n $ParameterName = $Parameter.ObjectName.Replace(\".dtsx\", \"\")+\".\"+$Parameter.Name\n }\n else\n {\n # check if exists a variable with the same name\n $VariableNameOccurrences = $($Variables | Where-Object { $_ -eq $Parameter.Name }).count\n $ParameterName = $Parameter.Name\n\n if ($VariableNameOccurrences -gt 1)\n {\n $ParameterName = $Parameter.ObjectName.Replace(\".dtsx\", \"\")+\".\"+$Parameter.Name\n }\n }\n\n if ($UseCustomFilter)\n {\n if ($ParameterName -match $CustomFilter)\n {\n Write-Host \"- $($Parameter.Name) skipped due to CustomFilters.\"\n continue\n }\n }\n\n # get reference to variable\n $Variable = $Environment.Variables[$ParameterName]\n\n # Add variable to list of variable\n $UpsertedVariables += $ParameterName\n\n # check to see if the parameter exists\n if(!$Variable)\n {\n # add the environment variable\n Add-EnvironmentVariable -Environment $Environment -Parameter $Parameter -ParameterName $ParameterName\n\n # get reference to the newly created variable\n $Variable = $Environment.Variables[$ParameterName]\n }\n\n # set the environment variable value\n Set-EnvironmentVariableValue -Variable $Variable -Parameter $Parameter -ParameterName $ParameterName\n }\n\n # alter the package\n $Package.Alter()\n }\n\n # alter the environment\n $Environment.Alter()\n\n return $UpsertedVariables\n}\n\nFunction Sync-EnvironmentVariables\n{\n # define parameters\n Param($Environment, $VariablesToPreserveInEnvironment)\n\n foreach($VariableToEvaluate in $Environment.Variables)\n {\n if ($VariablesToPreserveInEnvironment -notcontains $VariableToEvaluate.Name)\n {\n Write-Host \"- Removing environment variable: $($VariableToEvaluate.Name)\"\n $VariableToRemove = $Environment.Variables[$VariableToEvaluate.Name]\n $Environment.Variables.Remove($VariableToRemove) | Out-Null\n }\n }\n\n # alter the environment\n $Environment.Alter()\n}\n\nFunction Add-EnvironmentVariable\n{\n # define parameters\n Param($Environment, $Parameter, $ParameterName)\n\n # display\n Write-Host \"- Adding environment variable $($ParameterName)\"\n\n # check to see if design default value is empty or null\n if([string]::IsNullOrEmpty($Parameter.DesignDefaultValue))\n {\n # give it something\n $DefaultValue = \"\" # sensitive variables will not return anything so when trying to use the property of $Parameter.DesignDefaultValue, the Alter method will fail.\n }\n else\n {\n # take the design\n $DefaultValue = $Parameter.DesignDefaultValue\n }\n\n # add variable with an initial value\n $Environment.Variables.Add($ParameterName, $Parameter.DataType, $DefaultValue, $Parameter.Sensitive, $Parameter.Description)\n}\n\nFunction Set-EnvironmentVariableValue\n{\n # define parameters\n Param($Variable, $Parameter, $ParameterName)\n\n # check to make sure variable value is available\n if (-not $OctopusParameters){\n Write-Host \"[WARN] - OctopusParameters collection is empty\"\n }\n else\n {\n if($OctopusParameters.ContainsKey($ParameterName))\n {\n # display\n Write-Host \"[ OK ] - $($ParameterName) updated.\"\n\n # set the variable value\n $Variable.Value = $OctopusParameters[\"$($ParameterName)\"]\n }\n else\n {\n # warning\n Write-Host \"[WARN] - $($ParameterName) not in OctopusParameters collection.\"\n }\n }\n\n # Set reference\n $Parameter.Set([Microsoft.SqlServer.Management.IntegrationServices.ParameterInfo+ParameterValueType]::Referenced, \"$($ParameterName)\")\n}\n\nFunction Invoke-SsisProjectDeployment\n{\n $LocalModules = (New-Item \"$PSScriptRoot\\Modules\" -ItemType Directory -Force).FullName\n $pinnedSqlServerVersion = [version]'21.1.18256'\n $sqlConnection = $null\n $runtime = $null\n\n try\n {\n $runtime = Initialize-SsisDeploymentRuntime -LocalModulesPath $LocalModules -PinnedSqlServerVersion $pinnedSqlServerVersion\n\n # Store the IntegrationServices Assembly namespace to avoid typing it every time\n $ISNamespace = \"Microsoft.SqlServer.Management.IntegrationServices\"\n\n # ensure all boolean variables are true booleans\n $EnableCLR = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.EnableCLR'])\")\n $UseEnvironment = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseEnvironment'])\")\n $ReferenceProjectParametersToEnvironmentVairables = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.ReferenceProjectParametersToEnvironmentVairables'])\")\n\n $ReferencePackageParametersToEnvironmentVairables = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.ReferencePackageParametersToEnvironmentVairables'])\")\n $UseFullyQualifiedVariableNames = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseFullyQualifiedVariableNames'])\")\n $SyncEnvironment = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.SyncEnvironment'])\")\n # custom names for filtering out the excluded variables by design\n $UseCustomFilter = [System.Convert]::ToBoolean(\"$($OctopusParameters['SSIS.Template.UseCustomFilter'])\")\n $CustomFilter = [System.Convert]::ToString(\"$($OctopusParameters['SSIS.Template.CustomFilter'])\")\n # list of variables names to keep in target environment\n $VariablesToPreserveInEnvironment = @()\n $ssisPackageId = $OctopusParameters['SSIS.Template.ssisPackageId']\n\n # Get the extracted path\n $DeployedPath = $OctopusParameters[\"Octopus.Action.Package[$ssisPackageId].ExtractedPath\"]\n\n # Get all .ispac files from the deployed path\n $IsPacFiles = Get-ChildItem -Recurse -Path $DeployedPath | Where {$_.Extension.ToLower() -eq \".ispac\"}\n\n # display number of files\n Write-Host \"$($IsPacFiles.Count) .ispac file(s) found.\"\n\n Write-Host \"Connecting to server ...\"\n\n # Create a connection to the server\n $sqlConnectionString = \"Data Source=$($OctopusParameters['SSIS.Template.ServerName']);Initial Catalog=SSISDB;\"\n\n if (![string]::IsNullOrEmpty($OctopusParameters['SSIS.Template.sqlAccountUsername']) -and ![string]::IsNullOrEmpty($OctopusParameters['SSIS.Template.sqlAccountPassword']))\n {\n # Add username and password to connection string\n $sqlConnectionString += \"User ID=$($OctopusParameters['SSIS.Template.sqlAccountUsername']); Password=$($OctopusParameters['SSIS.Template.sqlAccountPassword']);\"\n }\n else\n {\n # Use integrated\n $sqlConnectionString += \"Integrated Security=SSPI;\"\n }\n\n # Create new connection object with connection string\n $sqlConnection = New-Object System.Data.SqlClient.SqlConnection $sqlConnectionString\n\n # create integration services object\n $integrationServices = New-Object \"$ISNamespace.IntegrationServices\" $sqlConnection\n\n # get reference to the catalog\n Write-Host \"Getting reference to catalog $($OctopusParameters['SSIS.Template.CataLogName'])\"\n $Catalog = Get-Catalog -CatalogName $OctopusParameters['SSIS.Template.CataLogName']\n\n # get folder reference\n $Folder = Get-Folder -FolderName $OctopusParameters['SSIS.Template.FolderName'] -Catalog $Catalog\n\n # loop through ispac files\n foreach($IsPacFile in $IsPacFiles)\n {\n # read project file\n $ProjectFile = [System.IO.File]::ReadAllBytes($IsPacFile.FullName)\n $ProjectName = $IsPacFile.Name.SubString(0, $IsPacFile.Name.LastIndexOf(\".\"))\n\n # deploy project\n Write-Host \"Deploying project $($IsPacFile.Name)...\"\n $Folder.DeployProject($ProjectName, $ProjectFile) | Out-Null\n\n # get reference to deployed project\n $Project = $Folder.Projects[$ProjectName]\n\n # check to see if they want to use environments\n if($UseEnvironment)\n {\n # get environment reference\n $Environment = Get-Environment -Folder $Folder -EnvironmentName $OctopusParameters['SSIS.Template.EnvironmentName']\n\n # set environment reference\n Set-EnvironmentReference -Project $Project -Environment $Environment -Folder $Folder\n\n # check to see if the user wants to convert project parameters to environment variables\n if($ReferenceProjectParametersToEnvironmentVairables)\n {\n # set environment variables\n Write-Host \"Referencing Project Parameters to Environment Variables...\"\n $VariablesToPreserveInEnvironment += Set-ProjectParametersToEnvironmentVariablesReference -Project $Project -Environment $Environment\n }\n\n # check to see if the user wants to convert the package parameters to environment variables\n if($ReferencePackageParametersToEnvironmentVairables)\n {\n # set package variables\n Write-Host \"Referencing Package Parameters to Environment Variables...\"\n $VariablesToPreserveInEnvironment += Set-PackageVariablesToEnvironmentVariablesReference -Project $Project -Environment $Environment\n }\n\n # Removes all unused variables from the environment\n if ($SyncEnvironment)\n {\n Write-Host \"Sync package environment variables...\"\n Sync-EnvironmentVariables -Environment $Environment -VariablesToPreserveInEnvironment $VariablesToPreserveInEnvironment\n }\n }\n }\n }\n\n finally\n {\n # check to make sure sqlconnection isn't null\n if($sqlConnection)\n {\n # check state of sqlconnection\n if($sqlConnection.State -eq [System.Data.ConnectionState]::Open)\n {\n # close the connection\n $sqlConnection.Close()\n }\n\n # cleanup\n $sqlConnection.Dispose()\n }\n\n # cleanup temporary pinned SqlServer module only when it was actually used\n if ($runtime -and $runtime.UsedPinnedSqlServerModule)\n {\n Remove-TemporaryPinnedSqlServerModule -LocalModulesPath $LocalModules -PinnedVersion $pinnedSqlServerVersion\n }\n }\n}\n\nInvoke-SsisProjectDeployment", "Octopus.Action.Script.ScriptSource": "Inline" }, "Parameters": [ @@ -187,10 +187,10 @@ } ], "$Meta": { - "ExportedAt": "2023-04-14T17:41:15.309Z", + "ExportedAt": "2026-03-06T13:42:00.0000000", "OctopusVersion": "2023.1.9791", "Type": "ActionTemplate" }, - "LastModifiedBy": "twerthi", + "LastModifiedBy": "bcullman", "Category": "sql" -} +} \ No newline at end of file