Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6000673
Initial plan
Copilot Sep 6, 2025
98100f5
Implement Set-SqlDscDatabaseDefault command with tests and documentation
Copilot Sep 6, 2025
5b4faa9
Fix file endings and replace Should -Not -Throw with direct command c…
Copilot Sep 6, 2025
8dadb42
Merge branch 'main' into copilot/fix-2178
johlju Sep 6, 2025
116623e
Replace New-InvalidOperationException with PSCmdlet.ThrowTerminatingE…
Copilot Sep 6, 2025
7e61feb
Fix integ test
johlju Sep 6, 2025
430a830
Merge branch 'main' into copilot/fix-2178
johlju Sep 6, 2025
b6c41f6
fix instructions
johlju Sep 6, 2025
950d028
Fix PSCmdlet.ThrowTerminatingError() to include exception parameter
Copilot Sep 6, 2025
bb57a89
Refine AI and DSC community guidelines for clarity and consistency
johlju Sep 6, 2025
c25798a
Update error handling guidelines to include try-catch for terminating…
johlju Sep 6, 2025
3c125da
Refactor verbose message variables in Set-SqlDscDatabaseDefault funct…
johlju Sep 6, 2025
c4aa5ce
Add guideline to avoid Write-Verbose inside ShouldProcess block for s…
johlju Sep 6, 2025
2c9585d
Enhance Set-SqlDscDatabaseDefault function with detailed ShouldProces…
johlju Sep 6, 2025
fc59c28
Consolidate PowerShell style and test guideline instructions in commu…
johlju Sep 6, 2025
0d297cf
Refactor `Set-SqlDscDatabaseDefault` command documentation for clarit…
johlju Sep 6, 2025
20de1f5
Update CHANGELOG.md to clarify the purpose of Set-SqlDscDatabaseDefau…
johlju Sep 6, 2025
75fb8d8
Add INPUTS section to Set-SqlDscDatabaseDefault documentation for pip…
johlju Sep 6, 2025
b0dc201
Remove verbose messages for updating default file group, file stream …
johlju Sep 6, 2025
1c5571b
Update database default object strings to use new identifier format
johlju Sep 6, 2025
a9117e5
Remove redundant OutputType attribute from Set-SqlDscDatabaseDefault …
johlju Sep 6, 2025
dfd2468
Refactor Set-SqlDscDatabaseDefault to improve error handling and stre…
johlju Sep 6, 2025
4106fe0
Add "filegroup" to cSpell words in settings.json
johlju Sep 6, 2025
e7ba896
Update error code in Set-SqlDscDatabaseDefault and clean up test cases
johlju Sep 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Added setup workflow for GitHub Copilot.
- Switch the workflow to use Linux.
- `Set-SqlDscDatabaseDefault`
- Added new command to set default objects of a database in a SQL Server Database Engine instance.
- The command can set the default filegroup, default FILESTREAM filegroup, and default Full-Text catalog
using SMO methods SetDefaultFileGroup, SetDefaultFileStreamFileGroup, and SetDefaultFullTextCatalog.
- Supports both ServerObject with Name parameter set and DatabaseObject parameter set.
- Includes comprehensive unit tests and integration tests.
- Attempt to unshallow the Copilot branch
- `SqlAgentAlert`
- Added new DSC resource to manage SQL Server Agent alerts.
Expand Down
194 changes: 194 additions & 0 deletions source/Public/Set-SqlDscDatabaseDefault.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<#
.SYNOPSIS
Sets default objects of a database in a SQL Server Database Engine instance.

.DESCRIPTION
This command sets default objects of a database in a SQL Server Database Engine instance.
It can set the default filegroup, default FILESTREAM filegroup, and default Full-Text catalog
using SMO methods.

.PARAMETER ServerObject
Specifies current server connection object.

.PARAMETER DatabaseObject
Specifies a database object to modify.

.PARAMETER Name
Specifies the name of the database to be modified.

.PARAMETER DefaultFileGroup
Sets the default filegroup for the database. The filegroup must exist in the database.

.PARAMETER DefaultFileStreamFileGroup
Sets the default FILESTREAM filegroup for the database. The filegroup must exist in the database.

.PARAMETER DefaultFullTextCatalog
Sets the default Full-Text catalog for the database. The catalog must exist in the database.

.PARAMETER Force
Specifies that the database defaults should be modified without any confirmation.

