Skip to content

Commit ed34b01

Browse files
authored
SqlDatabase: Support Changing Snapshot Isolation (#1622)
1 parent b6b1daa commit ed34b01

File tree

7 files changed

+331
-3
lines changed

7 files changed

+331
-3
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -367,6 +367,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
367367
`build`) and fixed file pattern matching syntax.
368368
- Bump GitHub actions codeql-action/upload-sarif to v4
369369
- Bump GitHub actions checkout to v6
370+
- SqlDatabase
371+
- Support enabling or disabling snapshot isolation
372+
([issue #845](https://github.com/dsccommunity/SqlServerDsc/issues/845)).
370373

371374
## [17.2.0] - 2025-09-16
372375

source/DSCResources/DSC_SqlDatabase/DSC_SqlDatabase.psm1

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ function Get-TargetResource
7676
CompatibilityLevel = $null
7777
RecoveryModel = $null
7878
OwnerName = $null
79+
SnapshotIsolation = $null
7980
}
8081

8182
$sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName -ErrorAction 'Stop'
@@ -92,6 +93,7 @@ function Get-TargetResource
9293
$returnValue['CompatibilityLevel'] = $sqlDatabaseObject.CompatibilityLevel
9394
$returnValue['RecoveryModel'] = $sqlDatabaseObject.RecoveryModel
9495
$returnValue['OwnerName'] = $sqlDatabaseObject.Owner
96+
$returnValue['SnapshotIsolation'] = $sqlDatabaseObject.SnapshotIsolationState -eq 'Enabled'
9597

9698
Write-Verbose -Message (
9799
$script:localizedData.DatabasePresent -f $Name
@@ -140,6 +142,9 @@ function Get-TargetResource
140142
141143
.PARAMETER OwnerName
142144
Specifies the name of the login that should be the owner of the database.
145+
146+
.PARAMETER SnapshotIsolation
147+
Specifies whether snapshot isolation should be enabled for the database.
143148
#>
144149
function Set-TargetResource
145150
{
@@ -184,7 +189,11 @@ function Set-TargetResource
184189

185190
[Parameter()]
186191
[System.String]
187-
$OwnerName
192+
$OwnerName,
193+
194+
[Parameter()]
195+
[System.Boolean]
196+
$SnapshotIsolation
188197
)
189198

190199
$sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName -ErrorAction 'Stop'
@@ -278,6 +287,22 @@ function Set-TargetResource
278287
$wasUpdate = $true
279288
}
280289

290+
if ($PSBoundParameters.ContainsKey('SnapshotIsolation'))
291+
{
292+
Write-Verbose -Message (
293+
$script:localizedData.UpdatingSnapshotIsolation -f $SnapshotIsolation
294+
)
295+
296+
if ($SnapshotIsolation)
297+
{
298+
Enable-SqlDscDatabaseSnapshotIsolation -DatabaseObject $sqlDatabaseObject -Force -ErrorAction 'Stop'
299+
}
300+
else
301+
{
302+
Disable-SqlDscDatabaseSnapshotIsolation -DatabaseObject $sqlDatabaseObject -Force -ErrorAction 'Stop'
303+
}
304+
}
305+
281306
try
282307
{
283308
if ($wasUpdate)
@@ -330,6 +355,17 @@ function Set-TargetResource
330355
{
331356
$sqlDatabaseObjectToCreate.SetOwner($OwnerName)
332357
}
358+
359+
<#
360+
This must be run after the object is created because
361+
snapshot isolation can only be set on an existing database.
362+
Snapshot isolation is disabled by default, so we only need
363+
to enable it if explicitly requested.
364+
#>
365+
if ($PSBoundParameters.ContainsKey('SnapshotIsolation') -and $SnapshotIsolation)
366+
{
367+
Enable-SqlDscDatabaseSnapshotIsolation -DatabaseObject $sqlDatabaseObjectToCreate -Force -ErrorAction 'Stop'
368+
}
333369
}
334370
}
335371
catch
@@ -397,6 +433,9 @@ function Set-TargetResource
397433
398434
.PARAMETER OwnerName
399435
Specifies the name of the login that should be the owner of the database.
436+
437+
.PARAMETER SnapshotIsolation
438+
Specifies whether snapshot isolation should be enabled for the database.
400439
#>
401440
function Test-TargetResource
402441
{
@@ -443,7 +482,11 @@ function Test-TargetResource
443482

444483
[Parameter()]
445484
[System.String]
446-
$OwnerName
485+
$OwnerName,
486+
487+
[Parameter()]
488+
[System.Boolean]
489+
$SnapshotIsolation
447490
)
448491

