Executing SQL queries on Azure SQL Database using Azure Devops can be a complex and challenging task, particularly when it comes to establishing a secure and reliable connection. This option can be valuable in numerous scenarios. For instance, you can insert pipeline metadata into the database to track deployment information or changes. This technique also allows you to steer other tasks based on values extracted from the database, enabling dynamic decision-making within your pipelines. Additionally, it can be used to perform specific tasks depending on the current configuration of the database, such as adjusting settings or executing configuration-specific scripts. These are just a few examples, and the technique can be adapted for many other use cases, making it a versatile tool in your DevOps toolkit.
In my recent project, I needed to achieve this, and I decided to leverage an existing service connection for connectivity. Despite the initial challenges, I was able to find two effective options that successfully addressed the issue. In this article, I will walk you through these options, detailing the steps and considerations involved, to help you seamlessly execute SQL queries from Azure DevOps to your Azure SQL Database.
The first option I discovered is the simplest and involves using the built-in task called Azure SQL Database Deployment.
This task is specifically designed for deploying to Azure SQL Database directly from Azure DevOps, but it also allows you to write your own SQL statements, which is useful in our scenario. The entire script is quite simple—it is configured to run manually and uses the latest Windows image for execution. It utilizes the aforementioned SQL Azure Dacpac Deployment task to connect to an Azure SQL Database using a predefined DevOps service connection with service principal authentication.
For simplicity, I added an inline SQL query (SELECT @@VERSION
) to be executed on a specified SQL Server and database. One of the great features of this task is the ability to automatically detect the IP address used by DevOps and temporarily add it to Azure SQL, simplifying the connectivity process (of course proper permissions must be in place).
trigger: - none pool: vmImage: windows-latest steps: - task: SqlAzureDacpacDeployment@1 inputs: azureSubscription: 'service-connection' AuthenticationType: 'servicePrincipal' ServerName: 'myserver' DatabaseName: 'mydb' deployType: 'InlineSqlTask' SqlInline: 'SELECT @@VERSION as Version' IpDetectionMethod: 'AutoDetect'
In the screenshot below, you can see the correct result of the query with the SQL Server version displayed on the screen
We can also execute stored procedures, and it still works well. Below, you can see the result of executing sp_help:
The above option is a wrapper that uses Invoke-Sqlcmd
behind the scenes. For more advanced scenarios, where additional control is required, you might need to interact directly with Invoke-Sqlcmd
. This approach involves a few more steps: first, use az account get-access-token
to obtain an access token after logging in with the service connection. Then, you can use this token directly with Invoke-Sqlcmd
to execute SQL commands:
trigger: - none pool: vmImage: windows-latest steps: - task: AzureCLI@2 inputs: azureSubscription: 'service-connection' scriptType: 'ps' scriptLocation: 'inlineScript' inlineScript: | $accessToken = az account get-access-token --resource https://database.windows.net/ --query accessToken --output tsv $result = Invoke-Sqlcmd -ServerInstance "server" -Database "database" -AccessToken $accessToken -Query "SELECT @@VERSION as version" $resultValue = $result["Version"] Write-Host $resultValue addSpnToEnvironment: true
This approach is much more flexible. For example, you can save the query result to a DevOps variable using ##vso[task.setvariable]
and then use this variable in subsequent tasks within the pipeline script. This allows for dynamic data handling and integration across different stages of your pipeline.
trigger: - none pool: vmImage: windows-latest steps: - task: AzureCLI@2 inputs: azureSubscription: 'service-connection' scriptType: 'ps' scriptLocation: 'inlineScript' inlineScript: | $accessToken = az account get-access-token --resource https://database.windows.net/ --query accessToken --output tsv $result = Invoke-Sqlcmd -ServerInstance "server" -Database "database" -AccessToken $accessToken -Query "SELECT @@VERSION as version" $resultValue = $result["Version"] # Output the value to be captured by Azure DevOps Write-Output "##vso[task.setvariable variable=queryResult]$resultValue" addSpnToEnvironment: true - task: AzureCLI@2 inputs: azureSubscription: 'service-connection' scriptType: 'ps' scriptLocation: 'inlineScript' inlineScript: | Write-Output "SQL Version is $(queryResult)" addSpnToEnvironment: true
In this summary, we explored methods for executing SQL queries from Azure DevOps to an Azure SQL Database. We first discussed the straightforward approach using the built-in Azure SQL Database Deployment task, which simplifies the process by leveraging a pre-configured service connection and automating IP address configuration.
Next, we examined a more advanced approach involving the AzureCLI@2 task. This method provides greater flexibility by allowing direct use of Invoke-Sqlcmd
with an access token obtained through az account get-access-token
. This approach not only enables the execution of SQL queries but also allows saving query results to DevOps variables, which can be utilized in subsequent pipeline tasks. Both methods offer effective solutions depending on the complexity of the scenario, with the latter providing enhanced control and integration within Azure DevOps pipelines. I hope you find these options useful for your SQL query execution needs. See you!
- Avoiding Issues: Monitoring Query Pushdowns in Databricks Federated Queries - October 27, 2024
- Microsoft Fabric: Using Workspace Identity for Authentication - September 25, 2024
- Executing SQL queries from Azure DevOps using Service Connection credentials - August 28, 2024
Last comments