A YAML Azure DevOps SSIS Pipeline

June 11, 2025    TFS/VSTS/AzureDevOps DevOps CI/CD YAML

A YAML Azure DevOps SSIS Pipeline

A MS Copilot generated image of ADO with conveyor belts

I needed to create an easy way to for my team to add a YAML pipeline to our many SSIS packages we maintain. I struggled for awhile as I was pushing the limits of using parameters and variables in templates. I still don’t have a good way to use Variable Groups, but hopefully this helps you

I could have named this post "I struggled so you don't have to" (as much, hopefully) 😁

I have another post focused on using templates , but this is focused on SSIS. The yml is also in my GitHub repo .

ssisBuild.yml

# Build the SSIS package and create artifacts that can be deployed
# Create a ispac for the 'Development', 'Test' and 'Production' which are the same as the Visual Studio Build Configuration drop down options
# https://learn.microsoft.com/en-us/sql/integration-services/devops/ssis-devops-overview

## Usage


parameters:
  - name: dtproj
    type: string
  - name: artifactName
    type: string
  - name: sourceFolder
    type: string
  - name: isMain
    type: string
    values:
     - 'true'
     - 'false'

jobs:
  - job: BuildAndCreateArtifacts
    displayName: "Build and Create .ispac Artifact"
    steps:
      - task: SSISBuild@1
        displayName: "Build SSIS Package - Development"
        inputs:
          projectPath: ${{ parameters.dtproj }}
          outputPath: '$(Build.ArtifactStagingDirectory)/Development'
          configuration: 'Development'
          stripSensitive: true
      - task: SSISBuild@1
        displayName: "Build SSIS Package - Test"
        inputs:
          projectPath: ${{ parameters.dtproj }}
          outputPath: '$(Build.ArtifactStagingDirectory)/Test'
          configuration: 'Test'
          stripSensitive: true
          # if Test isn't defined, continue on
          continueOnError: true
      - task: SSISBuild@1
        displayName: "Build SSIS Package - Production"
        inputs:
          projectPath: ${{ parameters.dtproj }}
          outputPath: '$(Build.ArtifactStagingDirectory)/Production'
          configuration: 'Production'
          stripSensitive: true

      - task: PublishBuildArtifacts@1
        displayName: "Publish The .ispac Build Artifacts"
        inputs:
          PathtoPublish: $(Build.ArtifactStagingDirectory)
          ArtifactName: ${{ parameters.artifactName }}

      # properties will need to be set manually in SSMS > package > configure
      # - task: PublishBuildArtifacts@1
      #   displayName: "Publish SSISSSISCatalog configuraiton Build Artifacts"
      #   inputs:
      #     PathtoPublish: '${{ parameters.sourceFolder }}/ssisConfiguration.json'
      #     ArtifactName: '${{ parameters.artifactName }}_config'

ssisDeployToEnvironment.yml

The repo version may be more up to date.

# Deploy/Publish the SSIS Package to the Database Server 
# Dev and Production Environments that are setup in the ADO UI under Pipelines > Environments
# https://learn.microsoft.com/en-us/sql/integration-services/devops/ssis-devops-overview

## Usage
## see https://dev.azure.com/AveraHealthPlans/Software/_git/Examples/Pipelines/SSIS
## Build an .ispac for each environment, then use those artifacts here

parameters:
  # should match the <name>.ispac
  - name: artifactName
    type: string
  # 'Development', 'Test', 'Production'
  - name: environmentName
    type: string
  # since we can't pull these directly from the variable group and use $(DatabaseAdoEnvironmentName) (it's not evaluated)
  # this should be from the variable Group
  - name: databaseAdoEnvironmentName
    type: string
  # the name of the agent under the ADO environment
  - name: databaseAdoResourceName
    type: string
  - name: databaseServer
    type: string
  # Example: '/SSISDB/MyFolder/MyProject'
  - name: destinationPath
    type: string