449492
Write-Verbose -Message (
@@ -521,6 +564,15 @@ function Test-TargetResource
521564

522565
$isDatabaseInDesiredState = $false
523566
}
567+
568+
if ($PSBoundParameters.ContainsKey('SnapshotIsolation') -and $getTargetResourceResult.SnapshotIsolation -ne $SnapshotIsolation)
569+
{
570+
Write-Verbose -Message (
571+
$script:localizedData.SnapshotIsolationWrong -f $Name, $getTargetResourceResult.SnapshotIsolation, $SnapshotIsolation
572+
)
573+
574+
$isDatabaseInDesiredState = $false
575+
}
524576
}
525577
}
526578
}

source/DSCResources/DSC_SqlDatabase/DSC_SqlDatabase.schema.mof

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ class DSC_SqlDatabase : OMI_BaseResource
99
[Write, Description("Specifies the version of the _SQL Database Compatibility Level_ to use for the specified database."), ValueMap{"Version80","Version90","Version100","Version110","Version120","Version130","Version140","Version150","Version160"}, Values{"Version80","Version90","Version100","Version110","Version120","Version130","Version140","Version150","Version160"}] String CompatibilityLevel;
1010
[Write, Description("The recovery model for the specified database."), ValueMap{"Simple","Full","BulkLogged"}, Values{"Simple","Full","BulkLogged"}] String RecoveryModel;
1111
[Write, Description("Specifies the name of the login that should be the owner of the database.")] String OwnerName;
12+
[Write, Description("Specifies whether snapshot isolation is enabled for the specified database.")] Boolean SnapshotIsolation;
1213
};

source/DSCResources/DSC_SqlDatabase/en-US/DSC_SqlDatabase.strings.psd1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ ConvertFrom-StringData @'
2222
OwnerNameWrong = The database '{0}' exist and has the owner '{1}', but expected it to have the owner '{2}'.
2323
UpdatingOwner = Changing the database owner to '{0}'.
2424
FailedToUpdateOwner = Failed changing to owner to '{0}' for the database '{1}'.
25+
UpdatingSnapshotIsolation = Updating snapshot isolation to '{0}'.
26+
SnapshotIsolationWrong = The database '{0}' exists and has snapshot isolation set to '{1}', but expected it to have snapshot isolation set to '{2}'.
2527
'@

tests/Integration/Resources/DSC_SqlDatabase.Integration.Tests.ps1

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,60 @@ Describe "$($script:dscResourceName)_Integration" -Tag @('Integration_SQL2016',
328328
}
329329
}
330330

