diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e1485879..81a8d9bcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - SqlServerDsc - Added build tasks to generate Wiki documentation for public commands. +- SqlDatabaseMail + - Added the parameter `UseDefaultCredentials` to control use of the DatabaseEngine + service account for SMTP server authentication. ### Fixed diff --git a/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.psm1 b/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.psm1 index 9aecdfc8f..25b965625 100644 --- a/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.psm1 +++ b/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.psm1 @@ -64,18 +64,19 @@ function Get-TargetResource ) $returnValue = @{ - Ensure = 'Absent' - ServerName = $ServerName - InstanceName = $InstanceName - AccountName = $null - EmailAddress = $null - MailServerName = $null - LoggingLevel = $null - ProfileName = $null - DisplayName = $null - ReplyToAddress = $null - Description = $null - TcpPort = $null + Ensure = 'Absent' + ServerName = $ServerName + InstanceName = $InstanceName + AccountName = $null + EmailAddress = $null + MailServerName = $null + LoggingLevel = $null + ProfileName = $null + DisplayName = $null + ReplyToAddress = $null + Description = $null + TcpPort = $null + UseDefaultCredentials = $null } Write-Verbose -Message ( @@ -145,6 +146,7 @@ function Get-TargetResource { $returnValue['MailServerName'] = $mailServer.Name $returnValue['TcpPort'] = $mailServer.Port + $returnValue['UseDefaultCredentials'] = $mailServer.UseDefaultCredentials } $mailProfile = $databaseMail.Profiles | @@ -233,10 +235,19 @@ function Get-TargetResource .PARAMETER TcpPort The TCP port used for communication. Default value is port 25. + .PARAMETER UseDefaultCredentials + Controls use of the DatabaseEngine service account for SMTP server authentication. + If $true, the DatabaseEngine service account is used access the SMTP server. + If $false, DatabaseEngine service account is not used. + .NOTES Information about the different properties can be found here https://docs.microsoft.com/en-us/sql/relational-databases/database-mail/configure-database-mail. + "UseDefaultCredentials" corresponds to "Windows Authentication using Database Engine service credentials" + described at the above link. This dsc resource does not yet address setting state for basic or anonymous + SMTP access that's used when UseDefaultCredentials is false. + #> function Set-TargetResource { @@ -293,7 +304,11 @@ function Set-TargetResource [Parameter()] [System.UInt16] - $TcpPort = 25 + $TcpPort = 25, + + [Parameter()] + [System.Boolean] + $UseDefaultCredentials ) Write-Verbose -Message ( @@ -382,6 +397,11 @@ function Set-TargetResource $mailServer.Port = $TcpPort } + if ($PSBoundParameters.ContainsKey('UseDefaultCredentials')) + { + $mailServer.UseDefaultCredentials = $UseDefaultCredentials + } + $mailServer.Alter() } } @@ -483,6 +503,21 @@ function Set-TargetResource $mailServer.Port = $TcpPort $mailServer.Alter() } + + $currentUseDefaultCredentials = $mailServer.UseDefaultCredentials + if ($PSBoundParameters.ContainsKey('UseDefaultCredentials') -and $currentUseDefaultCredentials -ne $UseDefaultCredentials) + { + Write-Verbose -Message ( + $script:localizedData.UpdatingPropertyOfMailServer -f @( + $currentUseDefaultCredentials + $UseDefaultCredentials + $script:localizedData.MailServerPropertyUseDefaultCredentials + ) + ) + + $mailServer.UseDefaultCredentials = $UseDefaultCredentials + $mailServer.Alter() + } } $databaseMailProfile = $databaseMail.Profiles | Where-Object -FilterScript { @@ -633,6 +668,11 @@ function Set-TargetResource .PARAMETER TcpPort The TCP port used for communication. Default value is port 25. + + .PARAMETER UseDefaultCredentials + Controls use of the DatabaseEngine service account for SMTP server authentication. + If $true, the DatabaseEngine service account is used access the SMTP server. + If $false, DatabaseEngine service account is not used. #> function Test-TargetResource { @@ -691,7 +731,11 @@ function Test-TargetResource [Parameter()] [System.UInt16] - $TcpPort = 25 + $TcpPort = 25, + + [Parameter()] + [System.Boolean] + $UseDefaultCredentials ) $getTargetResourceParameters = @{ @@ -727,6 +771,7 @@ function Test-TargetResource 'DisplayName' 'Description' 'LoggingLevel' + 'UseDefaultCredentials' ) TurnOffTypeChecking = $true Verbose = $VerbosePreference diff --git a/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.schema.mof b/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.schema.mof index ca6ad931d..4977b0346 100644 --- a/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.schema.mof +++ b/source/DSCResources/DSC_SqlDatabaseMail/DSC_SqlDatabaseMail.schema.mof @@ -13,4 +13,5 @@ class DSC_SqlDatabaseMail : OMI_BaseResource [Write, Description("The description for the _Database Mail_ profile and account.")] String Description; [Write, Description("The logging level that the _Database Mail_ will use. If not specified the default logging level is `'Extended'`."), ValueMap{"Normal","Extended","Verbose"}, Values{"Normal","Extended","Verbose"}] String LoggingLevel; [Write, Description("The TCP port used for communication. Default value is port `25`.")] UInt16 TcpPort; + [Write, Description("Specifies if the DatabaseEngine credentials are used for SMTP server authentication.")] Boolean UseDefaultCredentials; }; diff --git a/source/DSCResources/DSC_SqlDatabaseMail/en-US/DSC_SqlDatabaseMail.strings.psd1 b/source/DSCResources/DSC_SqlDatabaseMail/en-US/DSC_SqlDatabaseMail.strings.psd1 index 90da1b63b..910315e34 100644 --- a/source/DSCResources/DSC_SqlDatabaseMail/en-US/DSC_SqlDatabaseMail.strings.psd1 +++ b/source/DSCResources/DSC_SqlDatabaseMail/en-US/DSC_SqlDatabaseMail.strings.psd1 @@ -22,6 +22,7 @@ ConvertFrom-StringData @' MailServerPropertyReplyToEmailAddress = reply to e-mail address MailServerPropertyServerName = server name MailServerPropertyTcpPort = TCP port + MailServerPropertyUseDefaultCredentials = Use default credentials CreatingMailProfile = Creating a public default profile '{0}'. MailProfileExist = The public default profile '{0}' already exist. ConfigureSqlAgent = Configure the SQL Agent to use Database Mail. diff --git a/tests/Unit/DSC_SqlDatabaseMail.Tests.ps1 b/tests/Unit/DSC_SqlDatabaseMail.Tests.ps1 index e22404a98..82a2b7a14 100644 --- a/tests/Unit/DSC_SqlDatabaseMail.Tests.ps1 +++ b/tests/Unit/DSC_SqlDatabaseMail.Tests.ps1 @@ -75,6 +75,7 @@ Describe 'DSC_SqlDatabaseMail\Get-TargetResource' -Tag 'Get' { $mockDisplayName = $mockMailServerName $mockDescription = 'My mail description' $mockTcpPort = 25 + $mockUseDefaultCredentials = $false $mockDatabaseMailDisabledConfigValue = 0 $mockDatabaseMailEnabledConfigValue = 1 @@ -91,7 +92,8 @@ Describe 'DSC_SqlDatabaseMail\Get-TargetResource' -Tag 'Get' { return @( New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockMailServerName -PassThru | - Add-Member -MemberType NoteProperty -Name 'Port' -Value $mockTcpPort -PassThru -Force + Add-Member -MemberType NoteProperty -Name 'Port' -Value $mockTcpPort -PassThru -Force | + Add-Member -MemberType NoteProperty -Name 'UseDefaultCredentials' -Value $mockUseDefaultCredentials -PassThru -Force ) } -PassThru -Force } @@ -200,6 +202,7 @@ Describe 'DSC_SqlDatabaseMail\Get-TargetResource' -Tag 'Get' { $getTargetResourceResult.ReplyToAddress | Should -BeNullOrEmpty $getTargetResourceResult.Description | Should -BeNullOrEmpty $getTargetResourceResult.TcpPort | Should -BeNullOrEmpty + $getTargetResourceResult.UseDefaultCredentials | Should -BeNullOrEmpty } Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It @@ -257,15 +260,16 @@ Describe 'DSC_SqlDatabaseMail\Get-TargetResource' -Tag 'Get' { It 'Should return the correct values for the rest of the properties' { $inModuleScopeParameters = @{ - MockAccountName = $mockAccountName - MockEmailAddress = $mockEmailAddress - MockMailServerName = $mockMailServerName - MockProfileName = $mockProfileName - MockLoggingLevel = $mockLoggingLevelNormal - MockDisplayName = $mockDisplayName - MockReplyToAddress = $mockReplyToAddress - MockDescription = $mockDescription - MockTcpPort = $mockTcpPort + MockAccountName = $mockAccountName + MockEmailAddress = $mockEmailAddress + MockMailServerName = $mockMailServerName + MockProfileName = $mockProfileName + MockLoggingLevel = $mockLoggingLevelNormal + MockDisplayName = $mockDisplayName + MockReplyToAddress = $mockReplyToAddress + MockDescription = $mockDescription + MockTcpPort = $mockTcpPort + MockUseDefaultCredentials = $mockUseDefaultCredentials } InModuleScope -Parameters $inModuleScopeParameters -ScriptBlock { @@ -280,6 +284,7 @@ Describe 'DSC_SqlDatabaseMail\Get-TargetResource' -Tag 'Get' { $getTargetResourceResult.ReplyToAddress | Should -Be $MockReplyToAddress $getTargetResourceResult.Description | Should -Be $MockDescription $getTargetResourceResult.TcpPort | Should -Be $MockTcpPort + $getTargetResourceResult.UseDefaultCredentials | Should -Be $MockUseDefaultCredentials } Should -Invoke -CommandName Connect-SQL -Exactly -Times 1 -Scope It @@ -410,6 +415,7 @@ Describe 'DSC_SqlDatabaseMail\Test-TargetResource' -Tag 'Test' { $mockDisplayName = $mockMailServerName $mockDescription = 'My mail description' $mockTcpPort = 25 + $mockUseDefaultCredentials = $false $mockLoggingLevel = 'Normal' InModuleScope -ScriptBlock { @@ -454,29 +460,31 @@ Describe 'DSC_SqlDatabaseMail\Test-TargetResource' -Tag 'Test' { BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ - Ensure = 'Present' - ServerName = $mockServerName - InstanceName = $mockInstanceName - AccountName = $mockAccountName - EmailAddress = $mockEmailAddress - MailServerName = $mockMailServerName - LoggingLevel = $mockLoggingLevel - ProfileName = $mockProfileName - DisplayName = $mockDisplayName - ReplyToAddress = $mockReplyToAddress - Description = $mockDescription - TcpPort = $mockTcpPort + Ensure = 'Present' + ServerName = $mockServerName + InstanceName = $mockInstanceName + AccountName = $mockAccountName + EmailAddress = $mockEmailAddress + MailServerName = $mockMailServerName + LoggingLevel = $mockLoggingLevel + ProfileName = $mockProfileName + DisplayName = $mockDisplayName + ReplyToAddress = $mockReplyToAddress + Description = $mockDescription + TcpPort = $mockTcpPort + UseDefaultCredentials = $mockUseDefaultCredentials } } } It 'Should return the state as $true' { $inModuleScopeParameters = @{ - MockLoggingLevel = $mockLoggingLevel - MockDisplayName = $mockDisplayName - MockReplyToAddress = $mockReplyToAddress - MockDescription = $mockDescription - MockTcpPort = $mockTcpPort + MockLoggingLevel = $mockLoggingLevel + MockDisplayName = $mockDisplayName + MockReplyToAddress = $mockReplyToAddress + MockDescription = $mockDescription + MockTcpPort = $mockTcpPort + MockUseDefaultCredentials = $mockUseDefaultCredentials } InModuleScope -Parameters $inModuleScopeParameters -ScriptBlock { @@ -486,6 +494,7 @@ Describe 'DSC_SqlDatabaseMail\Test-TargetResource' -Tag 'Test' { $testTargetResourceParameters.ReplyToAddress = $MockReplyToAddress $testTargetResourceParameters.Description = $MockDescription $testTargetResourceParameters.TcpPort = $MockTcpPort + $testTargetResourceParameters.UseDefaultCredentials = $MockUseDefaultCredentials $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters @@ -555,24 +564,29 @@ Describe 'DSC_SqlDatabaseMail\Test-TargetResource' -Tag 'Test' { Property = 'TcpPort' PropertyValue = '2525' } + @{ + Property = 'UseDefaultCredentials' + PropertyValue = $true + } ) } BeforeAll { Mock -CommandName Get-TargetResource -MockWith { return @{ - Ensure = 'Present' - ServerName = $mockServerName - InstanceName = $mockInstanceName - AccountName = $mockAccountName - EmailAddress = $mockEmailAddress - MailServerName = $mockMailServerName - LoggingLevel = 'Normal' - ProfileName = $mockProfileName - DisplayName = $mockDisplayName - ReplyToAddress = $mockReplyToAddress - Description = $mockDescription - TcpPort = $mockTcpPort + Ensure = 'Present' + ServerName = $mockServerName + InstanceName = $mockInstanceName + AccountName = $mockAccountName + EmailAddress = $mockEmailAddress + MailServerName = $mockMailServerName + LoggingLevel = 'Normal' + ProfileName = $mockProfileName + DisplayName = $mockDisplayName + ReplyToAddress = $mockReplyToAddress + Description = $mockDescription + TcpPort = $mockTcpPort + UseDefaultCredentials = $mockUseDefaultCredentials } } } @@ -631,6 +645,7 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { $mockDisplayName = $mockMailServerName $mockDescription = 'My mail description' $mockTcpPort = 25 + $mockUseDefaultCredentials = $false $mockDatabaseMailDisabledConfigValue = 0 $mockDatabaseMailEnabledConfigValue = 1 @@ -670,6 +685,7 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockMailServerName -PassThru | Add-Member -MemberType NoteProperty -Name 'Port' -Value $mockTcpPort -PassThru | + Add-Member -MemberType NoteProperty -Name 'UseDefaultCredentials' -Value $mockUseDefaultCredentials -PassThru | Add-Member -MemberType ScriptMethod -Name 'Rename' -Value { InModuleScope -ScriptBlock { $script:MailServerRenameMethodCallCount += 1 @@ -872,11 +888,12 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { It 'Should call the correct methods without throwing' { $inModuleScopeParameters = @{ - MockLoggingLevel = $mockLoggingLevelNormal - MockDisplayName = $mockDisplayName - MockReplyToAddress = $mockReplyToAddress - MockDescription = $mockDescription - MockTcpPort = $mockTcpPort + MockLoggingLevel = $mockLoggingLevelNormal + MockDisplayName = $mockDisplayName + MockReplyToAddress = $mockReplyToAddress + MockDescription = $mockDescription + MockTcpPort = $mockTcpPort + MockUseDefaultCredentials = $mockUseDefaultCredentials } InModuleScope -Parameters $inModuleScopeParameters -ScriptBlock { @@ -886,6 +903,7 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { $setTargetResourceParameters['Description'] = $MockDescription $setTargetResourceParameters['LoggingLevel'] = $MockLoggingLevel $setTargetResourceParameters['TcpPort'] = $MockTcpPort + $setTargetResourceParameters['UseDefaultCredentials'] = $MockUseDefaultCredentials { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw @@ -975,6 +993,7 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { $setTargetResourceParameters['ProfileName'] = 'MissingProfile' # Also passing TcpPort when passing in MailServerName to add to code coverage $setTargetResourceParameters['TcpPort'] = 2525 + $setTargetResourceParameters['UseDefaultCredentials'] = $true { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw @@ -1029,6 +1048,10 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { Property = 'TcpPort' PropertyValue = '2525' } + @{ + Property = 'UseDefaultCredentials' + PropertyValue = $true + } ) } @@ -1075,6 +1098,18 @@ Describe 'DSC_SqlDatabaseMail\Set-TargetResource' -Tag 'Set' { $script:JobServerAlterMethodCallCount | Should -Be 0 $script:LoggingLevelAlterMethodCallCount | Should -Be 0 } + elseif ($Property -eq 'UseDefaultCredentials') + { + $script:MailServerRenameMethodCallCount | Should -Be 0 + $script:MailServerAlterMethodCallCount | Should -Be 1 + $script:MailAccountAlterMethodCallCount | Should -Be 0 + $script:MailProfileCreateMethodCallCount | Should -Be 0 + $script:MailProfileAlterMethodCallCount | Should -Be 0 + $script:MailProfileAddPrincipalMethodCallCount | Should -Be 0 + $script:MailProfileAddAccountMethodCallCount | Should -Be 0 + $script:JobServerAlterMethodCallCount | Should -Be 0 + $script:LoggingLevelAlterMethodCallCount | Should -Be 0 + } elseif ($Property -eq 'LoggingLevel') { $script:MailServerRenameMethodCallCount | Should -Be 0