Skip to content

Commit fdcca69

Browse files
authored
Set-SqlDscDatabaseProperty: Remove DatabaseSnapshotBaseName (#2342)
1 parent 8055ded commit fdcca69

File tree

6 files changed

+161
-33
lines changed

6 files changed

+161
-33
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- Removed parameters `AzureEdition` and `AzureServiceObjective`. Azure SQL Database
1818
service tier and SLO changes should be managed using `Set-AzSqlDatabase` from the
1919
Azure PowerShell module instead. See [issue #2177](https://github.com/dsccommunity/SqlServerDsc/issues/2177).
20+
- Removed parameter `DatabaseSnapshotBaseName`. Database snapshots should be
21+
created using the `New-SqlDscDatabaseSnapshot`, or the `New-SqlDscDatabase`
22+
command with the `-DatabaseSnapshotBaseName` parameter.
2023

2124
### Added
2225

@@ -237,6 +240,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
237240

238241
### Changed
239242

243+
- `New-SqlDscDatabase`
244+
- Added support for creating database snapshots through a new `Snapshot`
245+
parameter set. Use the `-DatabaseSnapshotBaseName` parameter to specify
246+
the source database name when creating a snapshot ([issue #2333](https://github.com/dsccommunity/SqlServerDsc/issues/2333)).
240247
- `Restart-ReportingServicesService`
241248
- BREAKING CHANGE: Removed the deprecated `InstanceName` parameter. All callers
242249
must now use the `ServiceName` parameter instead.

source/Public/New-SqlDscDatabase.ps1

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
55
.DESCRIPTION
66
This command creates a new database in a SQL Server Database Engine instance.
7+
It supports creating both regular databases and database snapshots.
78
89
.PARAMETER ServerObject
910
Specifies current server connection object.
@@ -32,6 +33,11 @@
3233
.PARAMETER OwnerName
3334
Specifies the name of the login that should be the owner of the database.
3435
36+
.PARAMETER DatabaseSnapshotBaseName
37+
Specifies the name of the source database from which to create a snapshot.
38+
When this parameter is specified, a database snapshot will be created instead
39+
of a regular database. The snapshot name is specified in the Name parameter.
40+
3541
.PARAMETER Force
3642
Specifies that the database should be created without any confirmation.
3743
@@ -55,14 +61,21 @@
5561
Creates a new database named **MyDatabase** with the specified collation and recovery model
5662
without prompting for confirmation.
5763
64+
.EXAMPLE
65+
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
66+
$serverObject | New-SqlDscDatabase -Name 'MyDatabaseSnapshot' -DatabaseSnapshotBaseName 'MyDatabase' -Force
67+
68+
Creates a database snapshot named **MyDatabaseSnapshot** from the source database **MyDatabase**
69+
without prompting for confirmation.
70+
5871
.OUTPUTS
5972
`[Microsoft.SqlServer.Management.Smo.Database]`
6073
#>
6174
function New-SqlDscDatabase
6275
{
6376
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('UseSyntacticallyCorrectExamples', '', Justification = 'Because the rule does not yet support parsing the code when a parameter type is not available. The ScriptAnalyzer rule UseSyntacticallyCorrectExamples will always error in the editor due to https://github.com/indented-automation/Indented.ScriptAnalyzerRules/issues/8.')]
6477
[OutputType([Microsoft.SqlServer.Management.Smo.Database])]
65-
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
78+
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium', DefaultParameterSetName = 'Database')]
6679
param
6780
(
6881
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
@@ -74,29 +87,34 @@ function New-SqlDscDatabase
7487
[System.String]
7588
$Name,
7689

77-
[Parameter()]
90+
[Parameter(ParameterSetName = 'Database')]
7891
[ValidateNotNullOrEmpty()]
7992
[System.String]
8093
$Collation,
8194

82-
[Parameter()]
95+
[Parameter(ParameterSetName = 'Database')]
8396
[Microsoft.SqlServer.Management.Smo.CatalogCollationType]
8497
$CatalogCollation,
8598

86-
[Parameter()]
99+
[Parameter(ParameterSetName = 'Database')]
87100
[ValidateSet('Version80', 'Version90', 'Version100', 'Version110', 'Version120', 'Version130', 'Version140', 'Version150', 'Version160')]
88101
[System.String]
89102
$CompatibilityLevel,
90103

91-
[Parameter()]
104+
[Parameter(ParameterSetName = 'Database')]
92105
[ValidateSet('Simple', 'Full', 'BulkLogged')]
93106
[System.String]
94107
$RecoveryModel,
95108

96-
[Parameter()]
109+
[Parameter(ParameterSetName = 'Database')]
97110
[System.String]
98111
$OwnerName,
99112

113+
[Parameter(Mandatory = $true, ParameterSetName = 'Snapshot')]
114+
[ValidateNotNullOrEmpty()]
115+
[System.String]
116+
$DatabaseSnapshotBaseName,
117+
100118
[Parameter()]
101119
[System.Management.Automation.SwitchParameter]
102120
$Force,
@@ -205,6 +223,24 @@ function New-SqlDscDatabase
205223
}
206224
}
207225

226+
# Validate source database exists when creating a snapshot
227+
if ($PSCmdlet.ParameterSetName -eq 'Snapshot')
228+
{
229+
if (-not $ServerObject.Databases[$DatabaseSnapshotBaseName])
230+
{
231+
$errorMessage = $script:localizedData.Database_SnapshotSourceDatabaseNotFound -f $DatabaseSnapshotBaseName, $ServerObject.InstanceName
232+
233+
$PSCmdlet.ThrowTerminatingError(
234+
[System.Management.Automation.ErrorRecord]::new(
235+
[System.InvalidOperationException]::new($errorMessage),
236+
'NSD0006', # cspell: disable-line
237+
[System.Management.Automation.ErrorCategory]::ObjectNotFound,
238+
$DatabaseSnapshotBaseName
239+
)
240+
)
241+
}
242+
}
243+
208244
$verboseDescriptionMessage = $script:localizedData.Database_Create_ShouldProcessVerboseDescription -f $Name, $ServerObject.InstanceName
209245
$verboseWarningMessage = $script:localizedData.Database_Create_ShouldProcessVerboseWarning -f $Name
210246
$captionMessage = $script:localizedData.Database_Create_ShouldProcessCaption
@@ -215,24 +251,35 @@ function New-SqlDscDatabase
215251
{
216252
$sqlDatabaseObjectToCreate = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database' -ArgumentList $ServerObject, $Name
217253

218-
if ($PSBoundParameters.ContainsKey('RecoveryModel'))
254+
# Handle database snapshot creation
255+
if ($PSCmdlet.ParameterSetName -eq 'Snapshot')
219256
{
220-
$sqlDatabaseObjectToCreate.RecoveryModel = $RecoveryModel
221-
}
257+
Write-Verbose -Message ($script:localizedData.Database_CreatingSnapshot -f $Name, $DatabaseSnapshotBaseName)
222258

223-
if ($PSBoundParameters.ContainsKey('Collation'))
224-
{
225-
$sqlDatabaseObjectToCreate.Collation = $Collation
259+
$sqlDatabaseObjectToCreate.DatabaseSnapshotBaseName = $DatabaseSnapshotBaseName
226260
}
227-
228-
if ($PSBoundParameters.ContainsKey('CatalogCollation'))
229-
{
230-
$sqlDatabaseObjectToCreate.CatalogCollation = $CatalogCollation
231-
}
232-
233-
if ($PSBoundParameters.ContainsKey('CompatibilityLevel'))
261+
else
234262
{
235-
$sqlDatabaseObjectToCreate.CompatibilityLevel = $CompatibilityLevel
263+
# Handle regular database creation
264+
if ($PSBoundParameters.ContainsKey('RecoveryModel'))
265+
{
266+
$sqlDatabaseObjectToCreate.RecoveryModel = $RecoveryModel
267+
}
268+
269+
if ($PSBoundParameters.ContainsKey('Collation'))
270+
{
271+
$sqlDatabaseObjectToCreate.Collation = $Collation
272+
}
273+
274+
if ($PSBoundParameters.ContainsKey('CatalogCollation'))
275+
{
276+
$sqlDatabaseObjectToCreate.CatalogCollation = $CatalogCollation
277+
}
278+
279+
if ($PSBoundParameters.ContainsKey('CompatibilityLevel'))
280+
{
281+
$sqlDatabaseObjectToCreate.CompatibilityLevel = $CompatibilityLevel
282+
}
236283
}
237284

238285
Write-Verbose -Message ($script:localizedData.Database_Creating -f $Name)
@@ -243,8 +290,9 @@ function New-SqlDscDatabase
243290
This must be run after the object is created because
244291
the owner property is read-only and the method cannot
245292
be call until the object has been created.
293+
This only applies to regular databases, not snapshots.
246294
#>
247-
if ($PSBoundParameters.ContainsKey('OwnerName'))
295+
if ($PSCmdlet.ParameterSetName -eq 'Database' -and $PSBoundParameters.ContainsKey('OwnerName'))
248296
{
249297
$sqlDatabaseObjectToCreate.SetOwner($OwnerName)
250298
}

source/Public/Set-SqlDscDatabaseProperty.ps1

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -104,9 +104,6 @@
104104
.PARAMETER DatabaseOwnershipChaining
105105
Specifies whether ownership chaining across objects within the database is enabled.
106106
107-
.PARAMETER DatabaseSnapshotBaseName
108-
Specifies the base name of the source database from which this database snapshot was created.
109-
110107
.PARAMETER DataRetentionEnabled
111108
Specifies whether SQL Server data retention policy is enabled at the database level.
112109
@@ -312,6 +309,11 @@
312309
class and can only be set during database creation (e.g., using `New-SqlDscDatabase`
313310
or CREATE DATABASE statements).
314311
312+
- **DatabaseSnapshotBaseName**: The base name of the source database for a database
313+
snapshot. This property is marked as ReadOnlyAfterCreation in the SMO Database
314+
class. To create database snapshots, use the `New-SqlDscDatabaseSnapshot` or
315+
`New-SqlDscDatabase` command with the `-DatabaseSnapshotBaseName` parameter.
316+
315317
There are some database properties that require method calls instead of direct
316318
property assignment and will be supported through separate commands, e.g.
317319
`Set-SqlDscDatabaseDefaultFileGroup`.
@@ -575,10 +577,6 @@ function Set-SqlDscDatabaseProperty
575577
[System.String]
576578
$Collation,
577579

578-
[Parameter()]
579-
[System.String]
580-
$DatabaseSnapshotBaseName,
581-
582580
[Parameter()]
583581
[System.String]
584582
$DefaultSchema,

source/en-US/SqlServerDsc.strings.psd1

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ ConvertFrom-StringData @'
358358
Database_InvalidCompatibilityLevel = The specified compatibility level '{0}' is not a valid compatibility level for the instance '{1}'.
359359
Database_InvalidCollation = The specified collation '{0}' is not a valid collation for the instance '{1}'.
360360
Database_CatalogCollationNotSupported = The parameter CatalogCollation is not supported on SQL Server instance '{0}' with version '{1}'. This parameter requires SQL Server 2019 (version 15) or later.
361+
Database_SnapshotSourceDatabaseNotFound = The source database '{0}' for the database snapshot does not exist on instance '{1}'.
362+
Database_CreatingSnapshot = Creating database snapshot '{0}' from source database '{1}'.
361363
Database_Create_ShouldProcessVerboseDescription = Creating the database '{0}' on the instance '{1}'.
362364
Database_Create_ShouldProcessVerboseWarning = Are you sure you want to create the database '{0}'?
363365
# This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages.

tests/Unit/Public/New-SqlDscDatabase.Tests.ps1

Lines changed: 76 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,27 @@ Describe 'New-SqlDscDatabase' -Tag 'Public' {
154154
}
155155

156156
Context 'Parameter validation' {
157-
It 'Should have the correct parameters in parameter set __AllParameterSets' -ForEach @(
157+
It 'Should have the correct parameters in parameter set Database' -ForEach @(
158158
@{
159-
ExpectedParameterSetName = '__AllParameterSets'
160-
ExpectedParameters = '[-ServerObject] <Server> [-Name] <string> [[-Collation] <string>] [[-CatalogCollation] <CatalogCollationType>] [[-CompatibilityLevel] <string>] [[-RecoveryModel] <string>] [[-OwnerName] <string>] [-Force] [-Refresh] [-WhatIf] [-Confirm] [<CommonParameters>]'
159+
ExpectedParameterSetName = 'Database'
160+
ExpectedParameters = '-ServerObject <Server> -Name <string> [-Collation <string>] [-CatalogCollation <CatalogCollationType>] [-CompatibilityLevel <string>] [-RecoveryModel <string>] [-OwnerName <string>] [-Force] [-Refresh] [-WhatIf] [-Confirm] [<CommonParameters>]'
161+
}
162+
) {
163+
$result = (Get-Command -Name 'New-SqlDscDatabase').ParameterSets |
164+
Where-Object -FilterScript { $_.Name -eq $ExpectedParameterSetName } |
165+
Select-Object -Property @(
166+
@{ Name = 'ParameterSetName'; Expression = { $_.Name } },
167+
@{ Name = 'ParameterListAsString'; Expression = { $_.ToString() } }
168+
)
169+
170+
$result.ParameterSetName | Should -Be $ExpectedParameterSetName
171+
$result.ParameterListAsString | Should -Be $ExpectedParameters
172+
}
173+
174+
It 'Should have the correct parameters in parameter set Snapshot' -ForEach @(
175+
@{
176+
ExpectedParameterSetName = 'Snapshot'
177+
ExpectedParameters = '-ServerObject <Server> -Name <string> -DatabaseSnapshotBaseName <string> [-Force] [-Refresh] [-WhatIf] [-Confirm] [<CommonParameters>]'
161178
}
162179
) {
163180
$result = (Get-Command -Name 'New-SqlDscDatabase').ParameterSets |
@@ -180,5 +197,61 @@ Describe 'New-SqlDscDatabase' -Tag 'Public' {
180197
$parameterInfo = (Get-Command -Name 'New-SqlDscDatabase').Parameters['Name']
181198
$parameterInfo.Attributes.Mandatory | Should -BeTrue
182199
}
200+
201+
It 'Should have DatabaseSnapshotBaseName as a mandatory parameter in Snapshot parameter set' {
202+
$parameterInfo = (Get-Command -Name 'New-SqlDscDatabase').Parameters['DatabaseSnapshotBaseName']
203+
$snapshotSetAttribute = $parameterInfo.Attributes | Where-Object { $_.ParameterSetName -eq 'Snapshot' }
204+
$snapshotSetAttribute.Mandatory | Should -BeTrue
205+
}
206+
}
207+
208+
Context 'When creating a database snapshot' {
209+
BeforeAll {
210+
$mockServerObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server'
211+
$mockServerObject | Add-Member -MemberType 'NoteProperty' -Name 'InstanceName' -Value 'TestInstance' -Force
212+
$mockServerObject | Add-Member -MemberType 'NoteProperty' -Name 'VersionMajor' -Value 15 -Force
213+
214+
# Mock source database
215+
$mockSourceDatabase = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database'
216+
$mockSourceDatabase | Add-Member -MemberType 'NoteProperty' -Name 'Name' -Value 'SourceDatabase' -Force
217+
218+
$mockServerObject | Add-Member -MemberType 'ScriptProperty' -Name 'Databases' -Value {
219+
return @{
220+
'SourceDatabase' = $mockSourceDatabase
221+
} | Add-Member -MemberType 'ScriptMethod' -Name 'Refresh' -Value {
222+
# Mock implementation
223+
} -PassThru -Force
224+
} -Force
225+
226+
Mock -CommandName 'New-Object' -ParameterFilter { $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Database' } -MockWith {
227+
$mockDatabaseObject = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database'
228+
$mockDatabaseObject | Add-Member -MemberType 'NoteProperty' -Name 'Name' -Value $ArgumentList[1] -Force
229+
$mockDatabaseObject | Add-Member -MemberType 'NoteProperty' -Name 'DatabaseSnapshotBaseName' -Value $null -Force
230+
$mockDatabaseObject | Add-Member -MemberType 'ScriptMethod' -Name 'Create' -Value {
231+
# Mock implementation
232+
} -Force
233+
return $mockDatabaseObject
234+
}
235+
}
236+
237+
It 'Should create a database snapshot successfully' {
238+
$result = New-SqlDscDatabase -ServerObject $mockServerObject -Name 'TestSnapshot' -DatabaseSnapshotBaseName 'SourceDatabase' -Force
239+
240+
$result | Should -Not -BeNullOrEmpty
241+
$result.Name | Should -Be 'TestSnapshot'
242+
$result.DatabaseSnapshotBaseName | Should -Be 'SourceDatabase'
243+
Should -Invoke -CommandName 'New-Object' -ParameterFilter { $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Database' } -Exactly -Times 1
244+
}
245+
246+
It 'Should throw error when source database does not exist' {
247+
$mockServerObjectNoSourceDb = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Server'
248+
$mockServerObjectNoSourceDb | Add-Member -MemberType 'NoteProperty' -Name 'InstanceName' -Value 'TestInstance' -Force
249+
$mockServerObjectNoSourceDb | Add-Member -MemberType 'ScriptProperty' -Name 'Databases' -Value {
250+
return @{}
251+
} -Force
252+
253+
{ New-SqlDscDatabase -ServerObject $mockServerObjectNoSourceDb -Name 'TestSnapshot' -DatabaseSnapshotBaseName 'NonExistentDatabase' -Force } |
254+
Should -Throw -ExpectedMessage '*does not exist*'
255+
}
183256
}
184257
}

0 commit comments

Comments
 (0)