331+
Context ('When using configuration <_>') -ForEach @(
332+
"$($script:dscResourceName)_AddDatabase6_Config"
333+
) {
334+
BeforeAll {
335+
$configurationName = $_
336+
}
337+
338+
AfterEach {
339+
Wait-ForIdleLcm
340+
}
341+
342+
It 'Should compile and apply the MOF without throwing' {
343+
$configurationParameters = @{
344+
OutputPath = $TestDrive
345+
# The variable $ConfigurationData was dot-sourced above.
346+
ConfigurationData = $ConfigurationData
347+
}
348+
349+
$null = & $configurationName @configurationParameters
350+
351+
$startDscConfigurationParameters = @{
352+
Path = $TestDrive
353+
ComputerName = 'localhost'
354+
Wait = $true
355+
Verbose = $true
356+
Force = $true
357+
ErrorAction = 'Stop'
358+
}
359+
360+
$null = Start-DscConfiguration @startDscConfigurationParameters
361+
}
362+
363+
It 'Should be able to call Get-DscConfiguration without throwing' {
364+
$script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction 'Stop'
365+
}
366+
367+
It 'Should have set the resource and all the parameters should match' {
368+
$resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript {
369+
$_.ConfigurationName -eq $configurationName `
370+
-and $_.ResourceId -eq $resourceId
371+
}
372+
373+
$resourceCurrentState.Ensure | Should -Be 'Present'
374+
$resourceCurrentState.Name | Should -Be $ConfigurationData.AllNodes.DatabaseName6
375+
$resourceCurrentState.ServerName | Should -Be $ConfigurationData.AllNodes.ServerName
376+
$resourceCurrentState.InstanceName | Should -Be $ConfigurationData.AllNodes.InstanceName
377+
$resourceCurrentState.SnapshotIsolation | Should -Be $ConfigurationData.AllNodes.SnapshotIsolation
378+
}
379+
380+
It 'Should return $true when Test-DscConfiguration is run' {
381+
Test-DscConfiguration -Verbose -ErrorAction 'Stop' | Should -Be 'True'
382+
}
383+
}
384+
331385
Context ('When using configuration <_>') -ForEach @(
332386
"$($script:dscResourceName)_RemoveDatabase2_Config"
333387
) {
@@ -378,6 +432,7 @@ Describe "$($script:dscResourceName)_Integration" -Tag @('Integration_SQL2016',
378432
$resourceCurrentState.OwnerName | Should -BeNullOrEmpty
379433
$resourceCurrentState.RecoveryModel | Should -BeNullOrEmpty
380434
$resourceCurrentState.CompatibilityLevel | Should -BeNullOrEmpty
435+
$resourceCurrentState.SnapshotIsolation | Should -BeNullOrEmpty
381436
}
382437

383438
It 'Should return $true when Test-DscConfiguration is run' {

tests/Integration/Resources/DSC_SqlDatabase.config.ps1

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ else
3030
DatabaseName3 = 'Database3'
3131
DatabaseName4 = 'Database4'
3232
DatabaseName5 = 'Database5'
33+
DatabaseName6 = 'Database6'
3334

3435
Collation = 'SQL_Latin1_General_Pref_CP850_CI_AS'
3536
CompatibilityLevel = 'Version120'
3637
RecoveryModel = 'Simple'
3738
OwnerName = 'sa'
39+
SnapshotIsolation = $true
3840
}
3941
)
4042
}
@@ -164,6 +166,31 @@ Configuration DSC_SqlDatabase_AddDatabase5_Config
164166
}
165167
}
166168

169+
<#
170+
.SYNOPSIS
171+
Creates a database with a specific snapshot isolation.
172+
#>
173+
Configuration DSC_SqlDatabase_AddDatabase6_Config
174+
{
175+
Import-DscResource -ModuleName 'SqlServerDsc'
176+
177+
node $AllNodes.NodeName
178+
{
179+
SqlDatabase 'Integration_Test'
180+
{
181+
Ensure = 'Present'
182+
ServerName = $Node.ServerName
183+
InstanceName = $Node.InstanceName
184+
Name = $Node.DatabaseName6
185+
SnapshotIsolation = $Node.SnapshotIsolation
186+
187+
PsDscRunAsCredential = New-Object `
188+
-TypeName System.Management.Automation.PSCredential `
189+
-ArgumentList @($Node.Username, (ConvertTo-SecureString -String $Node.Password -AsPlainText -Force))
190+
}
191+
}
192+
}
193+
167194
<#
168195
.SYNOPSIS
169196
Removes the second databases that was created.

0 commit comments

Comments
 (0)