From de395da8450fdecf96f008199bc5a87b4361f3fb Mon Sep 17 00:00:00 2001 From: Lodewijk Sioen Date: Tue, 17 Sep 2024 16:04:14 +0200 Subject: [PATCH] feat: TrustServerCertificate on AzSqlDatabaseMigration (#434) * TrustServerCertificate on AzSqlDatabaseMigration Added TrustServerCertificate for scenario's where you want to build locally for integration testing. * Correct description for parameter * Version 22+ of SqlServer module is needed TrustServerCertificate was introduced in version 22 --- .../03-Features/powershell/azure-sql.md | 20 +++++++++------- .../Arcus.Scripting.Sql.psd1 | Bin 7742 -> 7734 bytes .../Arcus.Scripting.Sql.psm1 | 6 ++++- .../Scripts/Invoke-AzSqlDatabaseMigration.ps1 | 18 +++++++------- .../Arcus.Scripting.Sql.tests.ps1 | 22 ++++++++++++------ .../appsettings.json | 4 +++- 6 files changed, 44 insertions(+), 26 deletions(-) diff --git a/docs/preview/03-Features/powershell/azure-sql.md b/docs/preview/03-Features/powershell/azure-sql.md index aac57796..aa17660a 100644 --- a/docs/preview/03-Features/powershell/azure-sql.md +++ b/docs/preview/03-Features/powershell/azure-sql.md @@ -24,15 +24,16 @@ If the DatabaseVersion table doesn't exist it will automatically create it. This function allows you to trigger a database migration, which will only execute the newly provided SQL scripts, based on the provided version number in each of the scripts. The current version is stored in a table "DatabaseVersion", which will be created if it doesn't exist yet. -| Parameter | Mandatory | Description | -| ------------------- | --------------------------------------- | ----------------------------------------------------------------------------------- | -| `ServerName` | yes | The full name of the SQL Server that hosts the SQL Database. | -| `DatabaseName` | yes | The name of the SQL Database | -| `UserName` | yes | The UserName of the SQL Database | -| `Password` | yes | The Password of the SQL Database | -| `ScriptsFolder` | no (default: `$PSScriptRoot/sqlScripts` | The directory folder where the SQL migration scripts are located on the file system | -| `ScriptsFileFilter` | no (default: `*.sql`) | The file filter to limit the SQL script files to use during the migrations | -| `DatabaseSchema` | no (default: `dbo`) | The database schema to use when running SQL commands on the target database | +| Parameter | Mandatory | Description | +| ------------------------| --------------------------------------- | ----------------------------------------------------------------------------------- | +| `ServerName` | yes | The full name of the SQL Server that hosts the SQL Database. | +| `DatabaseName` | yes | The name of the SQL Database | +| `UserName` | yes | The UserName of the SQL Database | +| `Password` | yes | The Password of the SQL Database | +| `TrustServerCertificate`| no (default: `$false`) | Indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust. | +| `ScriptsFolder` | no (default: `$PSScriptRoot/sqlScripts` | The directory folder where the SQL migration scripts are located on the file system | +| `ScriptsFileFilter` | no (default: `*.sql`) | The file filter to limit the SQL script files to use during the migrations | +| `DatabaseSchema` | no (default: `dbo`) | The database schema to use when running SQL commands on the target database | Make sure that the credentials that you provide can write tables to the database + any action that you specify in the SQL scripts. (If the user is a member of the `db_ddlamin` role, then that user should have the necessary rights) @@ -56,6 +57,7 @@ PS> Invoke-AzSqlDatabaseMigration ` -DatabaseName "my-database-name" ` -Username "my-sql-username" ` -Password "my-sql-password" ` +-TrustServerCertificate ` -ScriptsFolder "$PSScriptRoot/sql-scripts" ` -ScriptsFileFilter "*.MyScript.sql" ` -DatabaseSchema "custom" diff --git a/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psd1 b/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psd1 index 71e8ecc23c7306173a04d4396bc9013ff2b5ee4d..008ef81b39e0eb2729a9036c88687a8bc6f847a6 100644 GIT binary patch delta 22 ccmdmIv(08h6*s35gC2u15F2dn=H4s>08VKJDgXcg delta 30 fcmdmHv(IKj6}O-vgB}9}TQC>_q2=ag?#)5~cOM4* diff --git a/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psm1 b/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psm1 index 4a390666..ae04309f 100644 --- a/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psm1 +++ b/src/Arcus.Scripting.Sql/Arcus.Scripting.Sql.psm1 @@ -73,6 +73,9 @@ class DatabaseVersion : System.IComparable { .Parameter Password The password to be used to connect to the Azure SQL Database. + .Parameter TrustServerCertificate + Indicates whether the channel will be encrypted while bypassing walking the certificate chain to validate trust. + .Parameter ScriptsFolder The directory folder where the SQL migration scripts are located on the file system. @@ -88,12 +91,13 @@ function Invoke-AzSqlDatabaseMigration { [Parameter(Mandatory = $true)][string] $DatabaseName = $(throw "Please provide the name of the SQL Database"), [Parameter(Mandatory = $true)][string] $UserName = $(throw "Please provide the UserName of the SQL Database"), [Parameter(Mandatory = $true)][string] $Password = $(throw "Please provide the Password of the SQL Database"), + [Parameter(Mandatory = $false)][switch] $TrustServerCertificate, [Parameter(Mandatory = $false)][string] $ScriptsFolder = "$PSScriptRoot/sqlScripts", [Parameter(Mandatory = $false)][string] $ScriptsFileFilter = "*.sql", [Parameter(Mandatory = $false)][string] $DatabaseSchema = "dbo" ) - . $PSScriptRoot\Scripts\Invoke-AzSqlDatabaseMigration.ps1 -ServerName $ServerName -DatabaseName $DatabaseName -UserName $UserName -Password $Password -ScriptsFolder $ScriptsFolder -ScriptsFileFilter $ScriptsFileFilter -DatabaseSchema $DatabaseSchema + . $PSScriptRoot\Scripts\Invoke-AzSqlDatabaseMigration.ps1 -ServerName $ServerName -DatabaseName $DatabaseName -UserName $UserName -Password $Password -TrustServerCertificate $TrustServerCertificate -ScriptsFolder $ScriptsFolder -ScriptsFileFilter $ScriptsFileFilter -DatabaseSchema $DatabaseSchema } Export-ModuleMember -Function Invoke-AzSqlDatabaseMigration diff --git a/src/Arcus.Scripting.Sql/Scripts/Invoke-AzSqlDatabaseMigration.ps1 b/src/Arcus.Scripting.Sql/Scripts/Invoke-AzSqlDatabaseMigration.ps1 index 69df8ba9..229dfd4b 100644 --- a/src/Arcus.Scripting.Sql/Scripts/Invoke-AzSqlDatabaseMigration.ps1 +++ b/src/Arcus.Scripting.Sql/Scripts/Invoke-AzSqlDatabaseMigration.ps1 @@ -3,6 +3,7 @@ param( [Parameter(Mandatory = $true)][string] $DatabaseName = $(throw "Please provide the name of the SQL Database"), [Parameter(Mandatory = $true)][string] $UserName = $(throw "Please provide the user name of the user that must be used to perform the update"), [Parameter(Mandatory = $true)][string] $Password = $(throw "Please provide the password of the user that must be used to perform the update"), + [Parameter(Mandatory = $false)][bool] $TrustServerCertificate = $false, [Parameter(Mandatory = $false)][string] $ScriptsFolder = "$PSScriptRoot/sqlScripts", [Parameter(Mandatory = $false)][string] $ScriptsFileFilter = "*.sql", [Parameter(Mandatory = $false)][string] $DatabaseSchema = "dbo" @@ -27,18 +28,19 @@ function Execute-DbCommandWithResult($params, [string] $query) { return $result } -function Create-DbParams([string] $DatabaseName, [string] $serverInstance, [string] $UserName, [string] $Password) { +function Create-DbParams([string] $DatabaseName, [string] $serverInstance, [string] $UserName, [string] $Password, [bool] $TrustServerCertificate) { Write-Debug "databasename = $DatabaseName" Write-Debug "serverinstance = $serverInstance" Write-Debug "username = $UserName" return $params = @{ - 'Database' = $DatabaseName - 'ServerInstance' = $serverInstance - 'Username' = $UserName - 'Password' = $Password - 'OutputSqlErrors' = $true - 'AbortOnError' = $true + 'Database' = $DatabaseName + 'ServerInstance' = $serverInstance + 'Username' = $UserName + 'Password' = $Password + 'TrustServerCertificate' = $TrustServerCertificate + 'OutputSqlErrors' = $true + 'AbortOnError' = $true } } @@ -47,7 +49,7 @@ function Get-SqlScriptFileText([string] $scriptPath, [string] $fileName) { return $query = Get-Content $currentfilepath } -$params = Create-DbParams $DatabaseName $ServerName $UserName $Password +$params = Create-DbParams $DatabaseName $ServerName $UserName $Password $TrustServerCertificate $createDatabaseVersionTable = "IF NOT EXISTS ( SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'DatabaseVersion' AND TABLE_SCHEMA = '$DatabaseSchema' ) " + "BEGIN " + diff --git a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 index 738c3357..760b194c 100644 --- a/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 +++ b/src/Arcus.Scripting.Tests.Integration/Arcus.Scripting.Sql.tests.ps1 @@ -101,14 +101,15 @@ InModuleScope Arcus.Scripting.Sql { Describe "Arcus Azure SQL integration tests" { BeforeAll { $config = & $PSScriptRoot\Load-JsonAppsettings.ps1 - $serverInstance = $config.Arcus.Sql.ServerName + '.database.windows.net' + $serverInstance = If($config.Arcus.Sql.UseLocalDb) { $config.Arcus.Sql.ServerName } Else { $config.Arcus.Sql.ServerName + '.database.windows.net' } $params = @{ - 'ServerInstance' = $serverInstance - 'Database' = $config.Arcus.Sql.DatabaseName - 'Username' = $config.Arcus.Sql.UserName - 'Password' = $config.Arcus.Sql.Password - 'OutputSqlErrors' = $true - 'AbortOnError' = $true + 'ServerInstance' = $serverInstance + 'Database' = $config.Arcus.Sql.DatabaseName + 'Username' = $config.Arcus.Sql.UserName + 'Password' = $config.Arcus.Sql.Password + 'TrustServerCertificate' = $config.Arcus.Sql.TrustServerCertificate + 'OutputSqlErrors' = $true + 'AbortOnError' = $true } & $PSScriptRoot\Connect-AzAccountFromConfig.ps1 -config $config @@ -147,6 +148,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts" # Assert @@ -169,6 +171,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -DatabaseSchema $customSchema ` -ScriptsFolder "$PSScriptRoot\SqlScripts" @@ -201,6 +204,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts" # Assert @@ -235,6 +239,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts\MigrationScriptsAreSuccessfullyExecuted" # Assert @@ -282,6 +287,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts\MigrationStopsOnError" } | Should -Throw $version = Get-AzSqlDatabaseVersion $params @@ -301,6 +307,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts\OldMigrationScriptsAreStillSupported" $version = Get-AzSqlDatabaseVersion $params @@ -316,6 +323,7 @@ InModuleScope Arcus.Scripting.Sql { -DatabaseName $config.Arcus.Sql.DatabaseName ` -Username $config.Arcus.Sql.Username ` -Password $config.Arcus.Sql.Password ` + -TrustServerCertificate:([bool]::Parse($config.Arcus.Sql.TrustServerCertificate)) ` -ScriptsFolder "$PSScriptRoot\SqlScripts\OldAndNewNamingConventionSupported" $version = Get-AzSqlDatabaseVersion $params diff --git a/src/Arcus.Scripting.Tests.Integration/appsettings.json b/src/Arcus.Scripting.Tests.Integration/appsettings.json index 1b2bc141..cdddc9d0 100644 --- a/src/Arcus.Scripting.Tests.Integration/appsettings.json +++ b/src/Arcus.Scripting.Tests.Integration/appsettings.json @@ -29,10 +29,12 @@ } }, "Sql": { + "UseLocalDb": false, "ServerName": "#{Arcus.Scripting.Sql.ServerName}#", "DatabaseName": "#{Arcus.Scripting.Sql.DatabaseName}#", "UserName": "#{Arcus.Scripting.Sql.UserName}#", - "Password": "#{Arcus.Scripting.Sql.Password}#" + "Password": "#{Arcus.Scripting.Sql.Password}#", + "TrustServerCertificate": false }, "ActiveDirectory": { "TenantId": "#{Arcus.Scripting.ActiveDirectory.TenantId}#",