.PARAMETER Refresh
Specifies that the **ServerObject**'s databases should be refreshed before
modifying the database object. This is helpful when databases could have been
modified outside of the **ServerObject**, for example through T-SQL. But
on instances with a large amount of databases it might be better to make
sure the **ServerObject** is recent enough, or pass in **DatabaseObject**.

.PARAMETER PassThru
Specifies that the database object should be returned after modification.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
$databaseObject = $serverObject | Get-SqlDscDatabase -Name 'MyDatabase'
$databaseObject | Set-SqlDscDatabaseDefault -DefaultFileGroup 'MyFileGroup'

Sets the default filegroup of the database named **MyDatabase** to **MyFileGroup**.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
$serverObject | Set-SqlDscDatabaseDefault -Name 'MyDatabase' -DefaultFullTextCatalog 'MyCatalog' -Force

Sets the default Full-Text catalog of the database named **MyDatabase** to **MyCatalog** without prompting for confirmation.

.EXAMPLE
$serverObject = Connect-SqlDscDatabaseEngine -InstanceName 'MyInstance'
$databaseObject = $serverObject | Get-SqlDscDatabase -Name 'MyDatabase'
$databaseObject | Set-SqlDscDatabaseDefault -DefaultFileGroup 'DataFileGroup' -DefaultFileStreamFileGroup 'FileStreamFileGroup' -DefaultFullTextCatalog 'FTCatalog'

Sets multiple default objects for the database named **MyDatabase**.

