From c99d2fa1192838705f3bfdef2338329aabc4f0a6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Tue, 17 Mar 2026 09:03:37 +0000 Subject: [PATCH] New-DbaDbMailAccount, Set-DbaDbMailAccount - Add Port, SSL, and authentication parameters - Enhanced New-DbaDbMailAccount with Port, EnableSSL, UseDefaultCredentials, UserName, and Password parameters for SMTP server configuration - Created Set-DbaDbMailAccount for modifying existing mail accounts and their mail server settings (port, SSL, auth, server rename) - Updated New-DbaDbMailAccount parameter validation tests - Created integration and unit tests for Set-DbaDbMailAccount - Registered Set-DbaDbMailAccount in dbatools.psd1 and dbatools.psm1 Closes #9139 (do *MailAccount*) Co-authored-by: Andreas Jordan --- dbatools.psd1 | 1 + dbatools.psm1 | 1 + public/New-DbaDbMailAccount.ps1 | 76 +++++++++- public/Set-DbaDbMailAccount.ps1 | 200 +++++++++++++++++++++++++++ tests/New-DbaDbMailAccount.Tests.ps1 | 5 + tests/Set-DbaDbMailAccount.Tests.ps1 | 129 +++++++++++++++++ 6 files changed, 409 insertions(+), 3 deletions(-) create mode 100644 public/Set-DbaDbMailAccount.ps1 create mode 100644 tests/Set-DbaDbMailAccount.Tests.ps1 diff --git a/dbatools.psd1 b/dbatools.psd1 index 8ba552125e7c..24f36fbcc90e 100644 --- a/dbatools.psd1 +++ b/dbatools.psd1 @@ -621,6 +621,7 @@ 'Set-DbaDbFileGroup', 'Set-DbaDbFileGrowth', 'Set-DbaDbIdentity', + 'Set-DbaDbMailAccount', 'Set-DbaDbMirror', 'Set-DbaDbOwner', 'Set-DbaDbQueryStoreOption', diff --git a/dbatools.psm1 b/dbatools.psm1 index c07409453ec8..1afe4f2ad1ab 100644 --- a/dbatools.psm1 +++ b/dbatools.psm1 @@ -710,6 +710,7 @@ if ($PSVersionTable.PSVersion.Major -lt 5) { 'New-DbaDbMailServer', 'New-DbaDbMailAccount', 'New-DbaDbMailProfile', + 'Set-DbaDbMailAccount', 'Get-DbaResourceGovernor', 'Get-DbaRgResourcePool', 'Get-DbaRgWorkloadGroup', diff --git a/public/New-DbaDbMailAccount.ps1 b/public/New-DbaDbMailAccount.ps1 index 0c6325b1f773..11509c563c67 100644 --- a/public/New-DbaDbMailAccount.ps1 +++ b/public/New-DbaDbMailAccount.ps1 @@ -40,6 +40,28 @@ function New-DbaDbMailAccount { Specifies the SMTP server hostname or IP address that SQL Server will use to send emails through this account. The server must be accessible from the SQL Server instance. If not specified, uses the SQL Server instance name as the mail server. The function validates that the mail server exists unless -Force is used. + .PARAMETER Port + Specifies the TCP port number used to connect to the SMTP server. Common values are 25 (standard SMTP), 465 (SMTPS), and 587 (SMTP with STARTTLS). + Use 587 for Office 365 and Gmail which require STARTTLS. If not specified, the default port of 25 is used. + + .PARAMETER EnableSSL + Enables SSL/TLS encryption for the SMTP connection. Required for connecting to Office 365 (smtp.office365.com:587) and Gmail (smtp.gmail.com:587). + When enabled, the connection uses STARTTLS to upgrade to an encrypted connection. + + .PARAMETER UseDefaultCredentials + Configures the mail account to use Windows integrated security (the SQL Server service account credentials) for SMTP authentication. + Use this for internal mail relays in Windows domains that support Windows Authentication. Cannot be combined with UserName/Password. + + .PARAMETER UserName + Specifies the username for SMTP authentication when connecting to mail servers that require credentials. + For Office 365, use the full email address (e.g., 'alerts@company.com'). For Gmail, use the Gmail address. + Requires the -Password parameter to be specified as well. + + .PARAMETER Password + Specifies the password for SMTP authentication as a SecureString. Used in combination with -UserName for Basic authentication. + Create with: ConvertTo-SecureString 'yourpassword' -AsPlainText -Force + For Office 365, use an app-specific password if multi-factor authentication is enabled on the account. + .PARAMETER WhatIf If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. @@ -96,6 +118,33 @@ function New-DbaDbMailAccount { Creates a new database mail account with the email address admin@ad.local on sql2017 named "The DBA Team" using the smtp.ad.local mail server. + .EXAMPLE + PS C:\> $splatAccount = @{ + >> SqlInstance = 'sql2017' + >> Account = 'Office365Alerts' + >> EmailAddress = 'alerts@company.com' + >> MailServer = 'smtp.office365.com' + >> Port = 587 + >> EnableSSL = $true + >> UserName = 'alerts@company.com' + >> Password = (ConvertTo-SecureString 'app-password' -AsPlainText -Force) + >> } + PS C:\> New-DbaDbMailAccount @splatAccount + + Creates a new database mail account configured for Office 365 with SSL and authentication on sql2017. + + .EXAMPLE + PS C:\> $splatAccount = @{ + >> SqlInstance = 'sql2017' + >> Account = 'DomainRelay' + >> EmailAddress = 'sqlserver@company.local' + >> MailServer = 'smtp.company.local' + >> UseDefaultCredentials = $true + >> } + PS C:\> New-DbaDbMailAccount @splatAccount + + Creates a mail account that uses Windows integrated authentication (the SQL Server service account) for an internal domain mail relay. + #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Low")] param ( @@ -111,6 +160,11 @@ function New-DbaDbMailAccount { [string]$EmailAddress, [string]$ReplyToAddress, [string]$MailServer, + [int]$Port, + [switch]$EnableSSL, + [switch]$UseDefaultCredentials, + [string]$UserName, + [System.Security.SecureString]$Password, [switch]$Force, [switch]$EnableException ) @@ -141,8 +195,24 @@ function New-DbaDbMailAccount { } try { - $accountObj.MailServers.Item($($server.DomainInstanceName)).Rename($MailServer) - $accountObj.Alter() + if (Test-Bound -ParameterName MailServer) { + $mailServerObj = $accountObj.MailServers.Item($server.DomainInstanceName) + $mailServerObj.Rename($MailServer) + } else { + $mailServerObj = $accountObj.MailServers | Select-Object -First 1 + } + + if ($null -ne $mailServerObj) { + if (Test-Bound -ParameterName Port) { $mailServerObj.Port = $Port } + if (Test-Bound -ParameterName EnableSSL) { $mailServerObj.EnableSsl = $EnableSSL.IsPresent } + if (Test-Bound -ParameterName UseDefaultCredentials) { $mailServerObj.UseDefaultCredentials = $UseDefaultCredentials.IsPresent } + if (Test-Bound -ParameterName UserName) { $mailServerObj.UserName = $UserName } + if (Test-Bound -ParameterName Password) { + $mailServerObj.Password = (New-Object System.Net.NetworkCredential("", $Password)).Password + } + $mailServerObj.Alter() + } + $accountObj.Refresh() Add-Member -Force -InputObject $accountObj -MemberType NoteProperty -Name ComputerName -value $server.ComputerName Add-Member -Force -InputObject $accountObj -MemberType NoteProperty -Name InstanceName -value $server.ServiceName @@ -154,4 +224,4 @@ function New-DbaDbMailAccount { } } } -} \ No newline at end of file +} diff --git a/public/Set-DbaDbMailAccount.ps1 b/public/Set-DbaDbMailAccount.ps1 new file mode 100644 index 000000000000..2b5cb9e2ce56 --- /dev/null +++ b/public/Set-DbaDbMailAccount.ps1 @@ -0,0 +1,200 @@ +function Set-DbaDbMailAccount { + <# + .SYNOPSIS + Modifies an existing Database Mail account on SQL Server + + .DESCRIPTION + Modifies the configuration of an existing Database Mail account including account properties (display name, email address, description) and mail server settings (SMTP server name, port, SSL, and authentication). This command is useful for updating Database Mail accounts to use cloud email services like Office 365 or Gmail, or for updating credentials when passwords change. + + .PARAMETER SqlInstance + The target SQL Server instance or instances. + + .PARAMETER SqlCredential + Login to the target instance using alternative credentials. Accepts PowerShell credentials (Get-Credential). + + Windows Authentication, SQL Server Authentication, Active Directory - Password, and Active Directory - Integrated are all supported. + + For MFA support, please use Connect-DbaInstance. + + .PARAMETER Account + Specifies one or more Database Mail account names to modify. Used in combination with -SqlInstance. + + .PARAMETER InputObject + Accepts MailAccount objects from the pipeline, typically from Get-DbaDbMailAccount. Allows you to chain Database Mail commands together. + + .PARAMETER DisplayName + Updates the friendly name that appears in the 'From' field of outgoing emails. + + .PARAMETER Description + Updates the optional documentation text describing the account's purpose and usage. + + .PARAMETER EmailAddress + Updates the sender email address that appears in outgoing messages from this Database Mail account. + + .PARAMETER ReplyToAddress + Updates the alternate email address for replies when different from the sender address. + + .PARAMETER NewMailServerName + Renames or replaces the SMTP server hostname for the mail account. Use this to migrate to a different SMTP server. + + .PARAMETER Port + Updates the TCP port number used to connect to the SMTP server. Common values are 25 (standard SMTP), 465 (SMTPS), and 587 (SMTP with STARTTLS). + Use 587 for Office 365 and Gmail which require STARTTLS. + + .PARAMETER EnableSSL + Enables or disables SSL/TLS encryption for the SMTP connection. Use -EnableSSL:$false to explicitly disable SSL. + + .PARAMETER UseDefaultCredentials + Enables or disables Windows integrated authentication (the SQL Server service account credentials) for SMTP authentication. + Use -UseDefaultCredentials:$false to explicitly disable Windows authentication. + + .PARAMETER UserName + Updates the username for SMTP authentication. For Office 365, use the full email address. + + .PARAMETER Password + Updates the password for SMTP authentication as a SecureString. + Create with: ConvertTo-SecureString 'yourpassword' -AsPlainText -Force + + .PARAMETER WhatIf + If this switch is enabled, no actions are performed but informational messages will be displayed that explain what would happen if the command were to run. + + .PARAMETER Confirm + If this switch is enabled, you will be prompted for confirmation before executing any operations that change state. + + .PARAMETER EnableException + By default, when something goes wrong we try to catch it, interpret it and give you a friendly warning message. + This avoids overwhelming you with "sea of red" exceptions, but is inconvenient because it basically disables advanced scripting. + Using this switch turns this "nice by default" feature off and enables you to catch exceptions with your own try/catch. + + .NOTES + Tags: DatabaseMail, DbMail, Mail + Author: the dbatools team + Claude + + Website: https://dbatools.io + Copyright: (c) 2018 by dbatools, licensed under MIT + License: MIT https://opensource.org/licenses/MIT + + .LINK + https://dbatools.io/Set-DbaDbMailAccount + + .OUTPUTS + Microsoft.SqlServer.Management.Smo.Mail.MailAccount + + Returns the updated MailAccount object from the specified SQL Server instance. + + Default display properties (via Select-DefaultView): + - ComputerName: The computer name of the SQL Server instance + - InstanceName: The SQL Server instance name + - SqlInstance: The full SQL Server instance name (computer\instance) + - Id: Unique identifier for the mail account + - Name: Name of the mail account + - DisplayName: Friendly name that appears in the 'From' field of emails + - Description: Description of the account's purpose + - EmailAddress: Sender email address for outgoing messages + - ReplyToAddress: Alternate email address for replies + - IsBusyAccount: Boolean indicating if the account is currently processing emails + - MailServers: Collection of mail servers associated with this account + + .EXAMPLE + PS C:\> Set-DbaDbMailAccount -SqlInstance sql2017 -Account 'MaintenanceAlerts' -Port 587 -EnableSSL + + Updates the MaintenanceAlerts mail account on sql2017 to use port 587 with SSL enabled. + + .EXAMPLE + PS C:\> $splatAccount = @{ + >> SqlInstance = 'sql2017' + >> Account = 'Alerts' + >> NewMailServerName = 'smtp.office365.com' + >> Port = 587 + >> EnableSSL = $true + >> UserName = 'alerts@company.com' + >> Password = (ConvertTo-SecureString 'app-password' -AsPlainText -Force) + >> } + PS C:\> Set-DbaDbMailAccount @splatAccount + + Migrates the Alerts mail account on sql2017 to Office 365 with SSL and basic authentication. + + .EXAMPLE + PS C:\> Get-DbaDbMailAccount -SqlInstance sql2017 -Account 'MaintenanceAlerts' | Set-DbaDbMailAccount -Port 25 -EnableSSL:$false + + Uses the pipeline to update the MaintenanceAlerts account to use port 25 with SSL disabled. + + .EXAMPLE + PS C:\> Set-DbaDbMailAccount -SqlInstance sql2017 -Account 'DomainRelay' -UseDefaultCredentials + + Configures the DomainRelay mail account to use Windows integrated authentication. + + #> + [CmdletBinding(SupportsShouldProcess, ConfirmImpact = "Medium")] + param ( + [DbaInstanceParameter[]]$SqlInstance, + [PSCredential]$SqlCredential, + [string[]]$Account, + [Parameter(ValueFromPipeline)] + [Microsoft.SqlServer.Management.Smo.Mail.MailAccount[]]$InputObject, + [string]$DisplayName, + [string]$Description, + [string]$EmailAddress, + [string]$ReplyToAddress, + [string]$NewMailServerName, + [int]$Port, + [switch]$EnableSSL, + [switch]$UseDefaultCredentials, + [string]$UserName, + [System.Security.SecureString]$Password, + [switch]$EnableException + ) + process { + foreach ($instance in $SqlInstance) { + $InputObject += Get-DbaDbMailAccount -SqlInstance $instance -SqlCredential $SqlCredential -Account $Account -EnableException:$EnableException + } + + foreach ($mailAccount in $InputObject) { + $instanceName = $mailAccount.SqlInstance + if (-not $instanceName) { + $instanceName = $mailAccount.Parent.Parent.DomainInstanceName + } + + if ($Pscmdlet.ShouldProcess($instanceName, "Updating mail account $($mailAccount.Name)")) { + $accountChanged = $false + + try { + if (Test-Bound -ParameterName DisplayName) { $mailAccount.DisplayName = $DisplayName; $accountChanged = $true } + if (Test-Bound -ParameterName Description) { $mailAccount.Description = $Description; $accountChanged = $true } + if (Test-Bound -ParameterName EmailAddress) { $mailAccount.EmailAddress = $EmailAddress; $accountChanged = $true } + if (Test-Bound -ParameterName ReplyToAddress) { $mailAccount.ReplyToAddress = $ReplyToAddress; $accountChanged = $true } + + if ($accountChanged) { + $mailAccount.Alter() + } + } catch { + Stop-Function -Message "Failure updating account properties for $($mailAccount.Name) on $instanceName" -Target $mailAccount -ErrorRecord $_ -Continue + } + + try { + $mailServerObj = $mailAccount.MailServers | Select-Object -First 1 + + if ($null -ne $mailServerObj) { + if (Test-Bound -ParameterName NewMailServerName) { $mailServerObj.Rename($NewMailServerName) } + if (Test-Bound -ParameterName Port) { $mailServerObj.Port = $Port } + if (Test-Bound -ParameterName EnableSSL) { $mailServerObj.EnableSsl = $EnableSSL.IsPresent } + if (Test-Bound -ParameterName UseDefaultCredentials) { $mailServerObj.UseDefaultCredentials = $UseDefaultCredentials.IsPresent } + if (Test-Bound -ParameterName UserName) { $mailServerObj.UserName = $UserName } + if (Test-Bound -ParameterName Password) { + $mailServerObj.Password = (New-Object System.Net.NetworkCredential("", $Password)).Password + } + $mailServerObj.Alter() + } + } catch { + Stop-Function -Message "Failure updating mail server for account $($mailAccount.Name) on $instanceName" -Target $mailAccount -ErrorRecord $_ -Continue + } + + $mailAccount.Refresh() + Add-Member -Force -InputObject $mailAccount -MemberType NoteProperty -Name ComputerName -value $mailAccount.Parent.Parent.ComputerName + Add-Member -Force -InputObject $mailAccount -MemberType NoteProperty -Name InstanceName -value $mailAccount.Parent.Parent.ServiceName + Add-Member -Force -InputObject $mailAccount -MemberType NoteProperty -Name SqlInstance -value $mailAccount.Parent.Parent.DomainInstanceName + $mailAccount | Select-DefaultView -Property ComputerName, InstanceName, SqlInstance, Id, Name, DisplayName, Description, EmailAddress, ReplyToAddress, IsBusyAccount, MailServers + } + } + } +} diff --git a/tests/New-DbaDbMailAccount.Tests.ps1 b/tests/New-DbaDbMailAccount.Tests.ps1 index a74060763104..3b319370aa93 100644 --- a/tests/New-DbaDbMailAccount.Tests.ps1 +++ b/tests/New-DbaDbMailAccount.Tests.ps1 @@ -19,6 +19,11 @@ Describe $CommandName -Tag UnitTests { "EmailAddress", "ReplyToAddress", "MailServer", + "Port", + "EnableSSL", + "UseDefaultCredentials", + "UserName", + "Password", "Force", "EnableException" ) diff --git a/tests/Set-DbaDbMailAccount.Tests.ps1 b/tests/Set-DbaDbMailAccount.Tests.ps1 new file mode 100644 index 000000000000..614d3bfb2038 --- /dev/null +++ b/tests/Set-DbaDbMailAccount.Tests.ps1 @@ -0,0 +1,129 @@ +#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0" } +param( + $ModuleName = "dbatools", + $CommandName = "Set-DbaDbMailAccount", + $PSDefaultParameterValues = $TestConfig.Defaults +) + +Describe $CommandName -Tag UnitTests { + Context "Parameter validation" { + It "Should have the expected parameters" { + $hasParameters = (Get-Command $CommandName).Parameters.Values.Name | Where-Object { $PSItem -notin ("WhatIf", "Confirm") } + $expectedParameters = $TestConfig.CommonParameters + $expectedParameters += @( + "SqlInstance", + "SqlCredential", + "Account", + "InputObject", + "DisplayName", + "Description", + "EmailAddress", + "ReplyToAddress", + "NewMailServerName", + "Port", + "EnableSSL", + "UseDefaultCredentials", + "UserName", + "Password", + "EnableException" + ) + Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $hasParameters | Should -BeNullOrEmpty + } + } +} + +Describe $CommandName -Tag IntegrationTests { + BeforeAll { + $PSDefaultParameterValues["*-Dba*:EnableException"] = $true + + $accountName = "dbatoolsci_settest_$(Get-Random)" + $server = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle + + if ((Get-DbaSpConfigure -SqlInstance $server -Name "Database Mail XPs").RunningValue -ne 1) { + Set-DbaSpConfigure -SqlInstance $server -Name "Database Mail XPs" -Value 1 + } + + $splatMailAccount = @{ + SqlInstance = $TestConfig.InstanceSingle + Account = $accountName + Description = "Original description" + EmailAddress = "original@dbatools.net" + DisplayName = "Original Display Name" + } + $null = New-DbaDbMailAccount @splatMailAccount + + $PSDefaultParameterValues.Remove("*-Dba*:EnableException") + } + + AfterAll { + $PSDefaultParameterValues["*-Dba*:EnableException"] = $true + + $server = Connect-DbaInstance -SqlInstance $TestConfig.InstanceSingle + $mailAccountSettings = "EXEC msdb.dbo.sysmail_delete_account_sp @account_name = '$accountName';" + $server.query($mailAccountSettings) + } + + Context "Updates mail account properties" { + BeforeAll { + $splatSetAccount = @{ + SqlInstance = $TestConfig.InstanceSingle + Account = $accountName + Description = "Updated description" + DisplayName = "Updated Display Name" + } + $results = Set-DbaDbMailAccount @splatSetAccount + } + + It "Gets results" { + $results | Should -Not -BeNullOrEmpty + } + It "Should have updated Description" { + $results.Description | Should -Be "Updated description" + } + It "Should have updated DisplayName" { + $results.DisplayName | Should -Be "Updated Display Name" + } + } + + Context "Updates mail server port and SSL settings" { + BeforeAll { + $splatSetServer = @{ + SqlInstance = $TestConfig.InstanceSingle + Account = $accountName + Port = 587 + EnableSSL = $true + } + $results = Set-DbaDbMailAccount @splatSetServer + } + + It "Gets results" { + $results | Should -Not -BeNullOrEmpty + } + It "Should have updated port to 587" { + $mailServer = $results.MailServers | Select-Object -First 1 + $mailServer.Port | Should -Be 587 + } + It "Should have enabled SSL" { + $mailServer = $results.MailServers | Select-Object -First 1 + $mailServer.EnableSsl | Should -Be $true + } + } + + Context "Works with pipeline input" { + BeforeAll { + $results = Get-DbaDbMailAccount -SqlInstance $TestConfig.InstanceSingle -Account $accountName | Set-DbaDbMailAccount -Port 25 -EnableSSL:$false + } + + It "Gets results" { + $results | Should -Not -BeNullOrEmpty + } + It "Should have updated port back to 25" { + $mailServer = $results.MailServers | Select-Object -First 1 + $mailServer.Port | Should -Be 25 + } + It "Should have disabled SSL" { + $mailServer = $results.MailServers | Select-Object -First 1 + $mailServer.EnableSsl | Should -Be $false + } + } +}