jobs:
  - deployment: 'Deploy_${{ parameters.environmentName }}'
    displayName: 'Deploy ${{ parameters.environmentName }}'
    # dependsOn: ${{ parameters.stageDependsOn }} I kept getting Stage PublishProduction job Deploy_Production depends on unknown job Deploy_Development. so I removed this
    environment:
      name: ${{ parameters.databaseAdoEnvironmentName }}
      resourceName: ${{ parameters.databaseAdoResourceName }}
      resourceType: VirtualMachine
    strategy:
      runOnce:
        deploy:
          steps:
            - checkout: none
            # TODO: create json configuration files, publish them from the ssisBuild and use them here
            # for now: properties will need to be set manually in SSMS > package > configure on creation and if they change
            # https://learn.microsoft.com/en-us/sql/integration-services/devops/ssis-devops-overview?view=sql-server-ver16#ssis-catalog-configuration-task
            # - task: SSISCatalog@0
            #   inputs:
            #     # 'filePath', 'inline', 'none'
            #     configSource: 'filePath'
            #     # note: I'm not certain about using this, look at the documentation
            #     # configPath: '${{ parameters.artifactName }}/${{ parameters.artifactName }}_config/Project.params'
            #     # targetServer is where the SSISDB catalog is hosted and usually the same as destinationServer
            #     targetServer: ${{ parameters.databaseServer }}
            #     connectionStringSuffix: ''
            #     # 'win' or 'sql'
            #     authType: 'win'
            #     rollBackOnError: true

            # This will not create a new Package on the database in SSISDB
            # It will only update the existing ones
            # - task: SSISDeploy@1
            #   displayName: "Deploy SSIS Package"
            #   inputs:
            #     # Example: your build stage artifact from ssisBuild.yml
            #     # The auto download artifacts puts it in
            #     sourcePath: '$(Pipeline.Workspace)/${{ parameters.artifactName }}/${{ parameters.environmentName }}/${{ parameters.artifactName }}.ispac'
            #     # Example: 'SSISDB' or 'File System'
            #     destinationType: 'SSISDB'
            #     destinationServer: ${{ parameters.databaseServer }}
            #     destinationPath: ${{ parameters.destinationPath }}
            #     authType: 'win'
            #     whetherOverwrite: true
            #     whetherContinue: false

            # This will create or update the package.
            # If creating you still need to add the parameter overrides in SSMS > Project > Configure             
            - task: PowerShell@2
              displayName: "Deploy SSIS Package"
              inputs:
                targetType: 'inline'
                script: |
                  # SSISDeploy.exe needs to be on the VM with SSISDeploy.exe in the environment variable path
                  # https://learn.microsoft.com/en-us/sql/integration-services/devops/ssis-devops-standalone?view=sql-server-ver16
                  # Path to the SSISDeploy.exe
                  $ssisDeployPath = SSISDeploy.exe
                  
                  # Source path to the ISPAC file
                  $sourcePath = "$(Pipeline.Workspace)/${{ parameters.artifactName }}/${{ parameters.environmentName }}/${{ parameters.artifactName }}.ispac"
                  
                  # Destination type: CATALOG or FILE
                  $destinationType = "catalog"
                  
                  # Destination server (for CATALOG)
                  $destinationServer = "${{ parameters.databaseServer }}"
                  
                  # Destination path in SSISDB (for CATALOG)
                  $destinationPath = "${{ parameters.destinationPath }}"
                  
                  # Authentication type (WIN, SQL, ADPWD, ADINT)
                  $authType = "win"
                  
                  # Project password (if required)
                  $projectPassword = ""
                  
                  # Execute SSISDeploy.exe
                  ## SSISDeploy.exe -s:Example.ispac -d:"catalog;/SSISDB/ExampleA;AHDC790DBd01" -at:win
                  & SSISDeploy.exe -s:$sourcePath -d:"$destinationType;$destinationPath;$destinationServer;" -at:$authType
            # requires sysadmin server role 
            - template: ssisCreateAgentJob.yml
              parameters:
                artifactName: ${{ parameters.artifactName }}
                environmentName: ${{ parameters.environmentName }}
                databaseServer: ${{ parameters.databaseServer }}
                databaseName: ${{ parameters.databaseName }}
                ssisPackagePath: ${{ parameters.destinationPath }}

Future Improvements

  • Pull values from Variable Groups (I tried but didn’t find a way to make it happen with the template inside of a deployment job)
  • Create json configuration files and use in the SSISCatalog@0 task

https://github.com/MicrosoftDocs/sql-docs/pull/10117

Use the templates in your pipeline

See the Example in the Repo .

Azure DevOps Environments

We are deploying to OnPremise databases.

First we created a Development and Production environment . They are referenced by name in the databaseAdoEnvironmentName in the YAML above.

Then, we needed to setup [self-hosted agents] ( https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/windows-agent?view=azure-devops&tabs=IP-V4) . you’ll need an administrator to run theseThese are added as resources in the environment by clicking add resource and running the script provided.

Security

Read through Prepare Permissions .

For OnPremise hosted agents, it’d be best to have a local user created for the service to run under for each environment (even split up for database, IIS, other server) to give the least priveledge. Then create the agent with a PAT specific to that user after it is in ADO.

I didn’t find a lot of resources on how to do this properly. It seems like Microsoft didn’t consider security when making the NT AUTHORITY/SYSTEM the default for the agent. Maybe they consider the OnPremise Agent to be secure?

I found an article from Michael Boeynams . We didn’t go this far, but his approach is the most secure that I’ve found. His GitHub link with PowerShell scripts could be modified to set the required permissions for IIS deployment. Using a script would be much better than clicking around until you get the correct working permissions (you document it right?).

The ssisCreateAgentJob requires a sysadmin server role or you will get “Failed to execute: The SELECT permission was denied on the object ‘sysjobs’, database ‘msdb’, schema ‘dbo’. Only a member of the sysadmin server role can add a job for a different owner with @owner_login_name.”

Resources

Here are a few of the many links I went through during the process.

It’s always nice to close those research tabs .