diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d220cd5c6..1f8cc12f9a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `Install-SqlDscServer` + - Added parameter `AllowDqRemoval` to the `Upgrade` parameter set + ([issue #2155](https://github.com/dsccommunity/SqlServerDsc/issues/2155)). +- `Test-SqlDscIsSupportedFeature` + - Added DQ, DQC, and MDS features as discontinued starting with SQL Server 2025 + (17.x) and later versions ([issue #2380](https://github.com/dsccommunity/SqlServerDsc/issues/2380)). - Added public command `Get-SqlDscRSPackage` to retrieve package information for SQL Server Reporting Services or Power BI Report Server. Supports getting version information from an executable file @@ -59,6 +65,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added parameter `-KillActiveSessions` to automatically terminate any active sessions for a login before dropping it ([issue #2372](https://github.com/dsccommunity/SqlServerDsc/issues/2372)). +- `Invoke-SetupAction` + - Added parameter `AllowDqRemoval` for the `Upgrade` action to allow removal + of Data Quality (DQ) Services during upgrade to SQL Server 2025 (17.x) and + later versions. + - Now outputs setup progress when `-Verbose` is passed by using `/QUIETSIMPLE` + instead of `/QUIET`. ### Changed diff --git a/source/Private/Assert-SetupActionProperties.ps1 b/source/Private/Assert-SetupActionProperties.ps1 index 7f38e45c3f..5eb50b16ff 100644 --- a/source/Private/Assert-SetupActionProperties.ps1 +++ b/source/Private/Assert-SetupActionProperties.ps1 @@ -42,12 +42,19 @@ function Assert-SetupActionProperties $SetupAction ) + $setupExecutableFileVersion = $null + + <# + Assumes that the MediaPath parameter is always specified as this should + only be called internally by Invoke-SetupAction that have MediaPath as a + mandatory parameter. + #> + $setupExecutableFileVersion = $Property.MediaPath | + Join-Path -ChildPath 'setup.exe' | + Get-FileVersion + if ($Property.ContainsKey('Features')) { - $setupExecutableFileVersion = $Property.MediaPath | - Join-Path -ChildPath 'setup.exe' | - Get-FileVersion - $Property.Features | Assert-Feature -ProductVersion $setupExecutableFileVersion.ProductVersion } @@ -238,4 +245,22 @@ function Assert-SetupActionProperties ) } } + + # The parameter AllowDqRemoval is only allowed for SQL Server 2025 (17.x) and later versions. + if ($Property.ContainsKey('AllowDqRemoval')) + { + $majorVersion = $setupExecutableFileVersion.ProductVersion.Split('.')[0] + + if ([System.Int32] $majorVersion -lt 17) + { + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + ($script:localizedData.InstallSqlServerProperties_AllowDqRemovalInvalidVersion -f $majorVersion), + 'ASAP0003', # cSpell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidOperation, + 'Command parameters' + ) + ) + } + } } diff --git a/source/Private/Invoke-SetupAction.ps1 b/source/Private/Invoke-SetupAction.ps1 index 9af17a1df2..fed733f023 100644 --- a/source/Private/Invoke-SetupAction.ps1 +++ b/source/Private/Invoke-SetupAction.ps1 @@ -294,6 +294,10 @@ .PARAMETER AllowUpgradeForSSRSSharePointMode See the notes section for more information. + .PARAMETER AllowDqRemoval + Specifies whether to allow removal of Data Quality (DQ) Services during + upgrade to SQL Server 2025 (17.x) and later versions. + .PARAMETER NpEnabled See the notes section for more information. @@ -476,7 +480,7 @@ #> function Invoke-SetupAction { - # cSpell: ignore PBDMS Admini AZUREEXTENSION BSTR + # cSpell: ignore PBDMS Admini AZUREEXTENSION BSTR QUIETSIMPLE [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] [OutputType()] param @@ -1210,6 +1214,10 @@ function Invoke-SetupAction [System.Management.Automation.SwitchParameter] $AllowUpgradeForSSRSSharePointMode, + [Parameter(ParameterSetName = 'Upgrade')] + [System.Management.Automation.SwitchParameter] + $AllowDqRemoval, + [Parameter(ParameterSetName = 'Install')] [Parameter(ParameterSetName = 'InstallRole')] [Parameter(ParameterSetName = 'CompleteImage')] @@ -1428,7 +1436,27 @@ function Invoke-SetupAction $ErrorActionPreference = $originalErrorActionPreference - $setupArgument = '/QUIET /ACTION={0}' -f $setupAction + $quietSimpleSetupActions = @( + 'Install' + 'PrepareImage' + 'CompleteImage' + 'InstallFailoverCluster' + 'PrepareFailoverCluster' + 'CompleteFailoverCluster' + 'AddNode' + 'RemoveNode' + ) + + if ($VerbosePreference -eq 'Continue' -and $setupAction -in $quietSimpleSetupActions) + { + $quietMode = '/QUIETSIMPLE' + } + else + { + $quietMode = '/QUIET' + } + + $setupArgument = '{0} /ACTION={1}' -f $quietMode, $setupAction if ($DebugPreference -in @('Continue', 'Inquire')) { @@ -1534,12 +1562,9 @@ function Invoke-SetupAction # Must be handled differently because the parameter name could not be $PID. 'PRODUCTKEY' # cspell: disable-line { - # Remove the argument that was added above. - $setupArgument = $setupArgument -replace ' \/{0}' -f $parameterName - $sensitiveValue += $PSBoundParameters.$parameterName - $setupArgument += ' /PID="{0}"' -f $PSBoundParameters.$parameterName + $setupArgument = $setupArgument -replace $parameterName, ('PID="{0}"' -f $PSBoundParameters.$parameterName) break } @@ -1547,10 +1572,15 @@ function Invoke-SetupAction # Must be handled differently because the argument name shall have an underscore in the argument. 'SQLINSTJAVA' # cspell: disable-line { - # Remove the argument that was added above. - $setupArgument = $setupArgument -replace ' \/{0}' -f $parameterName + $setupArgument = $setupArgument -replace $parameterName, 'SQL_INST_JAVA' - $setupArgument += ' /SQL_INST_JAVA' + break + } + + # Must be handled differently because parameter name does not match the argument name. + 'ALLOWDQREMOVAL' # cspell: disable-line + { + $setupArgument = $setupArgument -replace $parameterName, 'IACCEPTDQUNINSTALL' # cspell: disable-line break } diff --git a/source/Public/Install-SqlDscServer.ps1 b/source/Public/Install-SqlDscServer.ps1 index e8b499986e..3af9cdca6f 100644 --- a/source/Public/Install-SqlDscServer.ps1 +++ b/source/Public/Install-SqlDscServer.ps1 @@ -276,6 +276,10 @@ .PARAMETER AllowUpgradeForSSRSSharePointMode See the notes section for more information. + .PARAMETER AllowDqRemoval + Specifies whether to allow removal of Data Quality (DQ) Services during + upgrade to SQL Server 2025 (17.x) and later versions. + .PARAMETER NpEnabled See the notes section for more information. @@ -994,6 +998,10 @@ function Install-SqlDscServer [System.Management.Automation.SwitchParameter] $AllowUpgradeForSSRSSharePointMode, + [Parameter(ParameterSetName = 'Upgrade')] + [System.Management.Automation.SwitchParameter] + $AllowDqRemoval, + [Parameter(ParameterSetName = 'Install')] [Parameter(ParameterSetName = 'InstallRole')] [System.Management.Automation.SwitchParameter] diff --git a/source/Public/Test-SqlDscIsSupportedFeature.ps1 b/source/Public/Test-SqlDscIsSupportedFeature.ps1 index e8331185c9..e0bc91f936 100644 --- a/source/Public/Test-SqlDscIsSupportedFeature.ps1 +++ b/source/Public/Test-SqlDscIsSupportedFeature.ps1 @@ -54,6 +54,7 @@ function Test-SqlDscIsSupportedFeature 13 = @('ADV_SSMS', 'SSMS') # cSpell: disable-line 14 = @('RS', 'RS_SHP', 'RS_SHPWFE') # cSpell: disable-line 16 = @('Tools', 'BC', 'CONN', 'BC', 'DREPLAY_CTLR', 'DREPLAY_CLT', 'SNAC_SDK', 'SDK', 'PolyBaseJava', 'SQL_INST_MR', 'SQL_INST_MPY', 'SQL_SHARED_MPY', 'SQL_SHARED_MR') # cSpell: disable-line + 17 = @('DQ', 'DQC', 'MDS') # Discontinued in SQL Server 2025 (17.x). See https://learn.microsoft.com/en-us/sql/database-engine/discontinued-database-engine-functionality-in-sql-server } <# diff --git a/source/en-US/SqlServerDsc.strings.psd1 b/source/en-US/SqlServerDsc.strings.psd1 index 74dcd36d3d..915347000c 100644 --- a/source/en-US/SqlServerDsc.strings.psd1 +++ b/source/en-US/SqlServerDsc.strings.psd1 @@ -162,6 +162,7 @@ ConvertFrom-StringData @' ## Assert-SetupActionProperties InstallSqlServerProperties_ASServerModeInvalidValue = The value for ASServerMode is not valid for the setup action {0}. InstallSqlServerProperties_RsInstallModeInvalidValue = The only valid value for RsInstallMode is 'FilesOnlyMode' when using setup action {0}. + InstallSqlServerProperties_AllowDqRemovalInvalidVersion = The parameter AllowDqRemoval is only allowed for SQL Server 2025 (17.x) and later versions. The media version is {0}.x. (ASAP0004) ## Get-SqlDscManagedComputer ManagedComputer_GetState = Returning the managed computer object for server {0}. diff --git a/tests/Unit/Private/Assert-SetupActionProperties.Tests.ps1 b/tests/Unit/Private/Assert-SetupActionProperties.Tests.ps1 index 5538c715cc..a764bce897 100644 --- a/tests/Unit/Private/Assert-SetupActionProperties.Tests.ps1 +++ b/tests/Unit/Private/Assert-SetupActionProperties.Tests.ps1 @@ -47,6 +47,14 @@ AfterAll { } Describe 'Assert-SetupActionProperties' -Tag 'Private' { + BeforeAll { + Mock -CommandName Get-FileVersion -MockWith { + return [PSCustomObject] @{ + ProductVersion = '16.0.1000.6' + } + } + } + Context 'When all properties are valid for setup action ''''' -ForEach @( @{ MockSetupAction = 'Install' @@ -100,6 +108,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { It 'Should not throw an exception' { InModuleScope -Parameters $_ -ScriptBlock { $null = Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive ValidProperty = 'Value' } -SetupAction $MockSetupAction -ErrorAction 'Stop' } @@ -118,6 +127,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { InModuleScope -Parameters $_ -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive $MockParameterName = 'Value' } -SetupAction 'NotUsed' } | Should -Throw -ErrorId 'ARCP0001,Assert-RequiredCommandParameter' # cSpell: disable-line @@ -162,6 +172,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { It 'Should throw the correct error' { InModuleScope -Parameters $_ -ScriptBlock { { + $MockParameters.MediaPath = $TestDrive $MockParameters.Role = 'SPI_AS_NewFarm' Assert-SetupActionProperties -Property $MockParameters -SetupAction 'NotUsed' @@ -175,6 +186,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { InModuleScope -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive SecurityMode = 'SQL' } -SetupAction 'NotUsed' } | Should -Throw -ErrorId 'ARCP0001,Assert-RequiredCommandParameter' # cSpell: disable-line @@ -188,6 +200,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { MockFileStreamLevel = $_ } -ScriptBlock { $null = Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive FileStreamLevel = $MockFileStreamLevel } -SetupAction 'NotUsed' -ErrorAction 'Stop' } @@ -201,6 +214,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { } -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive FileStreamLevel = $MockFileStreamLevel } -SetupAction 'NotUsed' } | Should -Throw -ErrorId 'ARCP0001,Assert-RequiredCommandParameter' # cSpell: disable-line @@ -238,6 +252,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { InModuleScope -Parameters $_ -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive $MockParameterName = 'AccountName' } -SetupAction 'NotUsed' } | Should -Throw -ErrorId 'ARCP0001,Assert-RequiredCommandParameter' # cSpell: disable-line @@ -274,7 +289,8 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { It 'Should not throw an exception' { InModuleScope -Parameters $_ -ScriptBlock { $null = Assert-SetupActionProperties -Property @{ - $MockParameterName = 'AccountName' + MediaPath = $TestDrive + $MockParameterName = 'AccountName' ($MockParameterName -replace 'Account', 'Password') = 'Password' } -SetupAction 'NotUsed' -ErrorAction 'Stop' } @@ -316,6 +332,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { It 'Should not throw an exception' { InModuleScope -Parameters $_ -ScriptBlock { $null = Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive $MockParameterName = 'myMSA$' } -SetupAction 'NotUsed' -ErrorAction 'Stop' } @@ -553,6 +570,7 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { InModuleScope -Parameters $_ -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive ASServerMode = 'PowerPivot' } -SetupAction $MockSetupAction } | Should -Throw -ErrorId 'ASAP0001,Assert-SetupActionProperties' # cSpell: disable-line @@ -569,10 +587,51 @@ Describe 'Assert-SetupActionProperties' -Tag 'Private' { InModuleScope -Parameters $_ -ScriptBlock { { Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive RsInstallMode = 'DefaultNativeMode' } -SetupAction $MockSetupAction } | Should -Throw -ErrorId 'ASAP0002,Assert-SetupActionProperties' # cSpell: disable-line } } } + + Context 'When specifying AllowDqRemoval with SQL Server version older than 2025 (17.x)' { + BeforeAll { + Mock -CommandName Get-FileVersion -MockWith { + return [PSCustomObject] @{ + ProductVersion = '16.0.1000.6' + } + } + } + + It 'Should throw an exception' { + InModuleScope -ScriptBlock { + { + Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive + AllowDqRemoval = $true + } -SetupAction 'Upgrade' + } | Should -Throw -ErrorId 'ASAP0003,Assert-SetupActionProperties' # cSpell: disable-line + } + } + } + + Context 'When specifying AllowDqRemoval with SQL Server 2025 (17.x)' { + BeforeAll { + Mock -CommandName Get-FileVersion -MockWith { + return [PSCustomObject] @{ + ProductVersion = '17.0.1000.6' + } + } + } + + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + $null = Assert-SetupActionProperties -Property @{ + MediaPath = $TestDrive + AllowDqRemoval = $true + } -SetupAction 'Upgrade' -ErrorAction 'Stop' + } + } + } } diff --git a/tests/Unit/Private/Invoke-SetupAction.Tests.ps1 b/tests/Unit/Private/Invoke-SetupAction.Tests.ps1 index 6c8491ac7a..1a29e36d4f 100644 --- a/tests/Unit/Private/Invoke-SetupAction.Tests.ps1 +++ b/tests/Unit/Private/Invoke-SetupAction.Tests.ps1 @@ -87,7 +87,7 @@ Describe 'Invoke-SetupAction' -Tag 'Private' { @{ MockParameterSetName = 'Upgrade' # cSpell: disable-next - MockExpectedParameters = '-Upgrade -AcceptLicensingTerms -MediaPath -InstanceName [-Enu] [-UpdateEnabled] [-UpdateSource ] [-InstanceDir ] [-InstanceId ] [-ProductKey ] [-BrowserSvcStartupType ] [-FTUpgradeOption ] [-ISSvcAccount ] [-ISSvcPassword ] [-ISSvcStartupType ] [-AllowUpgradeForSSRSSharePointMode] [-FailoverClusterRollOwnership ] [-ProductCoveredBySA] [-Timeout ] [-Force] [-WhatIf] [-Confirm] []' + MockExpectedParameters = '-Upgrade -AcceptLicensingTerms -MediaPath -InstanceName [-Enu] [-UpdateEnabled] [-UpdateSource ] [-InstanceDir ] [-InstanceId ] [-ProductKey ] [-BrowserSvcStartupType ] [-FTUpgradeOption ] [-ISSvcAccount ] [-ISSvcPassword ] [-ISSvcStartupType ] [-AllowUpgradeForSSRSSharePointMode] [-AllowDqRemoval] [-FailoverClusterRollOwnership ] [-ProductCoveredBySA] [-Timeout ] [-Force] [-WhatIf] [-Confirm] []' } @{ MockParameterSetName = 'EditionUpgrade' @@ -983,6 +983,11 @@ Describe 'Invoke-SetupAction' -Tag 'Private' { MockParameterValue = $true MockExpectedRegEx = '\/ALLOWUPGRADEFORSSRSSHAREPOINTMODE=True' # cspell: disable-line } + @{ + MockParameterName = 'AllowDqRemoval' + MockParameterValue = $true + MockExpectedRegEx = '\/IACCEPTDQUNINSTALL\s*' # cspell: disable-line + } @{ MockParameterName = 'FailoverClusterRollOwnership' MockParameterValue = 2 diff --git a/tests/Unit/Public/Install-SqlDscServer.Tests.ps1 b/tests/Unit/Public/Install-SqlDscServer.Tests.ps1 index 4d641e2ee1..7000176d35 100644 --- a/tests/Unit/Public/Install-SqlDscServer.Tests.ps1 +++ b/tests/Unit/Public/Install-SqlDscServer.Tests.ps1 @@ -77,7 +77,7 @@ Describe 'Install-SqlDscServer' -Tag 'Public' { @{ MockParameterSetName = 'Upgrade' # cSpell: disable-next - MockExpectedParameters = '-Upgrade -AcceptLicensingTerms -MediaPath -InstanceName [-Enu] [-UpdateEnabled] [-UpdateSource ] [-InstanceDir ] [-InstanceId ] [-ProductKey ] [-BrowserSvcStartupType ] [-FTUpgradeOption ] [-ISSvcAccount ] [-ISSvcPassword ] [-ISSvcStartupType ] [-AllowUpgradeForSSRSSharePointMode] [-FailoverClusterRollOwnership ] [-ProductCoveredBySA] [-Timeout ] [-Force] [-WhatIf] [-Confirm] []' + MockExpectedParameters = '-Upgrade -AcceptLicensingTerms -MediaPath -InstanceName [-Enu] [-UpdateEnabled] [-UpdateSource ] [-InstanceDir ] [-InstanceId ] [-ProductKey ] [-BrowserSvcStartupType ] [-FTUpgradeOption ] [-ISSvcAccount ] [-ISSvcPassword ] [-ISSvcStartupType ] [-AllowUpgradeForSSRSSharePointMode] [-AllowDqRemoval] [-FailoverClusterRollOwnership ] [-ProductCoveredBySA] [-Timeout ] [-Force] [-WhatIf] [-Confirm] []' } @{ MockParameterSetName = 'EditionUpgrade' @@ -785,6 +785,11 @@ Describe 'Install-SqlDscServer' -Tag 'Public' { MockParameterValue = 2 MockExpectedRegEx = '\/FAILOVERCLUSTERROLLOWNERSHIP=2' # cspell: disable-line } + @{ + MockParameterName = 'AllowDqRemoval' + MockParameterValue = $true + MockExpectedRegEx = '\/IACCEPTDQUNINSTALL\s*' # cspell: disable-line + } ) { BeforeAll { Mock -CommandName Start-SqlSetupProcess -MockWith { diff --git a/tests/Unit/Public/Test-SqlDscIsSupportedFeature.Tests.ps1 b/tests/Unit/Public/Test-SqlDscIsSupportedFeature.Tests.ps1 index 308baca24a..03d43dda68 100644 --- a/tests/Unit/Public/Test-SqlDscIsSupportedFeature.Tests.ps1 +++ b/tests/Unit/Public/Test-SqlDscIsSupportedFeature.Tests.ps1 @@ -105,4 +105,30 @@ Describe 'Test-SqlDscIsSupportedFeature' -Tag 'Public' { Test-SqlDscIsSupportedFeature -Feature 'PolyBaseJava' -ProductVersion 14 | Should -BeFalse } } + + Context 'When DQ, DQC, and MDS features are discontinued in SQL Server 2025 (17.x)' { + It 'Should return $true for feature on major version 16' -ForEach @( + @{ Feature = 'DQ' } + @{ Feature = 'DQC' } + @{ Feature = 'MDS' } + ) { + Test-SqlDscIsSupportedFeature -Feature $Feature -ProductVersion 16 | Should -BeTrue + } + + It 'Should return $false for feature on major version 17' -ForEach @( + @{ Feature = 'DQ' } + @{ Feature = 'DQC' } + @{ Feature = 'MDS' } + ) { + Test-SqlDscIsSupportedFeature -Feature $Feature -ProductVersion 17 | Should -BeFalse + } + + It 'Should return $false for feature on major version 999 (future version)' -ForEach @( + @{ Feature = 'DQ' } + @{ Feature = 'DQC' } + @{ Feature = 'MDS' } + ) { + Test-SqlDscIsSupportedFeature -Feature $Feature -ProductVersion 999 | Should -BeFalse + } + } }