.OUTPUTS
None. But when **PassThru** is specified the output is `[Microsoft.SqlServer.Management.Smo.Database]`.
#>
function Set-SqlDscDatabaseDefault
{
[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.')]
[OutputType()]
[OutputType([Microsoft.SqlServer.Management.Smo.Database])]
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'Medium')]
param
(
[Parameter(ParameterSetName = 'ServerObject', Mandatory = $true, ValueFromPipeline = $true)]
[Microsoft.SqlServer.Management.Smo.Server]
$ServerObject,

[Parameter(ParameterSetName = 'DatabaseObject', Mandatory = $true, ValueFromPipeline = $true)]
[Microsoft.SqlServer.Management.Smo.Database]
$DatabaseObject,

[Parameter(ParameterSetName = 'ServerObject', Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[System.String]
$Name,

[Parameter()]
[ValidateNotNullOrEmpty()]
[System.String]
$DefaultFileGroup,

[Parameter()]
[ValidateNotNullOrEmpty()]
[System.String]
$DefaultFileStreamFileGroup,

[Parameter()]
[ValidateNotNullOrEmpty()]
[System.String]
$DefaultFullTextCatalog,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$Force,

[Parameter(ParameterSetName = 'ServerObject')]
[System.Management.Automation.SwitchParameter]
$Refresh,

[Parameter()]
[System.Management.Automation.SwitchParameter]
$PassThru
)

process
{
if ($PSCmdlet.ParameterSetName -eq 'ServerObject')
{
if ($Refresh.IsPresent)
{
# Refresh the server object's databases collection
$ServerObject.Databases.Refresh()
}

Write-Verbose -Message ($script:localizedData.DatabaseDefault_Set -f $Name, $ServerObject.InstanceName)

# Get the database object
$DatabaseObject = $ServerObject.Databases[$Name]

if (-not $DatabaseObject)
{
$errorMessage = $script:localizedData.Database_NotFound -f $Name
New-InvalidOperationException -Message $errorMessage
}
}
else
{
$Name = $DatabaseObject.Name
$ServerObject = $DatabaseObject.Parent
Write-Verbose -Message ($script:localizedData.DatabaseDefault_Set -f $Name, $ServerObject.InstanceName)
}

if ($Force.IsPresent -and -not $Confirm)
{
$ConfirmPreference = 'None'
}

$verboseDescriptionMessage = $script:localizedData.DatabaseDefault_Set_ShouldProcessVerboseDescription -f $Name, $ServerObject.InstanceName
$verboseWarningMessage = $script:localizedData.DatabaseDefault_Set_ShouldProcessVerboseWarning -f $Name
$captionMessage = $script:localizedData.DatabaseDefault_Set_ShouldProcessCaption

if ($PSCmdlet.ShouldProcess($verboseDescriptionMessage, $verboseWarningMessage, $captionMessage))
{
try
{
$wasUpdate = $false

if ($PSBoundParameters.ContainsKey('DefaultFileGroup'))
{
Write-Verbose -Message ($script:localizedData.DatabaseDefault_UpdatingDefaultFileGroup -f $DefaultFileGroup)
$DatabaseObject.SetDefaultFileGroup($DefaultFileGroup)
$wasUpdate = $true
}

if ($PSBoundParameters.ContainsKey('DefaultFileStreamFileGroup'))
{
Write-Verbose -Message ($script:localizedData.DatabaseDefault_UpdatingDefaultFileStreamFileGroup -f $DefaultFileStreamFileGroup)
$DatabaseObject.SetDefaultFileStreamFileGroup($DefaultFileStreamFileGroup)
$wasUpdate = $true
}

if ($PSBoundParameters.ContainsKey('DefaultFullTextCatalog'))
{
Write-Verbose -Message ($script:localizedData.DatabaseDefault_UpdatingDefaultFullTextCatalog -f $DefaultFullTextCatalog)
$DatabaseObject.SetDefaultFullTextCatalog($DefaultFullTextCatalog)
$wasUpdate = $true
}

if ($wasUpdate)
{
Write-Verbose -Message ($script:localizedData.DatabaseDefault_Updated -f $Name)
}

if ($PassThru.IsPresent)
{
return $DatabaseObject
}
}
catch
{
$errorMessage = $script:localizedData.DatabaseDefault_SetFailed -f $Name, $ServerObject.InstanceName
New-InvalidOperationException -Message $errorMessage -ErrorRecord $_
}
}
}
}
12 changes: 12 additions & 0 deletions source/en-US/SqlServerDsc.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,18 @@ ConvertFrom-StringData @'
Database_RecoveryModelWrong = The database '{0}' exists and has the recovery model '{1}', but expected it to have the recovery model '{2}'.
Database_OwnerNameWrong = The database '{0}' exists and has the owner '{1}', but expected it to have the owner '{2}'.

## Set-SqlDscDatabaseDefault
DatabaseDefault_Set = Setting default objects of database '{0}' on instance '{1}'. (SSDD0001)
DatabaseDefault_Updated = Database '{0}' default objects were updated successfully. (SSDD0002)
DatabaseDefault_SetFailed = Failed to set default objects of database '{0}' on instance '{1}'. (SSDD0003)
DatabaseDefault_UpdatingDefaultFileGroup = Setting the default filegroup to '{0}'. (SSDD0004)
DatabaseDefault_UpdatingDefaultFileStreamFileGroup = Setting the default FILESTREAM filegroup to '{0}'. (SSDD0005)
DatabaseDefault_UpdatingDefaultFullTextCatalog = Setting the default Full-Text catalog to '{0}'. (SSDD0006)
DatabaseDefault_Set_ShouldProcessVerboseDescription = Setting default objects of the database '{0}' on the instance '{1}'.
DatabaseDefault_Set_ShouldProcessVerboseWarning = Are you sure you want to modify the default objects of the database '{0}'?
# This string shall not end with full stop (.) since it is used as a title of ShouldProcess messages.
DatabaseDefault_Set_ShouldProcessCaption = Set database default objects on instance

## Get-AgentAlertObject
Get_AgentAlertObject_GettingAlert = Getting SQL Agent Alert '{0}'. (GAAO0001)

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')]
param ()

BeforeDiscovery {
try
{
if (-not (Get-Module -Name 'DscResource.Test'))
{
# Assumes dependencies have been resolved, so if this module is not available, run 'noop' task.
if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable))
{
# Redirect all streams to $null, except the error stream (stream 2)
& "$PSScriptRoot/../../../build.ps1" -Tasks 'noop' 3>&1 4>&1 5>&1 6>&1 > $null
}

# If the dependencies have not been resolved, this will throw an error.
Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop'
}
}
catch [System.IO.FileNotFoundException]
{
throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.'
}
}

BeforeAll {
$script:moduleName = 'SqlServerDsc'

Import-Module -Name $script:moduleName -Force -ErrorAction 'Stop'
}

