diff --git a/CHANGELOG.md b/CHANGELOG.md index 1480f060f..5f041f4f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- SqlSetup + - Added new parameter ProductCoveredbySA which is introduced in SQL 2022. + +### Added + - `Connect-SqlDscDatabaseEngine` - Added integration test for the command. - `Uninstall-SqlDscServer` diff --git a/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.psm1 b/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.psm1 index 46dc88b6b..029f964b7 100644 --- a/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.psm1 +++ b/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.psm1 @@ -176,6 +176,7 @@ function Get-TargetResource UseEnglish = $UseEnglish ServerName = $ServerName SqlVersion = $null + ProductCoveredBySA = $null } <# @@ -318,6 +319,16 @@ function Get-TargetResource $getTargetResourceReturnValue.SqlTempdbLogFileGrowth = $currentTempDbProperties.SqlTempdbLogFileGrowth } + if ($sqlVersion -ge 16) + { + # Grab the value of ProductCoveredBySA from the registry based on the instance + $getRegistryPropertyParams = @{ + Path = "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL$($SqlVersion).$($InstanceName)\Setup" + Name = 'IsProductCoveredBySA' + } + $getTargetResourceReturnValue.ProductCoveredBySA = Get-RegistryPropertyValue @getRegistryPropertyParams + } + # Get all members of the sysadmin role. $sqlSystemAdminAccounts = Get-SqlRoleMembers -RoleName 'sysadmin' -ServerName $sqlHostName -InstanceName $InstanceName $getTargetResourceReturnValue.SQLSysAdminAccounts = $sqlSystemAdminAccounts @@ -518,6 +529,11 @@ function Get-TargetResource .PARAMETER ProductKey Product key for licensed installations. + .PARAMETER ProductCoveredBySA + Specifies the license coverage for SQL Server. True indicates it's covered under Software Assurance or SQL Server subscription. + False, or omitting the parameter, indicates it's covered under a SQL Server license. + Default value is False. + .PARAMETER UpdateEnabled Enabled updates during installation. @@ -748,6 +764,10 @@ function Set-TargetResource [System.String] $ProductKey, + [Parameter()] + [System.Boolean] + $ProductCoveredBySA, + [Parameter()] [System.String] $UpdateEnabled, @@ -1290,6 +1310,12 @@ function Set-TargetResource $setupArguments['FailoverClusterIPAddresses'] = $clusterIPAddresses } + # Add Parameter ProductCoveredBySA + if ($PSBoundParameters.ContainsKey('ProductCoveredBySA')) + { + $setupArguments['ProductCoveredBySA'] = $ProductCoveredBySA + } + # Add standard install arguments $setupArguments += @{ Quiet = $true @@ -1767,6 +1793,13 @@ function Set-TargetResource .PARAMETER ProductKey Product key for licensed installations. + .PARAMETER ProductCoveredBySA + Specifies the license coverage for SQL Server. True indicates it's covered under Software Assurance or SQL Server subscription. + False, or omitting the parameter, indicates it's covered under a SQL Server license. + Default value is False. + + Not used in Test-TargetResource. + .PARAMETER UpdateEnabled Enabled updates during installation. @@ -2005,6 +2038,10 @@ function Test-TargetResource [System.String] $ProductKey, + [Parameter()] + [System.Boolean] + $ProductCoveredBySA, + [Parameter()] [System.String] $UpdateEnabled, diff --git a/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.schema.mof b/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.schema.mof index d9275c65f..cd96c8494 100644 --- a/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.schema.mof +++ b/source/DSCResources/DSC_SqlSetup/DSC_SqlSetup.schema.mof @@ -10,6 +10,7 @@ class DSC_SqlSetup : OMI_BaseResource [Key, Description("Specifies the name of the instance to be installed.")] String InstanceName; [Write, Description("_SQL Server_ instance ID (if different from parameter **InstanceName**).")] String InstanceID; [Write, Description("Product key for licensed installations.")] String ProductKey; + [Write, Description("Specifies the Software Assurance license coverage for SQL Server instance.")] Boolean ProductCoveredbySA; [Write, Description("Enabled updates during installation.")] String UpdateEnabled; [Write, Description("Path to the source of updates to be applied during installation.")] String UpdateSource; [Write, Description("Enable customer experience reporting.")] String SQMReporting; diff --git a/source/Examples/Resources/SqlSetup/8-InstallDefaultInstanceSingleServer2022OrLater.ps1 b/source/Examples/Resources/SqlSetup/8-InstallDefaultInstanceSingleServer2022OrLater.ps1 new file mode 100644 index 000000000..b69c9bd1e --- /dev/null +++ b/source/Examples/Resources/SqlSetup/8-InstallDefaultInstanceSingleServer2022OrLater.ps1 @@ -0,0 +1,100 @@ +<# + .DESCRIPTION + This example shows how to install a default instance of SQL Server, and + Analysis Services in Tabular mode, on a single server. + It contains configurations that apply to Sql Server 2022 or later only. + + .NOTES + SQL Server setup is run using the SYSTEM account. Even if SetupCredential is provided + it is not used to install SQL Server at this time (see issue #139). +#> + +Configuration Example +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlInstallCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlAdministratorCredential = $SqlInstallCredential, + + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlServiceCredential, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlAgentServiceCredential = $SqlServiceCredential + ) + + Import-DscResource -ModuleName 'xPSDesiredStateConfiguration' -ModuleVersion '9.1.0' + Import-DscResource -ModuleName 'SqlServerDsc' + + node localhost + { + #region Install prerequisites for SQL Server + WindowsFeature 'NetFramework35' + { + Name = 'NET-Framework-Core' + Source = '\\fileserver.company.local\images$\Win2k12R2\Sources\Sxs' # Assumes built-in Everyone has read permission to the share and path. + Ensure = 'Present' + } + + WindowsFeature 'NetFramework45' + { + Name = 'NET-Framework-45-Core' + Ensure = 'Present' + } + #endregion Install prerequisites for SQL Server + + #region Install SQL Server + SqlSetup 'InstallDefaultInstance' + { + InstanceName = 'MSSQLSERVER' + Features = 'SQLENGINE,AS' + SQLCollation = 'SQL_Latin1_General_CP1_CI_AS' + SQLSvcAccount = $SqlServiceCredential + AgtSvcAccount = $SqlAgentServiceCredential + ASSvcAccount = $SqlServiceCredential + SQLSysAdminAccounts = 'COMPANY\SQL Administrators', $SqlAdministratorCredential.UserName + ASSysAdminAccounts = 'COMPANY\SQL Administrators', $SqlAdministratorCredential.UserName + InstallSharedDir = 'C:\Program Files\Microsoft SQL Server' + InstallSharedWOWDir = 'C:\Program Files (x86)\Microsoft SQL Server' + InstanceDir = 'C:\Program Files\Microsoft SQL Server' + InstallSQLDataDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data' + SQLUserDBDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data' + SQLUserDBLogDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data' + SQLTempDBDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data' + SQLTempDBLogDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Data' + SQLBackupDir = 'C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL\Backup' + ASServerMode = 'TABULAR' + ASConfigDir = 'C:\MSOLAP\Config' + ASDataDir = 'C:\MSOLAP\Data' + ASLogDir = 'C:\MSOLAP\Log' + ASBackupDir = 'C:\MSOLAP\Backup' + ASTempDir = 'C:\MSOLAP\Temp' + SourcePath = 'C:\InstallMedia\SQL2016RTM' + UpdateEnabled = 'False' + ProductCoveredbySA = $true + ForceReboot = $false + SqlTempdbFileCount = 4 + SqlTempdbFileSize = 1024 + SqlTempdbFileGrowth = 512 + SqlTempdbLogFileSize = 128 + SqlTempdbLogFileGrowth = 64 + + PsDscRunAsCredential = $SqlInstallCredential + + DependsOn = '[WindowsFeature]NetFramework35', '[WindowsFeature]NetFramework45' + } + #endregion Install SQL Server + } +} diff --git a/source/Examples/Resources/SqlSetup/8-UsingSkipRuleDuringInstall.ps1 b/source/Examples/Resources/SqlSetup/9-UsingSkipRuleDuringInstall.ps1 similarity index 100% rename from source/Examples/Resources/SqlSetup/8-UsingSkipRuleDuringInstall.ps1 rename to source/Examples/Resources/SqlSetup/9-UsingSkipRuleDuringInstall.ps1 diff --git a/tests/Unit/DSC_SqlSetup.Tests.ps1 b/tests/Unit/DSC_SqlSetup.Tests.ps1 index 5efad6987..b0f66d8e2 100644 --- a/tests/Unit/DSC_SqlSetup.Tests.ps1 +++ b/tests/Unit/DSC_SqlSetup.Tests.ps1 @@ -32,6 +32,9 @@ BeforeDiscovery { # Testing each supported SQL Server version $testProductVersion = @( + @{ + MockSqlMajorVersion = 16 # SQL Server 2022 + } @{ MockSqlMajorVersion = 15 # SQL Server 2019 } @@ -332,11 +335,11 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { InModuleScope -ScriptBlock { $script:mockGetTargetResourceParameters = @{ - InstanceName = 'MSSQLSERVER' - SourceCredential = $null - SourcePath = $TestDrive - Feature = 'NewFeature' # Test enabling a code-feature. - ServerName = 'host.company.local' + InstanceName = 'MSSQLSERVER' + SourceCredential = $null + SourcePath = $TestDrive + Feature = 'NewFeature' # Test enabling a code-feature. + ServerName = 'host.company.local' } } } @@ -394,6 +397,7 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $result.RSSvcAccountUsername | Should -BeNullOrEmpty $result.ASSvcAccountUsername | Should -BeNullOrEmpty $result.ASCollation | Should -BeNullOrEmpty + $result.ProductCoveredBySA | Should -BeFalse $result.ASSysAdminAccounts | Should -BeNullOrEmpty $result.ASDataDir | Should -BeNullOrEmpty $result.ASLogDir | Should -BeNullOrEmpty @@ -658,10 +662,10 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $script:mockSourcePathUNC = Join-Path -Path "\\localhost\$testDrive_DriveShare" -ChildPath (Split-Path -Path $TestDrive -NoQualifier) $script:mockGetTargetResourceParameters = @{ - InstanceName = 'MSSQLSERVER' - SourceCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @('COMPANY\sqladmin', ('dummyPassw0rd' | ConvertTo-SecureString -asPlainText -Force)) - SourcePath = $mockSourcePathUNC - SqlVersion = ('{0}.0' -f $MockSqlMajorVersion) + InstanceName = 'MSSQLSERVER' + SourceCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @('COMPANY\sqladmin', ('dummyPassw0rd' | ConvertTo-SecureString -asPlainText -Force)) + SourcePath = $mockSourcePathUNC + SqlVersion = ('{0}.0' -f $MockSqlMajorVersion) } } } @@ -828,6 +832,18 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $result.Features | Should -Match 'BOL\b' $result.Features | Should -Match 'MDS\b' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $result.Features | Should -Match 'SQLENGINE\b' + $result.Features | Should -Match 'REPLICATION\b' + $result.Features | Should -Match 'DQ\b' + $result.Features | Should -Match 'DQC\b' + $result.Features | Should -Match 'FULLTEXT\b' + $result.Features | Should -Match 'AS\b' + $result.Features | Should -Match 'IS\b' + $result.Features | Should -Match 'BOL\b' + $result.Features | Should -Match 'MDS\b' + } else { $result.Features | Should -Match 'SQLENGINE\b' @@ -972,6 +988,18 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $result.Features | Should -Match 'BC\b' $result.Features | Should -Match 'SDK\b' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $result.Features | Should -Match 'SQLENGINE\b' + $result.Features | Should -Match 'REPLICATION\b' + $result.Features | Should -Match 'DQ\b' + $result.Features | Should -Match 'DQC\b' + $result.Features | Should -Match 'FULLTEXT\b' + $result.Features | Should -Match 'AS\b' + $result.Features | Should -Match 'IS\b' + $result.Features | Should -Match 'BOL\b' + $result.Features | Should -Match 'MDS\b' + } else { $result.Features | Should -Match 'SQLENGINE\b' @@ -1205,6 +1233,18 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $result.Features | Should -Match 'BC\b' $result.Features | Should -Match 'SDK\b' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $result.Features | Should -Match 'SQLENGINE\b' + $result.Features | Should -Match 'REPLICATION\b' + $result.Features | Should -Match 'DQ\b' + $result.Features | Should -Match 'DQC\b' + $result.Features | Should -Match 'FULLTEXT\b' + $result.Features | Should -Match 'AS\b' + $result.Features | Should -Match 'IS\b' + $result.Features | Should -Match 'BOL\b' + $result.Features | Should -Match 'MDS\b' + } else { $result.Features | Should -Match 'SQLENGINE\b' @@ -1514,6 +1554,18 @@ Describe 'SqlSetup\Get-TargetResource' -Tag 'Get' { $result.Features | Should -Match 'BC\b' $result.Features | Should -Match 'SDK\b' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $result.Features | Should -Match 'SQLENGINE\b' + $result.Features | Should -Match 'REPLICATION\b' + $result.Features | Should -Match 'DQ\b' + $result.Features | Should -Match 'DQC\b' + $result.Features | Should -Match 'FULLTEXT\b' + $result.Features | Should -Match 'AS\b' + $result.Features | Should -Match 'IS\b' + $result.Features | Should -Match 'BOL\b' + $result.Features | Should -Match 'MDS\b' + } else { $result.Features | Should -Match 'SQLENGINE\b' @@ -2315,6 +2367,10 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { { $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,AS,IS,BOL,CONN,BC,SDK,MDS' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,AS,IS,BOL,MDS' + } else { $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,RS,AS,IS,BOL,CONN,BC,SDK,MDS,SSMS,ADV_SSMS' @@ -2351,7 +2407,7 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { BrowserSvcStartupType = 'Automatic' } - if ($MockSqlMajorVersion -in ('13', '14', '15')) + if ($MockSqlMajorVersion -in ('13', '14', '15', '16')) { $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',SSMS,ADV_SSMS', '' } @@ -2365,6 +2421,13 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { { $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',RS', '' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',Conn', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',RS', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',Bc', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',SDK', '' + } { Set-TargetResource @mockSetTargetResourceParameters } | Should -Not -Throw } @@ -2598,6 +2661,10 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { { $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,AS,IS,BOL,CONN,BC,SDK,MDS' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,AS,IS,BOL,MDS' + } else { $mockStartSqlSetupProcessExpectedArgument.Features = 'SQLENGINE,REPLICATION,DQ,DQC,FULLTEXT,RS,AS,IS,BOL,CONN,BC,SDK,MDS,SSMS,ADV_SSMS' @@ -2636,7 +2703,7 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { SqlVersion = ('{0}.0' -f $MockSqlMajorVersion) } - if ($MockSqlMajorVersion -in ('13', '14', '15')) + if ($MockSqlMajorVersion -in ('13', '14', '15', '16')) { $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',SSMS,ADV_SSMS', '' } @@ -2650,6 +2717,13 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { { $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',RS', '' } + elseif ($MockSqlMajorVersion -in ('16')) + { + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',Conn', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',RS', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',Bc', '' + $mockSetTargetResourceParameters.Features = $mockSetTargetResourceParameters.Features -replace ',SDK', '' + } { Set-TargetResource @mockSetTargetResourceParameters } | Should -Not -Throw } @@ -2707,6 +2781,52 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { } } + Context 'When installing the database engine and ProductcoveredBySA is true' { + BeforeAll { + Mock -CommandName Get-FilePathMajorVersion -MockWith { + return 16 + } + + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Features = '' + } + } + } + + It 'Should set the system in the desired state when feature is SQLENGINE' { + $mockStartSqlSetupProcessExpectedArgument = @{ + Quiet = 'True' + IAcceptSQLServerLicenseTerms = 'True' + Action = 'Install' + InstanceName = 'MSSQLSERVER' + Features = 'SQLENGINE' + SQLSysAdminAccounts = 'COMPANY\sqladmin COMPANY\SQLAdmins COMPANY\User1' + PID = '1FAKE-2FAKE-3FAKE-4FAKE-5FAKE' + ProductCoveredBySA = 'True' + } + + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $mockSetTargetResourceParameters = @{ + Features = 'SQLENGINE' + SQLSysAdminAccounts = 'COMPANY\User1', 'COMPANY\SQLAdmins' + InstanceName = 'MSSQLSERVER' + SourceCredential = $null + SourcePath = $TestDrive + ProductKey = '1FAKE-2FAKE-3FAKE-4FAKE-5FAKE' + ProductCoveredBySA = $true + ServerName = 'host.company.local' + } + + { Set-TargetResource @mockSetTargetResourceParameters } | Should -Not -Throw + } + + Should -Invoke -CommandName Start-SqlSetupProcess -Exactly -Times 1 -Scope It + } + } + Context 'When installing the database engine and disabling the TCP protocol' { BeforeAll { Mock -CommandName Get-FilePathMajorVersion -MockWith { @@ -2964,6 +3084,9 @@ Describe 'SqlSetup\Set-TargetResource' -Tag 'Set' { } Context 'When passing invalid features for ' -ForEach @( + @{ + MockSqlMajorVersion = 16 # SQL Server 2022 + } @{ MockSqlMajorVersion = 15 # SQL Server 2019 }