Describe 'Set-SqlDscDatabaseDefault' -Tag @('Integration_SQL2017', 'Integration_SQL2019', 'Integration_SQL2022') {
BeforeAll {
# Starting the named instance SQL Server service prior to running tests.
Start-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'

$script:mockInstanceName = 'DSCSQLTEST'
$script:mockComputerName = Get-ComputerName

$mockSqlAdministratorUserName = 'SqlAdmin' # Using computer name as NetBIOS name throw exception.
$mockSqlAdministratorPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force

$script:mockSqlAdminCredential = [System.Management.Automation.PSCredential]::new($mockSqlAdministratorUserName, $mockSqlAdministratorPassword)

$script:serverObject = Connect-SqlDscDatabaseEngine -InstanceName $script:mockInstanceName -Credential $script:mockSqlAdminCredential

# Test database names
$script:testDatabaseName = 'SqlDscTestSetDatabaseDefault_' + (Get-Random)

# Create test database for the integration tests
$script:testDatabaseObject = New-SqlDscDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName -Force

# Create additional filegroup for testing (needed for setting default filegroup)
$script:testFileGroupName = 'TestFileGroup_' + (Get-Random)
$script:serverObject.Databases[$script:testDatabaseName].Query("ALTER DATABASE [$script:testDatabaseName] ADD FILEGROUP [$script:testFileGroupName]")

# Add a file to the filegroup so it can be set as default
$script:testFileName = 'TestFile_' + (Get-Random)
$script:serverObject.Databases[$script:testDatabaseName].Query("ALTER DATABASE [$script:testDatabaseName] ADD FILE (NAME = '$script:testFileName', FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL15.DSCSQLTEST\MSSQL\DATA\$script:testFileName.ndf') TO FILEGROUP [$script:testFileGroupName]")
}

AfterAll {
# Disconnect from the database engine.
Disconnect-SqlDscDatabaseEngine -ServerObject $script:serverObject

# Stopping the named instance SQL Server service after running tests.
Stop-Service -Name 'MSSQL$DSCSQLTEST' -Verbose -ErrorAction 'Stop'
}

Context 'When using the DatabaseObject parameter' {
It 'Should set the default filegroup without throwing an error' {
{ Set-SqlDscDatabaseDefault -DatabaseObject $script:testDatabaseObject -DefaultFileGroup $script:testFileGroupName -Force } | Should -Not -Throw

# Verify the change was applied
$script:testDatabaseObject.Refresh()
$script:testDatabaseObject.DefaultFileGroup | Should -Be $script:testFileGroupName
}

It 'Should reset the default filegroup back to PRIMARY' {
{ Set-SqlDscDatabaseDefault -DatabaseObject $script:testDatabaseObject -DefaultFileGroup 'PRIMARY' -Force } | Should -Not -Throw

# Verify the change was applied
$script:testDatabaseObject.Refresh()
$script:testDatabaseObject.DefaultFileGroup | Should -Be 'PRIMARY'
}
}

Context 'When using the ServerObject parameter' {
It 'Should set the default filegroup using server object and database name' {
{ Set-SqlDscDatabaseDefault -ServerObject $script:serverObject -Name $script:testDatabaseName -DefaultFileGroup $script:testFileGroupName -Force } | Should -Not -Throw

# Verify the change was applied by refreshing the database object
$script:testDatabaseObject.Refresh()
$script:testDatabaseObject.DefaultFileGroup | Should -Be $script:testFileGroupName
}

It 'Should return the database object when PassThru is specified' {
$result = Set-SqlDscDatabaseDefault -ServerObject $script:serverObject -Name $script:testDatabaseName -DefaultFileGroup 'PRIMARY' -PassThru -Force

$result | Should -Not -BeNullOrEmpty
$result.Name | Should -Be $script:testDatabaseName
$result.DefaultFileGroup | Should -Be 'PRIMARY'
}
}

Context 'When the command fails' {
It 'Should throw an error when trying to set a non-existent filegroup as default' {
{ Set-SqlDscDatabaseDefault -DatabaseObject $script:testDatabaseObject -DefaultFileGroup 'NonExistentFileGroup' -Force } | Should -Throw
}

It 'Should throw an error when database is not found' {
{ Set-SqlDscDatabaseDefault -ServerObject $script:serverObject -Name 'NonExistentDatabase' -DefaultFileGroup 'PRIMARY' -Force } | Should -Throw
}
}

Context 'After all tests are completed' {
It 'Should clean up the test database' {
{ Remove-SqlDscDatabase -ServerObject $script:serverObject -Name $script:testDatabaseName -Force } | Should -Not -Throw
}
}
}
Loading
Loading