From e89e4f9fb25fe597e0fb457b9da9da94491003c7 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 14:52:56 +0100 Subject: [PATCH 01/10] Changes to xSQLServer Changed tests to be more dynamically and to find the bug in issue #401. --- Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 | 314 +++++++++++++--------- 1 file changed, 189 insertions(+), 125 deletions(-) diff --git a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 index eb8de204c..080c900a6 100644 --- a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 +++ b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 @@ -109,15 +109,19 @@ try $mockClusterNodes = @($env:COMPUTERNAME,'SQL01','SQL02') - $mockClusterDiskMap = @{ - UserData = 'K:' - UserLogs = 'L:' - TempDbData = 'M:' - TempDbLogs = 'N:' - SQLBackup = 'O:' + $mockClusterDiskMap = { + @{ + SysData = Split-Path -Path $mockDynamicSqlDataDirectoryPath -Qualifier + UserData = Split-Path -Path $mockDynamicSqlUserDatabasePath -Qualifier + UserLogs = Split-Path -Path $mockDynamicSqlUserDatabaseLogPath -Qualifier + TempDbData = Split-Path -Path $mockDynamicSqlTempDatabasePath -Qualifier + TempDbLogs = Split-Path -Path $mockDynamicSqlTempDatabaseLogPath -Qualifier + Backup = Split-Path -Path $mockDynamicSqlBackupPath -Qualifier + } } $mockCSVClusterDiskMap = @{ + SysData = @{Path='C:\ClusterStorage\SysData';Name="Cluster Virtual Disk (SQL System Data Disk)"} UserData = @{Path='C:\ClusterStorage\SQLData';Name="Cluster Virtual Disk (SQL Data Disk)"} UserLogs = @{Path='C:\ClusterStorage\SQLLogs';Name="Cluster Virtual Disk (SQL Log Disk)"} TempDbData = @{Path='C:\ClusterStorage\TempDBData';Name="Cluster Virtual Disk (SQL TempDBData Disk)"} @@ -479,9 +483,9 @@ try Add-Member -MemberType NoteProperty -Name 'LoginMode' -Value $mockSqlLoginMode -PassThru | Add-Member -MemberType NoteProperty -Name 'Collation' -Value $mockSqlCollation -PassThru | Add-Member -MemberType NoteProperty -Name 'InstallDataDirectory' -Value $mockSqlInstallPath -PassThru | - Add-Member -MemberType NoteProperty -Name 'BackupDirectory' -Value $mockSqlBackupPath -PassThru | - Add-Member -MemberType NoteProperty -Name 'SQLTempDBDir' -Value $mockSqlTempDatabasePath -PassThru | - Add-Member -MemberType NoteProperty -Name 'SQLTempDBLogDir' -Value $mockSqlTempDatabaseLogPath -PassThru | + Add-Member -MemberType NoteProperty -Name 'BackupDirectory' -Value $mockDynamicSqlBackupPath -PassThru | + Add-Member -MemberType NoteProperty -Name 'SQLTempDBDir' -Value $mockDynamicSqlTempDatabasePath -PassThru | + Add-Member -MemberType NoteProperty -Name 'SQLTempDBLogDir' -Value $mockDynamicSqlTempDatabaseLogPath -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultFile' -Value $mockSqlDefaultDatabaseFilePath -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultLog' -Value $mockSqlDefaultDatabaseLogPath -PassThru | Add-Member ScriptProperty Logins { @@ -503,9 +507,9 @@ try Add-Member -MemberType NoteProperty -Name 'LoginMode' -Value $mockSqlLoginMode -PassThru | Add-Member -MemberType NoteProperty -Name 'Collation' -Value $mockSqlCollation -PassThru | Add-Member -MemberType NoteProperty -Name 'InstallDataDirectory' -Value $mockSqlInstallPath -PassThru | - Add-Member -MemberType NoteProperty -Name 'BackupDirectory' -Value $mockSqlBackupPath -PassThru | - Add-Member -MemberType NoteProperty -Name 'SQLTempDBDir' -Value $mockSqlTempDatabasePath -PassThru | - Add-Member -MemberType NoteProperty -Name 'SQLTempDBLogDir' -Value $mockSqlTempDatabaseLogPath -PassThru | + Add-Member -MemberType NoteProperty -Name 'BackupDirectory' -Value $mockDynamicSqlBackupPath -PassThru | + Add-Member -MemberType NoteProperty -Name 'SQLTempDBDir' -Value $mockDynamicSqlTempDatabasePath -PassThru | + Add-Member -MemberType NoteProperty -Name 'SQLTempDBLogDir' -Value $mockDynamicSqlTempDatabaseLogPath -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultFile' -Value $mockSqlDefaultDatabaseFilePath -PassThru | Add-Member -MemberType NoteProperty -Name 'DefaultLog' -Value $mockSqlDefaultDatabaseLogPath -PassThru | Add-Member -MemberType NoteProperty -Name 'IsClustered' -Value $true -PassThru | @@ -625,6 +629,10 @@ try $mockGetCIMInstance_MSCluster_ClusterSharedVolume = { return @( + ( + New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | + Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockCSVClusterDiskMap['SysData'].Path -PassThru -Force + ), ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | Add-Member -MemberType NoteProperty -Name 'Name' -Value $mockCSVClusterDiskMap['UserData'].Path -PassThru -Force @@ -652,32 +660,37 @@ try return @( ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | - Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserData'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['SysData'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['SysData'].Name}) -PassThru -Force + ), + ( + New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserData'].Path}) -PassThru -Force | Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserData'].Name}) -PassThru -Force ), ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | - Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserLogs'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserLogs'].Path}) -PassThru -Force | Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['UserLogs'].Name}) -PassThru -Force ), ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | - Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBData'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBData'].Path}) -PassThru -Force | Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBData'].Name}) -PassThru -Force ), ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | - Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBLogs'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBLogs'].Path}) -PassThru -Force | Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['TempDBLogs'].Name}) -PassThru -Force ), ( New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_ClusterSharedVolume', 'root/MSCluster' | - Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['Backup'].Path}) -PassThru -Force | + Add-Member -MemberType NoteProperty -Name GroupComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['Backup'].Path}) -PassThru -Force | Add-Member -MemberType NoteProperty -Name PartComponent -Value (New-Object PSObject -Property @{Name=$mockCSVClusterDiskMap['Backup'].Name}) -PassThru -Force ) ) } - + @@ -743,7 +756,8 @@ try $mockGetCimAssociatedInstance_MSCluster_ResourceGroupToResource = { return @( ( - $mockClusterDiskMap.Keys | ForEach-Object { + # $mockClusterDiskMap contains variables that are assigned dynamically (during runtime) before each test. + (& $mockClusterDiskMap).Keys | ForEach-Object { $diskName = $_ New-Object Microsoft.Management.Infrastructure.CimInstance 'MSCluster_Resource','root/MSCluster' | Add-Member -MemberType NoteProperty -Name 'Name' -Value $diskName -PassThru -Force | @@ -768,7 +782,9 @@ try $mockGetCimAssociatedInstance_MSCluster_DiskPartition = { $clusterDiskName = $InputObject.Name - $clusterDiskPath = $mockClusterDiskMap.$clusterDiskName + + # $mockClusterDiskMap contains variables that are assigned dynamically (during runtime) before each test. + $clusterDiskPath = (& $mockClusterDiskMap).$clusterDiskName return @( ( @@ -817,7 +833,7 @@ try } # Start by checking whether we have the same number of parameters - New-VerboseMessage 'Verifying argument count (expected vs actual)' + Write-Verbose 'Verifying argument count (expected vs actual)' -Verbose $mockStartWin32ProcessExpectedArgument.Keys.Count | Should BeExactly $argumentHashTable.Keys.Count foreach ($argumentKey in $mockStartWin32ProcessExpectedArgument.Keys) @@ -849,11 +865,6 @@ try # Feature support is tested elsewhere, so just include the minimum Features = 'SQLEngine' - # Ensure we use "clustered" disks for our paths - SQLUserDBDir = 'K:\MSSQL\Data\' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDbDir = 'M:\MSSQL\TempDb\Data\' - SQLTempDbLogDir = 'N:\MSSQL\TempDb\Logs' } Describe "xSQLServerSetup\Get-TargetResource" -Tag 'Get' { @@ -919,9 +930,9 @@ try $mockDefaultInstance_InstanceId = "$($mockSqlDatabaseEngineName)$($mockSqlMajorVersion).$($mockDefaultInstance_InstanceName)" $mockSqlInstallPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL" - $mockSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" - $mockSqlTempDatabasePath = '' - $mockSqlTempDatabaseLogPath = '' + $mockDynamicSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" + $mockDynamicSqlTempDatabasePath = '' + $mockDynamicSqlTempDatabaseLogPath = '' $mockSqlDefaultDatabaseFilePath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" $mockSqlDefaultDatabaseLogPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" @@ -1426,7 +1437,7 @@ try $result.InstallSQLDataDir | Should Be $mockSqlInstallPath $result.SQLUserDBDir | Should Be $mockSqlDefaultDatabaseFilePath $result.SQLUserDBLogDir | Should Be $mockSqlDefaultDatabaseLogPath - $result.SQLBackupDir | Should Be $mockSqlBackupPath + $result.SQLBackupDir | Should Be $mockDynamicSqlBackupPath $result.FTSvcAccountUsername | Should Be $mockSqlServiceAccount $result.RSSvcAccountUsername | Should Be $mockSqlServiceAccount $result.ASSvcAccountUsername | Should Be $mockSqlServiceAccount @@ -1622,7 +1633,7 @@ try $result.InstallSQLDataDir | Should Be $mockSqlInstallPath $result.SQLUserDBDir | Should Be $mockSqlDefaultDatabaseFilePath $result.SQLUserDBLogDir | Should Be $mockSqlDefaultDatabaseLogPath - $result.SQLBackupDir | Should Be $mockSqlBackupPath + $result.SQLBackupDir | Should Be $mockDynamicSqlBackupPath $result.FTSvcAccountUsername | Should Be $mockSqlServiceAccount $result.RSSvcAccountUsername | Should Be $mockSqlServiceAccount $result.ASSvcAccountUsername | Should Be $mockSqlServiceAccount @@ -1640,9 +1651,9 @@ try $mockNamedInstance_InstanceId = "$($mockSqlDatabaseEngineName)$($mockSqlMajorVersion).$($mockNamedInstance_InstanceName)" $mockSqlInstallPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL" - $mockSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\Backup" - $mockSqlTempDatabasePath = '' - $mockSqlTempDatabaseLogPath = '' + $mockDynamicSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\Backup" + $mockDynamicSqlTempDatabasePath = '' + $mockDynamicSqlTempDatabaseLogPath = '' $mockSqlDefaultDatabaseFilePath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\DATA\" $mockSqlDefaultDatabaseLogPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\DATA\" @@ -1931,7 +1942,7 @@ try $result.InstallSQLDataDir | Should Be $mockSqlInstallPath $result.SQLUserDBDir | Should Be $mockSqlDefaultDatabaseFilePath $result.SQLUserDBLogDir | Should Be $mockSqlDefaultDatabaseLogPath - $result.SQLBackupDir | Should Be $mockSqlBackupPath + $result.SQLBackupDir | Should Be $mockDynamicSqlBackupPath $result.FTSvcAccountUsername | Should Be $mockSqlServiceAccount $result.RSSvcAccountUsername | Should Be $mockSqlServiceAccount $result.ASSvcAccountUsername | Should Be $mockSqlServiceAccount @@ -2093,9 +2104,9 @@ try $mockDefaultInstance_InstanceId = "$($mockSqlDatabaseEngineName)$($mockSqlMajorVersion).$($mockDefaultInstance_InstanceName)" $mockSqlInstallPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL" - $mockSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" - $mockSqlTempDatabasePath = '' - $mockSqlTempDatabaseLogPath = '' + $mockDynamicSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" + $mockDynamicSqlTempDatabasePath = '' + $mockDynamicSqlTempDatabaseLogPath = '' $mockSqlDefaultDatabaseFilePath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" $mockSqlDefaultDatabaseLogPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" @@ -2552,7 +2563,7 @@ try Mock -CommandName Connect-SQL -MockWith $mockConnectSQLCluster -Verifiable - Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterResource -Verifiable -ParameterFilter { + Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterResource -Verifiable -ParameterFilter { $Filter -eq "Type = 'SQL Server'" } @@ -2568,8 +2579,15 @@ try FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName } - New-Variable -Name 'FailoverClusterDisks' -Value $mockClusterDiskMap['UserData'] - + $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' + $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' + $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' + $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' + $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' + $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + + New-Variable -Name 'FailoverClusterDisks' -Value (& $mockClusterDiskMap)['UserData'] + $result = Test-TargetResource @testClusterParameters $result | Should Be $true @@ -2681,9 +2699,9 @@ try $mockDefaultInstance_InstanceId = "$($mockSqlDatabaseEngineName)$($mockSqlMajorVersion).$($mockDefaultInstance_InstanceName)" $mockSqlInstallPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL" - $mockSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" - $mockSqlTempDatabasePath = '' - $mockSqlTempDatabaseLogPath = '' + $mockDynamicSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\Backup" + $mockDynamicSqlTempDatabasePath = '' + $mockDynamicSqlTempDatabaseLogPath = '' $mockSqlDefaultDatabaseFilePath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" $mockSqlDefaultDatabaseLogPath = "C:\Program Files\Microsoft SQL Server\$($mockDefaultInstance_InstanceId)\MSSQL\DATA\" @@ -3189,9 +3207,9 @@ try $mockNamedInstance_InstanceId = "$($mockSqlDatabaseEngineName)$($mockSqlMajorVersion).$($mockNamedInstance_InstanceName)" $mockSqlInstallPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL" - $mockSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\Backup" - $mockSqlTempDatabasePath = '' - $mockSqlTempDatabaseLogPath = '' + $mockDynamicSqlBackupPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\Backup" + $mockDynamicSqlTempDatabasePath = '' + $mockDynamicSqlTempDatabaseLogPath = '' $mockSqlDefaultDatabaseFilePath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\DATA\" $mockSqlDefaultDatabaseLogPath = "C:\Program Files\Microsoft SQL Server\$($mockNamedInstance_InstanceId)\MSSQL\DATA\" @@ -3374,7 +3392,7 @@ try $Filter -eq "Name = 'Available Storage'" } -Verifiable - Mock -CommandName Get-CimAssociatedInstance -MockWith $mockGetCimAssociatedInstance_MSCluster_ResourceGroupToResource -ParameterFilter { + Mock -CommandName Get-CimAssociatedInstance -MockWith $mockGetCimAssociatedInstance_MSCluster_ResourceGroupToResource -ParameterFilter { ($Association -eq 'MSCluster_ResourceGroupToResource') -and ($ResultClassName -eq 'MSCluster_Resource') } -Verfiable @@ -3386,7 +3404,7 @@ try $ResultClassName -eq 'MSCluster_DiskPartition' } -Verifiable - Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterNetwork -ParameterFilter { + Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterNetwork -ParameterFilter { ($Namespace -eq 'root/MSCluster') -and ($ClassName -eq 'MSCluster_Network') -and ($Filter -eq 'Role >= 2') } -Verifiable @@ -3429,12 +3447,18 @@ try { Set-TargetResource @testParameters } | Should Not Throw } } - + # For testing InstallFailoverCluster action Context "When SQL Server version is $mockSQLMajorVersion and the system is not in the desired state and the action is InstallFailoverCluster" { BeforeAll { - $testParameters = $mockDefaultClusterParameters.Clone() + $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' + $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' + $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' + $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' + $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' + $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + $testParameters = $mockDefaultClusterParameters.Clone() $testParameters += @{ InstanceName = 'MSSQLSERVER' SourcePath = $mockSourcePath @@ -3442,16 +3466,21 @@ try FailoverClusterGroupName = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName FailoverClusterIPAddress = $mockDefaultInstance_FailoverClusterIPAddress - } - } + # Ensure we use "clustered" disks for our paths + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDbDir = $mockDynamicSqlTempDatabasePath + SQLTempDbLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + } - BeforeAll { Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterResourceGroup_AvailableStorage -ParameterFilter { $Filter -eq "Name = 'Available Storage'" } -Verifiable - Mock -CommandName Get-CimAssociatedInstance -MockWith $mockGetCimAssociatedInstance_MSCluster_ResourceGroupToResource -ParameterFilter { + Mock -CommandName Get-CimAssociatedInstance -MockWith $mockGetCimAssociatedInstance_MSCluster_ResourceGroupToResource -ParameterFilter { ($Association -eq 'MSCluster_ResourceGroupToResource') -and ($ResultClassName -eq 'MSCluster_Resource') } -Verfiable @@ -3471,7 +3500,7 @@ try $ClassName -eq 'MSCluster_ClusterSharedVolumeToResource' } -Verifiable - Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterNetwork -ParameterFilter { + Mock -CommandName Get-CimInstance -MockWith $mockGetCimInstance_MSClusterNetwork -ParameterFilter { ($Namespace -eq 'root/MSCluster') -and ($ClassName -eq 'MSCluster_Network') -and ($Filter -eq 'Role >= 2') } -Verifiable @@ -3488,22 +3517,19 @@ try } It 'Should pass proper parameters to setup' { - $mockStartWin32ProcessExpectedArgument = @{ - IAcceptSQLServerLicenseTerms = 'True' - SkipRules = 'Cluster_VerifyForErrors' - Quiet = 'True' - SQLSysAdminAccounts = 'COMPANY\sqladmin' + $mockStartWin32ProcessExpectedArgument = $mockStartWin32ProcessExpectedArgumentClusterDefault.Clone() + $mockStartWin32ProcessExpectedArgument += @{ Action = 'InstallFailoverCluster' - InstanceName = 'MSSQLSERVER' - Features = 'SQLEngine' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs; SysData' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite - FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' + SkipRules = 'Cluster_VerifyForErrors' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath } { Set-TargetResource @testParameters } | Should Not Throw @@ -3519,28 +3545,30 @@ try { Set-TargetResource @testParameters } | Should Not Throw } + It 'Should throw an error when one or more paths are not resolved to clustered storage' { $badPathParameters = $testParameters.Clone() - + # Pass in a bad path $badPathParameters.SQLUserDBDir = 'C:\MSSQL\' - { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: TempDbData; TempDbLogs; UserLogs' + { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; TempDbData; TempDbLogs; UserLogs' } It 'Should properly map paths to clustered disk resources' { - $mockStartWin32ProcessExpectedArgument = $mockStartWin32ProcessExpectedArgumentClusterDefault.Clone() - $mockStartWin32ProcessExpectedArgument += @{ + $mockStartWin32ProcessExpectedArgument += @{ Action = 'InstallFailoverCluster' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath SkipRules = 'Cluster_VerifyForErrors' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' } { Set-TargetResource @testParameters } | Should Not Throw @@ -3555,11 +3583,13 @@ try Action = 'InstallFailoverCluster' FailoverClusterIPAddresses = 'DEFAULT' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' } @@ -3594,11 +3624,13 @@ try $mockStartWin32ProcessExpectedArgument += @{ FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'InstallFailoverCluster' } @@ -3617,11 +3649,13 @@ try $mockStartWin32ProcessExpectedArgument += @{ FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_MultiSite FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'InstallFailoverCluster' } @@ -3631,12 +3665,14 @@ try It 'Should pass proper parameters to setup when Cluster Shared volumes are specified' { $csvTestParameters = $testParameters.Clone() - + + $csvTestParameters['InstallSQLDataDir'] = $mockCSVClusterDiskMap['SysData'].Path $csvTestParameters['SQLUserDBDir'] = $mockCSVClusterDiskMap['UserData'].Path $csvTestParameters['SQLUserDBLogDir'] = $mockCSVClusterDiskMap['UserLogs'].Path $csvTestParameters['SQLTempDBDir'] = $mockCSVClusterDiskMap['TempDBData'].Path $csvTestParameters['SQLTempDBLogDir'] = $mockCSVClusterDiskMap['TempDBLogs'].Path - + $csvTestParameters['SQLBackupDir'] = $mockCSVClusterDiskMap['Backup'].Path + $mockStartWin32ProcessExpectedArgument = @{ IAcceptSQLServerLicenseTerms = 'True' SkipRules = 'Cluster_VerifyForErrors' @@ -3645,14 +3681,16 @@ try Action = 'InstallFailoverCluster' InstanceName = 'MSSQLSERVER' Features = 'SQLEngine' - FailoverClusterDisks = "$($mockCSVClusterDiskMap['UserData'].Name); $($mockCSVClusterDiskMap['UserLogs'].Name); $($mockCSVClusterDiskMap['TempDBData'].Name); $($mockCSVClusterDiskMap['TempDBLogs'].Name)" + FailoverClusterDisks = "$($mockCSVClusterDiskMap['Backup'].Name); $($mockCSVClusterDiskMap['UserData'].Name); $($mockCSVClusterDiskMap['UserLogs'].Name); $($mockCSVClusterDiskMap['TempDBData'].Name); $($mockCSVClusterDiskMap['TempDBLogs'].Name)" FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName + InstallSQLDataDir = $mockCSVClusterDiskMap['SysData'].Path SQLUserDBDir = $mockCSVClusterDiskMap['UserData'].Path SQLUserDBLogDir = $mockCSVClusterDiskMap['UserLogs'].Path SQLTempDBDir = $mockCSVClusterDiskMap['TempDBData'].Path SQLTempDBLogDir = $mockCSVClusterDiskMap['TempDBLogs'].Path + SQLBackupDir = $mockCSVClusterDiskMap['Backup'].Path } { Set-TargetResource @csvTestParameters } | Should Not Throw @@ -3660,13 +3698,14 @@ try It 'Should pass proper parameters to setup when Cluster Shared volumes are specified and are the same for one or more parameter values' { $csvTestParameters = $testParameters.Clone() - + + $csvTestParameters['InstallSQLDataDir'] = $mockCSVClusterDiskMap['SysData'].Path + '\Data' $csvTestParameters['SQLUserDBDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\Data' $csvTestParameters['SQLUserDBLogDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\Logs' $csvTestParameters['SQLTempDBDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\TEMPDB' $csvTestParameters['SQLTempDBLogDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\TEMPDBLOG' $csvTestParameters['SQLBackupDir'] = $mockCSVClusterDiskMap['Backup'].Path + '\Backup' - + $mockStartWin32ProcessExpectedArgument = @{ IAcceptSQLServerLicenseTerms = 'True' SkipRules = 'Cluster_VerifyForErrors' @@ -3679,6 +3718,7 @@ try FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName + InstallSQLDataDir = "$($mockCSVClusterDiskMap['SysData'].Path)\Data" SQLUserDBDir = "$($mockCSVClusterDiskMap['UserData'].Path)\Data" SQLUserDBLogDir = "$($mockCSVClusterDiskMap['UserData'].Path)\Logs" SQLTempDBDir = "$($mockCSVClusterDiskMap['UserData'].Path)\TEMPDB" @@ -3785,8 +3825,14 @@ try Context "When SQL Server version is $mockSqlMajorVersion and the system is not in the desired state and the action is CompleteFailoverCluster." { BeforeEach { - $testParameters = $mockDefaultClusterParameters.Clone() + $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' + $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' + $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' + $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' + $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' + $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + $testParameters = $mockDefaultClusterParameters.Clone() $testParameters += @{ InstanceName = 'MSSQLSERVER' SourcePath = $mockSourcePath @@ -3794,6 +3840,14 @@ try FailoverClusterGroupName = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName FailoverClusterIPAddress = $mockDefaultInstance_FailoverClusterIPAddress + + # Ensure we use "clustered" disks for our paths + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDbDir = $mockDynamicSqlTempDatabasePath + SQLTempDbLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath } } @@ -3835,7 +3889,7 @@ try # Pass in a bad path $badPathParameters.SQLUserDBDir = 'C:\MSSQL\' - { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: TempDbData; TempDbLogs; UserLogs' + { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; TempDbData; TempDbLogs; UserLogs' } It 'Should properly map paths to clustered disk resources' { @@ -3844,13 +3898,15 @@ try $mockStartWin32ProcessExpectedArgument += @{ Action = 'CompleteFailoverCluster' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath SkipRules = 'Cluster_VerifyForErrors' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' } { Set-TargetResource @testParameters } | Should Not Throw @@ -3865,11 +3921,13 @@ try Action = 'CompleteFailoverCluster' FailoverClusterIPAddresses = 'DEFAULT' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' } @@ -3904,11 +3962,13 @@ try $mockStartWin32ProcessExpectedArgument += @{ FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'CompleteFailoverCluster' } @@ -3927,11 +3987,13 @@ try $mockStartWin32ProcessExpectedArgument += @{ FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_MultiSite FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'CompleteFailoverCluster' } @@ -3949,14 +4011,16 @@ try Action = 'CompleteFailoverCluster' InstanceName = 'MSSQLSERVER' Features = 'SQLEngine' - FailoverClusterDisks = 'TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - SQLUserDBDir = 'K:\MSSQL\Data' - SQLUserDBLogDir = 'L:\MSSQL\Logs' - SQLTempDBDir = 'M:\MSSQL\TempDb\Data' - SQLTempDBLogDir = 'N:\MSSQL\TempDb\Logs' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + SQLUserDBDir = $mockDynamicSqlUserDatabasePath + SQLUserDBLogDir = $mockDynamicSqlUserDatabaseLogPath + SQLTempDBDir = $mockDynamicSqlTempDatabasePath + SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath + SQLBackupDir = $mockDynamicSqlBackupPath } { Set-TargetResource @testParameters } | Should Not Throw From edc5a87d383464366131d033bb682835743daf09 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 17:50:12 +0100 Subject: [PATCH 02/10] Changes to xSQLServerSetup Now it can correctly determine the right cluster when only parameter InstallSQLDataDir is assigned a path (issue #401). Now the only mandatory path parameter is InstallSQLDataDir when installing Database Engine (issue #400). It now can handle mandatory parameters, and are not using wildcards to find the variables containing paths (issue #394). --- .../MSFT_xSQLServerSetup.psm1 | 56 +++++++-- README.md | 30 ++--- Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 | 119 +++++++++++++----- 3 files changed, 138 insertions(+), 67 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index 287955234..87f78f153 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -824,10 +824,38 @@ function Set-TargetResource # Perform disk mapping for specific cluster installation types if ($Action -in @('CompleteFailoverCluster','InstallFailoverCluster')) { - $failoverClusterDisks = @() - # Get a required lising of drives based on user parameters - $requiredDrives = Get-Variable -Name 'SQL*Dir' -ValueOnly | Where-Object { -not [String]::IsNullOrEmpty($_) } | Sort-Object -Unique | Add-Member -MemberType NoteProperty -Name IsMapped -Value $false -PassThru + $parametersToEvaluatePathFor = @( + 'InstallSQLDataDir' + 'SQLUserDBDir' + 'SQLUserDBLogDir' + 'SQLTempDBDir' + 'SQLTempDBLogDir' + 'SQLBackupDir' + ) + + $requiredDrive = @() + + <# + Get a required lising of drives based on user parameters. + Using $MyInvocation.MyCommand.Parameters.GetEnumerator() instead of PSBoundParameters + to be able to get default parameters. + #> + foreach ($parameter in $MyInvocation.MyCommand.Parameters.GetEnumerator()) + { + $parameterName = $parameter.Key + if ($parameterName -in $parametersToEvaluatePathFor) + { + $parameterValue = Get-Variable -Name $parameterName -ValueOnly -ErrorAction SilentlyContinue + if ($parameterValue) + { + New-VerboseMessage -Message ("Found assigned parameter '{0}'. Adding path '{1}' to required cluster drives." -f $parameterName, $parameterValue) + $requiredDrive += $parameterValue + } + } + } + + $requiredDrive = $requiredDrive | Sort-Object -Unique | Add-Member -MemberType NoteProperty -Name IsMapped -Value $false -PassThru # Get the disk resources that are available (not assigned to a cluster role) $availableStorage = Get-CimInstance -Namespace 'root/MSCluster' -ClassName 'MSCluster_ResourceGroup' -Filter "Name = 'Available Storage'" | @@ -846,27 +874,29 @@ function Set-TargetResource } } - foreach ($requiredDrive in $requiredDrives) + $failoverClusterDisks = @() + + foreach ($currentRequiredDrive in $requiredDrive) { foreach ($diskResource in ($availableStorage | Where-Object {$_.IsPossibleOwner -eq $true})) { $partitions = $diskResource | Get-CimAssociatedInstance -ResultClassName 'MSCluster_DiskPartition' | Select-Object -ExpandProperty Path foreach ($partition in $partitions) { - if ($requiredDrive -imatch $partition.Replace('\','\\')) + if ($currentRequiredDrive -imatch $partition.Replace('\','\\')) { - $requiredDrive.IsMapped = $true + $currentRequiredDrive.IsMapped = $true $failoverClusterDisks += $diskResource.Name break } - if ($requiredDrive.IsMapped) + if ($currentRequiredDrive.IsMapped) { break } } - if ($requiredDrive.IsMapped) + if ($currentRequiredDrive.IsMapped) { break } @@ -878,16 +908,16 @@ function Set-TargetResource foreach ($clusterSharedVolume in $clusterSharedVolumes) { - foreach ($requiredDrive in ($requiredDrives | Where-Object {$_.IsMapped -eq $false})) + foreach ($currentRequiredDrive in ($requiredDrive | Where-Object {$_.IsMapped -eq $false})) { - if ($requiredDrive -imatch $clusterSharedVolume.Name.Replace('\','\\')) + if ($currentRequiredDrive -imatch $clusterSharedVolume.Name.Replace('\','\\')) { $diskName = Get-CimInstance -ClassName 'MSCluster_ClusterSharedVolumeToResource' -Namespace 'root/MSCluster' | ` Where-Object {$_.GroupComponent.Name -eq $clusterSharedVolume.Name} | ` Select-Object -ExpandProperty PartComponent | ` Select-Object -ExpandProperty Name $failoverClusterDisks += $diskName - $requiredDrive.IsMapped = $true + $currentRequiredDrive.IsMapped = $true } } } @@ -896,7 +926,7 @@ function Set-TargetResource $failoverClusterDisks = $failoverClusterDisks | Sort-Object -Unique # Ensure we mapped all required drives - $unMappedRequiredDrives = $requiredDrives | Where-Object {$_.IsMapped -eq $false} | Measure-Object + $unMappedRequiredDrives = $requiredDrive | Where-Object {$_.IsMapped -eq $false} | Measure-Object if ($unMappedRequiredDrives.Count -gt 0) { throw New-TerminatingError -ErrorType FailoverClusterDiskMappingError -FormatArgs ($failoverClusterDisks -join '; ') -ErrorCategory InvalidResult @@ -1153,7 +1183,7 @@ function Set-TargetResource Path = $pathToSetupExecutable Arguments = $arguments } - + if ($Action -in @('InstallFailoverCluster','AddNode')) { $processArguments.Add('Credential',$SetupCredential) diff --git a/README.md b/README.md index 9ed44ea37..5ca5368a1 100644 --- a/README.md +++ b/README.md @@ -854,27 +854,15 @@ Installs SQL Server on the target node. #### Requirements * Target machine must be running Windows Server 2008 R2 or later. - -For configurations that utilize the 'InstallFailoverCluster' action, the following parameters are required (beyond those required for the standalone installation): - -* InstanceName (can be MSSQLSERVER if you want to install a default clustered instance) -* FailoverClusterNetworkName -* When installation SQL Server database engine: - * InstallSQLDataDir - * SQLUserDBDir - * SQLUserDBLogDir - * SQLTempDBDir - * SQLTempDBLogDir - * SQLBackupDir - * AgtSvcAccount - * SQLSvcAccount -* When installing SQL Analysis Services - * ASDataDir - * ASLogDir - * ASBackupDir - * ASTempDir - * ASConfigDir - * AsSvcAccount +* For configurations that utilize the 'InstallFailoverCluster' action, the following parameters are required (beyond those required for the standalone installation) + * InstanceName (can be MSSQLSERVER if you want to install a default clustered instance) + * FailoverClusterNetworkName + * When installation SQL Server database engine: + * InstallSQLDataDir + * AgtSvcAccount + * SQLSvcAccount + * When installing SQL Analysis Services + * AsSvcAccount #### Parameters diff --git a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 index 080c900a6..408986041 100644 --- a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 +++ b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 @@ -109,6 +109,13 @@ try $mockClusterNodes = @($env:COMPUTERNAME,'SQL01','SQL02') + $mockSqlDataDirectoryPath = 'E:\MSSQL\Data' + $mockSqlUserDatabasePath = 'K:\MSSQL\Data' + $mockSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' + $mockSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' + $mockSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' + $mockSqlBackupPath = 'O:\MSSQL\Backup' + $mockClusterDiskMap = { @{ SysData = Split-Path -Path $mockDynamicSqlDataDirectoryPath -Qualifier @@ -2579,12 +2586,12 @@ try FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName } - $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' - $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' - $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' - $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' - $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' - $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + $mockDynamicSqlDataDirectoryPath = $mockSqlDataDirectoryPath + $mockDynamicSqlUserDatabasePath = $mockSqlUserDatabasePath + $mockDynamicSqlUserDatabaseLogPath = $mockSqlUserDatabaseLogPath + $mockDynamicSqlTempDatabasePath = $mockSqlTempDatabasePath + $mockDynamicSqlTempDatabaseLogPath = $mockSqlTempDatabaseLogPath + $mockDynamicSqlBackupPath = $mockSqlBackupPath New-Variable -Name 'FailoverClusterDisks' -Value (& $mockClusterDiskMap)['UserData'] @@ -3451,12 +3458,12 @@ try # For testing InstallFailoverCluster action Context "When SQL Server version is $mockSQLMajorVersion and the system is not in the desired state and the action is InstallFailoverCluster" { BeforeAll { - $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' - $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' - $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' - $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' - $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' - $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + $mockDynamicSqlDataDirectoryPath = $mockSqlDataDirectoryPath + $mockDynamicSqlUserDatabasePath = $mockSqlUserDatabasePath + $mockDynamicSqlUserDatabaseLogPath = $mockSqlUserDatabaseLogPath + $mockDynamicSqlTempDatabasePath = $mockSqlTempDatabasePath + $mockDynamicSqlTempDatabaseLogPath = $mockSqlTempDatabaseLogPath + $mockDynamicSqlBackupPath = $mockSqlBackupPath $testParameters = $mockDefaultClusterParameters.Clone() $testParameters += @{ @@ -3520,7 +3527,7 @@ try $mockStartWin32ProcessExpectedArgument = $mockStartWin32ProcessExpectedArgumentClusterDefault.Clone() $mockStartWin32ProcessExpectedArgument += @{ Action = 'InstallFailoverCluster' - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs; SysData' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName SkipRules = 'Cluster_VerifyForErrors' @@ -3535,6 +3542,52 @@ try { Set-TargetResource @testParameters } | Should Not Throw } + It 'Should pass proper parameters to setup when only InstallSQLDataDir is assigned a path' { + $mockStartWin32ProcessExpectedArgument = $mockStartWin32ProcessExpectedArgumentClusterDefault.Clone() + $mockStartWin32ProcessExpectedArgument += @{ + Action = 'InstallFailoverCluster' + FailoverClusterDisks = 'SysData' + FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite + FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName + SkipRules = 'Cluster_VerifyForErrors' + InstallSQLDataDir = $mockDynamicSqlDataDirectoryPath + } + + $setTargetResourceParameters = $testParameters.Clone() + $setTargetResourceParameters.Remove('SQLUserDBDir') + $setTargetResourceParameters.Remove('SQLUserDBLogDir') + $setTargetResourceParameters.Remove('SQLTempDbDir') + $setTargetResourceParameters.Remove('SQLTempDbLogDir') + $setTargetResourceParameters.Remove('SQLBackupDir') + + { Set-TargetResource @setTargetResourceParameters } | Should Not Throw + } + + It 'Should pass proper parameters to setup when three variables are assigned the same drive, but different paths' { + $mockStartWin32ProcessExpectedArgument = $mockStartWin32ProcessExpectedArgumentClusterDefault.Clone() + $mockStartWin32ProcessExpectedArgument += @{ + Action = 'InstallFailoverCluster' + FailoverClusterDisks = 'SysData' + FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite + FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName + SkipRules = 'Cluster_VerifyForErrors' + InstallSQLDataDir = 'E:\SQLData' + SQLUserDBDir = 'E:\SQLData\UserDb' + SQLUserDBLogDir = 'E:\SQLData\UserDbLogs' + } + + $setTargetResourceParameters = $testParameters.Clone() + $setTargetResourceParameters.Remove('SQLTempDbDir') + $setTargetResourceParameters.Remove('SQLTempDbLogDir') + $setTargetResourceParameters.Remove('SQLBackupDir') + + $setTargetResourceParameters['InstallSQLDataDir'] = 'E:\SQLData' + $setTargetResourceParameters['SQLUserDBDir'] = 'E:\SQLData\UserDb' + $setTargetResourceParameters['SQLUserDBLogDir'] = 'E:\SQLData\UserDbLogs' + + { Set-TargetResource @setTargetResourceParameters } | Should Not Throw + } + It 'Should pass the SetupCredential object to the StartWin32Process function' { $mockStartWin32Process_SetupCredential = { $Credential | Should Not BeNullOrEmpty @@ -3552,7 +3605,7 @@ try # Pass in a bad path $badPathParameters.SQLUserDBDir = 'C:\MSSQL\' - { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; TempDbData; TempDbLogs; UserLogs' + { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; SysData; TempDbData; TempDbLogs; UserLogs' } It 'Should properly map paths to clustered disk resources' { @@ -3568,7 +3621,7 @@ try SQLBackupDir = $mockDynamicSqlBackupPath SkipRules = 'Cluster_VerifyForErrors' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' } { Set-TargetResource @testParameters } | Should Not Throw @@ -3589,7 +3642,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' } @@ -3630,7 +3683,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'InstallFailoverCluster' } @@ -3655,7 +3708,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'InstallFailoverCluster' } @@ -3681,7 +3734,7 @@ try Action = 'InstallFailoverCluster' InstanceName = 'MSSQLSERVER' Features = 'SQLEngine' - FailoverClusterDisks = "$($mockCSVClusterDiskMap['Backup'].Name); $($mockCSVClusterDiskMap['UserData'].Name); $($mockCSVClusterDiskMap['UserLogs'].Name); $($mockCSVClusterDiskMap['TempDBData'].Name); $($mockCSVClusterDiskMap['TempDBLogs'].Name)" + FailoverClusterDisks = "$($mockCSVClusterDiskMap['Backup'].Name); $($mockCSVClusterDiskMap['UserData'].Name); $($mockCSVClusterDiskMap['UserLogs'].Name); $($mockCSVClusterDiskMap['SysData'].Name); $($mockCSVClusterDiskMap['TempDBData'].Name); $($mockCSVClusterDiskMap['TempDBLogs'].Name)" FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName @@ -3699,7 +3752,7 @@ try It 'Should pass proper parameters to setup when Cluster Shared volumes are specified and are the same for one or more parameter values' { $csvTestParameters = $testParameters.Clone() - $csvTestParameters['InstallSQLDataDir'] = $mockCSVClusterDiskMap['SysData'].Path + '\Data' + $csvTestParameters['InstallSQLDataDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\Data' $csvTestParameters['SQLUserDBDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\Data' $csvTestParameters['SQLUserDBLogDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\Logs' $csvTestParameters['SQLTempDBDir'] = $mockCSVClusterDiskMap['UserData'].Path + '\TEMPDB' @@ -3718,7 +3771,7 @@ try FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - InstallSQLDataDir = "$($mockCSVClusterDiskMap['SysData'].Path)\Data" + InstallSQLDataDir = "$($mockCSVClusterDiskMap['UserData'].Path)\Data" SQLUserDBDir = "$($mockCSVClusterDiskMap['UserData'].Path)\Data" SQLUserDBLogDir = "$($mockCSVClusterDiskMap['UserData'].Path)\Logs" SQLTempDBDir = "$($mockCSVClusterDiskMap['UserData'].Path)\TEMPDB" @@ -3825,12 +3878,12 @@ try Context "When SQL Server version is $mockSqlMajorVersion and the system is not in the desired state and the action is CompleteFailoverCluster." { BeforeEach { - $mockDynamicSqlDataDirectoryPath = 'E:\MSSQL\Data' - $mockDynamicSqlUserDatabasePath = 'K:\MSSQL\Data' - $mockDynamicSqlUserDatabaseLogPath = 'L:\MSSQL\Logs' - $mockDynamicSqlTempDatabasePath = 'M:\MSSQL\TempDb\Data' - $mockDynamicSqlTempDatabaseLogPath = 'N:\MSSQL\TempDb\Logs' - $mockDynamicSqlBackupPath = 'O:\MSSQL\Backup' + $mockDynamicSqlDataDirectoryPath = $mockSqlDataDirectoryPath + $mockDynamicSqlUserDatabasePath = $mockSqlUserDatabasePath + $mockDynamicSqlUserDatabaseLogPath = $mockSqlUserDatabaseLogPath + $mockDynamicSqlTempDatabasePath = $mockSqlTempDatabasePath + $mockDynamicSqlTempDatabaseLogPath = $mockSqlTempDatabaseLogPath + $mockDynamicSqlBackupPath = $mockSqlBackupPath $testParameters = $mockDefaultClusterParameters.Clone() $testParameters += @{ @@ -3889,7 +3942,7 @@ try # Pass in a bad path $badPathParameters.SQLUserDBDir = 'C:\MSSQL\' - { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; TempDbData; TempDbLogs; UserLogs' + { Set-TargetResource @badPathParameters } | Should Throw 'Unable to map the specified paths to valid cluster storage. Drives mapped: Backup; SysData; TempDbData; TempDbLogs; UserLogs' } It 'Should properly map paths to clustered disk resources' { @@ -3906,7 +3959,7 @@ try SQLBackupDir = $mockDynamicSqlBackupPath SkipRules = 'Cluster_VerifyForErrors' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' } { Set-TargetResource @testParameters } | Should Not Throw @@ -3927,7 +3980,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' } @@ -3968,7 +4021,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'CompleteFailoverCluster' } @@ -3993,7 +4046,7 @@ try SQLTempDBDir = $mockDynamicSqlTempDatabasePath SQLTempDBLogDir = $mockDynamicSqlTempDatabaseLogPath SQLBackupDir = $mockDynamicSqlBackupPath - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' SkipRules = 'Cluster_VerifyForErrors' Action = 'CompleteFailoverCluster' } @@ -4011,7 +4064,7 @@ try Action = 'CompleteFailoverCluster' InstanceName = 'MSSQLSERVER' Features = 'SQLEngine' - FailoverClusterDisks = 'Backup; TempDbData; TempDbLogs; UserData; UserLogs' + FailoverClusterDisks = 'Backup; SysData; TempDbData; TempDbLogs; UserData; UserLogs' FailoverClusterIPAddresses = $mockDefaultInstance_FailoverClusterIPAddressParameter_SingleSite FailoverClusterGroup = 'SQL Server (MSSQLSERVER)' FailoverClusterNetworkName = $mockDefaultInstance_FailoverClusterNetworkName From d171eb13ed4d9017dd95e2f630b57d86faf4731d Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 17:53:12 +0100 Subject: [PATCH 03/10] Adde changes to CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f07d423ec..e6475429d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ - Properly checks for use of SQLSysAdminAccounts parameter in $PSBoundParameters. The test now also properly evaluates the setup argument for SQLSysAdminAccounts. - xSQLServerSetup should now function correctly for the InstallFailoverCluster action, and also supports cluster shared volumes. Note that the AddNode action is not currently working. - It now detects that feature Client Connectivity Tools (CONN) and Client Connectivity Backwards Compatibility Tools (BC) is installed. + - Now it can correctly determine the right cluster when only parameter InstallSQLDataDir is assigned a path (issue #401). + - Now the only mandatory path parameter is InstallSQLDataDir when installing Database Engine (issue #400). + - It now can handle mandatory parameters, and are not using wildcards to find the variables containing paths (issue #394). - Enables CodeCov.io code coverage reporting. - Added badge for CodeCov.io to README.md. - Examples From e2ad23adff5fcad00660f5a53bb28ebb20890e2c Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 22:20:49 +0100 Subject: [PATCH 04/10] Changes to xSQLServerSetup Changed the logic of how the parameters are evaluated. --- .../MSFT_xSQLServerSetup.psm1 | 54 +++++++++++-------- Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 | 5 +- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index 87f78f153..b4aa0d3e5 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -779,8 +779,7 @@ function Set-TargetResource } } - # Remove trailing "\" from paths - foreach ($var in @( + $parametersToEvaluateTrailingSlash = @( 'InstallSQLDataDir', 'SQLUserDBDir', 'SQLUserDBLogDir', @@ -791,12 +790,21 @@ function Set-TargetResource 'ASLogDir', 'ASBackupDir', 'ASTempDir', - 'ASConfigDir') + 'ASConfigDir' ) + + # Remove trailing slash ('\') from paths + foreach ($parameter in $PSBoundParameters.GetEnumerator()) { - if (Get-Variable -Name $var -ErrorAction SilentlyContinue) + $parameterName = $parameter.Key + if ($parameterName -in $parametersToEvaluateTrailingSlash) { - Set-Variable -Name $var -Value (Get-Variable -Name $var).Value.TrimEnd('\') + $parameterValue = $parameter.Value + if ($parameterValue) + { + #Write-Host $parameterValue + Set-Variable -Name $parameterName -Value $parameterValue.TrimEnd('\') + } } } @@ -824,29 +832,30 @@ function Set-TargetResource # Perform disk mapping for specific cluster installation types if ($Action -in @('CompleteFailoverCluster','InstallFailoverCluster')) { + $requiredDrive = @() - $parametersToEvaluatePathFor = @( - 'InstallSQLDataDir' - 'SQLUserDBDir' - 'SQLUserDBLogDir' - 'SQLTempDBDir' - 'SQLTempDBLogDir' - 'SQLBackupDir' + # This is also used to evaluate which cluster shard disks should be used. + $parametersToEvaluateShareDisk = @( + 'InstallSQLDataDir', + 'SQLUserDBDir', + 'SQLUserDBLogDir', + 'SQLTempDBDir', + 'SQLTempDBLogDir', + 'SQLBackupDir', + 'ASDataDir', + 'ASLogDir', + 'ASBackupDir', + 'ASTempDir', + 'ASConfigDir' ) - $requiredDrive = @() - - <# - Get a required lising of drives based on user parameters. - Using $MyInvocation.MyCommand.Parameters.GetEnumerator() instead of PSBoundParameters - to be able to get default parameters. - #> - foreach ($parameter in $MyInvocation.MyCommand.Parameters.GetEnumerator()) + # Get a required listing of drives based on parameters assigned by user. + foreach ($parameter in $PSBoundParameters.GetEnumerator()) { $parameterName = $parameter.Key - if ($parameterName -in $parametersToEvaluatePathFor) + if ($parameterName -in $parametersToEvaluateShareDisk) { - $parameterValue = Get-Variable -Name $parameterName -ValueOnly -ErrorAction SilentlyContinue + $parameterValue = $parameter.Value if ($parameterValue) { New-VerboseMessage -Message ("Found assigned parameter '{0}'. Adding path '{1}' to required cluster drives." -f $parameterName, $parameterValue) @@ -855,6 +864,7 @@ function Set-TargetResource } } + # Only keep unique paths and add a member to keep track if the path is mapped to a disk. $requiredDrive = $requiredDrive | Sort-Object -Unique | Add-Member -MemberType NoteProperty -Name IsMapped -Value $false -PassThru # Get the disk resources that are available (not assigned to a cluster role) diff --git a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 index 408986041..e5332184c 100644 --- a/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 +++ b/Tests/Unit/MSFT_xSQLServerSetup.Tests.ps1 @@ -698,9 +698,6 @@ try ) } - - - $mockGetCimInstance_MSClusterNetwork = { return @( ( @@ -3581,7 +3578,7 @@ try $setTargetResourceParameters.Remove('SQLTempDbLogDir') $setTargetResourceParameters.Remove('SQLBackupDir') - $setTargetResourceParameters['InstallSQLDataDir'] = 'E:\SQLData' + $setTargetResourceParameters['InstallSQLDataDir'] = 'E:\SQLData\' # This ends with \ to test removal of paths ending with \ $setTargetResourceParameters['SQLUserDBDir'] = 'E:\SQLData\UserDb' $setTargetResourceParameters['SQLUserDBLogDir'] = 'E:\SQLData\UserDbLogs' From 59b66cc43006745d0921a13a86de700b05ba5de4 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 22:22:29 +0100 Subject: [PATCH 05/10] Remove debug code --- DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 | 1 - 1 file changed, 1 deletion(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index b4aa0d3e5..d4d49d0a9 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -802,7 +802,6 @@ function Set-TargetResource $parameterValue = $parameter.Value if ($parameterValue) { - #Write-Host $parameterValue Set-Variable -Name $parameterName -Value $parameterValue.TrimEnd('\') } } From 3fc40b183ec8c221060483e182503a8cd1182761 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 22:42:12 +0100 Subject: [PATCH 06/10] Style changes, fixed missing descriptions --- .../MSFT_xSQLServerSetup.psm1 | 99 +++++++++++++++++-- .../MSFT_xSQLServerSetup.schema.mof | 2 +- README.md | 2 +- 3 files changed, 92 insertions(+), 11 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index d4d49d0a9..822149746 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -509,7 +509,7 @@ function Get-TargetResource Specifies the startup mode for SQL Server Browser service .PARAMETER FailoverClusterGroupName - The name of the resource group to create for the clustered SQL Server instance + The name of the resource group to create for the clustered SQL Server instance. Default is 'SQL Server (InstanceName)'. .PARAMETER FailoverClusterIPAddress Array of IP Addresses to be assigned to the clustered SQL Server instance @@ -524,139 +524,181 @@ function Set-TargetResource [CmdletBinding()] param ( + [Parameter()] [ValidateSet('Install','InstallFailoverCluster','AddNode','PrepareFailoverCluster','CompleteFailoverCluster')] [System.String] $Action = 'Install', + [Parameter()] [System.String] $SourcePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SetupCredential, + [Parameter()] [System.Management.Automation.PSCredential] $SourceCredential, + [Parameter()] [System.Boolean] $SuppressReboot, + [Parameter()] [System.Boolean] $ForceReboot, + [Parameter()] [System.String] $Features, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $InstanceName, + [Parameter()] [System.String] $InstanceID, + [Parameter()] [System.String] $ProductKey, + [Parameter()] [System.String] $UpdateEnabled, + [Parameter()] [System.String] $UpdateSource, + [Parameter()] [System.String] $SQMReporting, + [Parameter()] [System.String] $ErrorReporting, + [Parameter()] [System.String] $InstallSharedDir, + [Parameter()] [System.String] $InstallSharedWOWDir, + [Parameter()] [System.String] $InstanceDir, + [Parameter()] [System.Management.Automation.PSCredential] $SQLSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $AgtSvcAccount, + [Parameter()] [System.String] $SQLCollation, + [Parameter()] [System.String[]] $SQLSysAdminAccounts, + [Parameter()] [System.String] $SecurityMode, + [Parameter()] [System.Management.Automation.PSCredential] $SAPwd, + [Parameter()] [System.String] $InstallSQLDataDir, + [Parameter()] [System.String] $SQLUserDBDir, + [Parameter()] [System.String] $SQLUserDBLogDir, + [Parameter()] [System.String] $SQLTempDBDir, + [Parameter()] [System.String] $SQLTempDBLogDir, + [Parameter()] [System.String] $SQLBackupDir, + [Parameter()] [System.Management.Automation.PSCredential] $FTSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $RSSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $ASSvcAccount, + [Parameter()] [System.String] $ASCollation, + [Parameter()] [System.String[]] $ASSysAdminAccounts, + [Parameter()] [System.String] $ASDataDir, + [Parameter()] [System.String] $ASLogDir, + [Parameter()] [System.String] $ASBackupDir, + [Parameter()] [System.String] $ASTempDir, + [Parameter()] [System.String] $ASConfigDir, + [Parameter()] [System.Management.Automation.PSCredential] $ISSvcAccount, + [Parameter()] [System.String] [ValidateSet('Automatic', 'Disabled', 'Manual')] $BrowserSvcStartupType, + [Parameter()] [System.String] $FailoverClusterGroupName = "SQL Server ($InstanceName)", + [Parameter()] [System.String[]] $FailoverClusterIPAddress, + [Parameter()] [System.String] $FailoverClusterNetworkName ) @@ -1355,7 +1397,7 @@ function Set-TargetResource Specifies the startup mode for SQL Server Browser service .PARAMETER FailoverClusterGroupName - The name of the resource group to create for the clustered SQL Server instance + The name of the resource group to create for the clustered SQL Server instance. Default is 'SQL Server (InstanceName)'. .PARAMETER FailoverClusterIPAddress Array of IP Addresses to be assigned to the clustered SQL Server instance @@ -1369,142 +1411,181 @@ function Test-TargetResource [OutputType([System.Boolean])] param ( + [Parameter()] [ValidateSet('Install','InstallFailoverCluster','AddNode','PrepareFailoverCluster','CompleteFailoverCluster')] [System.String] $Action = 'Install', + [Parameter()] [System.String] $SourcePath, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.Management.Automation.PSCredential] $SetupCredential, + [Parameter()] [System.Management.Automation.PSCredential] $SourceCredential, + [Parameter()] [System.Boolean] $SuppressReboot, + [Parameter()] [System.Boolean] $ForceReboot, + [Parameter()] [System.String] $Features, - [parameter(Mandatory = $true)] + [Parameter(Mandatory = $true)] [System.String] $InstanceName, + [Parameter()] [System.String] $InstanceID, + [Parameter()] [System.String] $ProductKey, + [Parameter()] [System.String] $UpdateEnabled, + [Parameter()] [System.String] $UpdateSource, + [Parameter()] [System.String] $SQMReporting, + [Parameter()] [System.String] $ErrorReporting, + [Parameter()] [System.String] $InstallSharedDir, + [Parameter()] [System.String] $InstallSharedWOWDir, + [Parameter()] [System.String] $InstanceDir, + [Parameter()] [System.Management.Automation.PSCredential] $SQLSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $AgtSvcAccount, + [Parameter()] [System.String] $SQLCollation, + [Parameter()] [System.String[]] $SQLSysAdminAccounts, + [Parameter()] [System.String] $SecurityMode, + [Parameter()] [System.Management.Automation.PSCredential] $SAPwd, + [Parameter()] [System.String] $InstallSQLDataDir, + [Parameter()] [System.String] $SQLUserDBDir, + [Parameter()] [System.String] $SQLUserDBLogDir, + [Parameter()] [System.String] $SQLTempDBDir, + [Parameter()] [System.String] $SQLTempDBLogDir, + [Parameter()] [System.String] $SQLBackupDir, + [Parameter()] [System.Management.Automation.PSCredential] $FTSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $RSSvcAccount, + [Parameter()] [System.Management.Automation.PSCredential] $ASSvcAccount, + [Parameter()] [System.String] $ASCollation, + [Parameter()] [System.String[]] $ASSysAdminAccounts, + [Parameter()] [System.String] $ASDataDir, + [Parameter()] [System.String] $ASLogDir, + [Parameter()] [System.String] $ASBackupDir, + [Parameter()] [System.String] $ASTempDir, + [Parameter()] [System.String] $ASConfigDir, + [Parameter()] [System.Management.Automation.PSCredential] $ISSvcAccount, + [Parameter()] [System.String] [ValidateSet('Automatic', 'Disabled', 'Manual')] $BrowserSvcStartupType, - [Parameter(ParameterSetName = 'ClusterInstall')] + [Parameter()] [System.String] $FailoverClusterGroupName = "SQL Server ($InstanceName)", - [Parameter(ParameterSetName = 'ClusterInstall')] + [Parameter()] [System.String[]] $FailoverClusterIPAddress, - [Parameter(ParameterSetName = 'ClusterInstall')] + [Parameter()] [System.String] $FailoverClusterNetworkName ) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.schema.mof b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.schema.mof index fa3e30b52..f30fd5590 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.schema.mof +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.schema.mof @@ -48,7 +48,7 @@ class MSFT_xSQLServerSetup : OMI_BaseResource [Write, EmbeddedInstance("MSFT_Credential"), Description("Service account for Integration Services service.")] String ISSvcAccount; [Read, Description("Output username for the Integration Services service.")] String ISSvcAccountUsername; [Write, Description("Specifies the startup mode for SQL Server Browser service."), ValueMap{"Automatic", "Disabled", "Manual"}, Values{"Automatic", "Disabled", "Manual"}] String BrowserSvcStartupType; - [Write, Description("The name of the resource group to create for the clustered SQL Server instance.")] String FailoverClusterGroupName; + [Write, Description("The name of the resource group to create for the clustered SQL Server instance. Default is 'SQL Server (InstanceName)'.")] String FailoverClusterGroupName; [Write, Description("Array of IP Addresses to be assigned to the clustered SQL Server instance.")] String FailoverClusterIPAddress[]; [Write, Description("Host name to be assigend to the clustered SQL Server instance.")] String FailoverClusterNetworkName; }; diff --git a/README.md b/README.md index 5ca5368a1..56c52ba36 100644 --- a/README.md +++ b/README.md @@ -907,7 +907,7 @@ Installs SQL Server on the target node. * **[String] ASConfigDir** _(Write)_: Path for Analysis Services config. * **[PSCredential] ISSvcAccount** _(Write)_: Service account for Integration Services service. * **[String] BrowserSvcStartupType** _(Write)_: Specifies the startup mode for SQL Server Browser service. { Automatic | Disabled | 'Manual' } -* **[String] FailoverClusterGroupName** _(Write)_: The name of the resource group to create for the clustered SQL Server instance. Defaults to 'SQL Server (_InstanceName_)'. +* **[String] FailoverClusterGroupName** _(Write)_: The name of the resource group to create for the clustered SQL Server instance. Default is 'SQL Server (_InstanceName_)'. * **[String[]]FailoverClusterIPAddress** _(Write)_: Array of IP Addresses to be assigned to the clustered SQL Server instance. IP addresses must be in [dotted-decimal notation](https://en.wikipedia.org/wiki/Dot-decimal_notation), for example ````10.0.0.100````. If no IP address is specified, uses 'DEFAULT' for this setup parameter. * **[String] FailoverClusterNetworkName** _(Write)_: Host name to be assigned to the clustered SQL Server instance. From cc9b4f5446388d51df37bb425a3b9b43b3861bfb Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 23:04:15 +0100 Subject: [PATCH 07/10] Changed logic once again --- .../MSFT_xSQLServerSetup.psm1 | 64 +++++++++---------- 1 file changed, 31 insertions(+), 33 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index 822149746..53052436b 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -714,6 +714,33 @@ function Set-TargetResource $InstanceName = $InstanceName.ToUpper() + $parametersToEvaluateTrailingSlash = @( + 'InstallSQLDataDir', + 'SQLUserDBDir', + 'SQLUserDBLogDir', + 'SQLTempDBDir', + 'SQLTempDBLogDir', + 'SQLBackupDir', + 'ASDataDir', + 'ASLogDir', + 'ASBackupDir', + 'ASTempDir', + 'ASConfigDir' + ) + + # Remove trailing slash ('\') from paths + foreach ($parameterName in $parametersToEvaluateTrailingSlash) + { + if ($PSBoundParameters.ContainsKey($parameterName)) + { + $parameterValue = Get-Variable -Name $parameterName -ValueOnly + if ($parameterValue) + { + Set-Variable -Name $parameterName -Value $parameterValue.TrimEnd('\') + } + } + } + $SourcePath = [Environment]::ExpandEnvironmentVariables($SourcePath) if ($SourceCredential) @@ -821,34 +848,6 @@ function Set-TargetResource } } - $parametersToEvaluateTrailingSlash = @( - 'InstallSQLDataDir', - 'SQLUserDBDir', - 'SQLUserDBLogDir', - 'SQLTempDBDir', - 'SQLTempDBLogDir', - 'SQLBackupDir', - 'ASDataDir', - 'ASLogDir', - 'ASBackupDir', - 'ASTempDir', - 'ASConfigDir' - ) - - # Remove trailing slash ('\') from paths - foreach ($parameter in $PSBoundParameters.GetEnumerator()) - { - $parameterName = $parameter.Key - if ($parameterName -in $parametersToEvaluateTrailingSlash) - { - $parameterValue = $parameter.Value - if ($parameterValue) - { - Set-Variable -Name $parameterName -Value $parameterValue.TrimEnd('\') - } - } - } - $setupArguments = @{} if ($Action -in @('PrepareFailoverCluster','CompleteFailoverCluster','InstallFailoverCluster')) @@ -891,15 +890,14 @@ function Set-TargetResource ) # Get a required listing of drives based on parameters assigned by user. - foreach ($parameter in $PSBoundParameters.GetEnumerator()) + foreach ($parameterName in $parametersToEvaluateShareDisk) { - $parameterName = $parameter.Key - if ($parameterName -in $parametersToEvaluateShareDisk) + if ($PSBoundParameters.ContainsKey($parameterName)) { - $parameterValue = $parameter.Value + $parameterValue = Get-Variable -Name $parameterName -ValueOnly if ($parameterValue) { - New-VerboseMessage -Message ("Found assigned parameter '{0}'. Adding path '{1}' to required cluster drives." -f $parameterName, $parameterValue) + New-VerboseMessage -Message ("Found assigned parameter '{0}'. Adding path '{1}' to list of paths that required cluster drive." -f $parameterName, $parameterValue) $requiredDrive += $parameterValue } } From aadb21bc181335b504c8c7b1a829434f54958777 Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sat, 25 Feb 2017 23:11:36 +0100 Subject: [PATCH 08/10] Removed to much in style cleanup --- DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 index 53052436b..295e104e6 100644 --- a/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 +++ b/DSCResources/MSFT_xSQLServerSetup/MSFT_xSQLServerSetup.psm1 @@ -1575,15 +1575,15 @@ function Test-TargetResource [ValidateSet('Automatic', 'Disabled', 'Manual')] $BrowserSvcStartupType, - [Parameter()] + [Parameter(ParameterSetName = 'ClusterInstall')] [System.String] $FailoverClusterGroupName = "SQL Server ($InstanceName)", - [Parameter()] + [Parameter(ParameterSetName = 'ClusterInstall')] [System.String[]] $FailoverClusterIPAddress, - [Parameter()] + [Parameter(ParameterSetName = 'ClusterInstall')] [System.String] $FailoverClusterNetworkName ) From 7605400487d9cde87d6d5b8c235496ca24f271ae Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 26 Feb 2017 09:22:39 +0100 Subject: [PATCH 09/10] Changed README.md after review. --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 56c52ba36..24d30c82d 100644 --- a/README.md +++ b/README.md @@ -854,14 +854,17 @@ Installs SQL Server on the target node. #### Requirements * Target machine must be running Windows Server 2008 R2 or later. -* For configurations that utilize the 'InstallFailoverCluster' action, the following parameters are required (beyond those required for the standalone installation) - * InstanceName (can be MSSQLSERVER if you want to install a default clustered instance) +* For configurations that utilize the 'InstallFailoverCluster' action, the following parameters are required (beyond those required for the standalone installation). See the article [Install SQL Server from the Command Prompt](https://msdn.microsoft.com/en-us/library/ms144259.aspx) under the section [Failover Cluster Parameters](https://msdn.microsoft.com/en-us/library/ms144259.aspx#Anchor_8) for more information. + * InstanceName (can be MSSQLSERVER if you want to install a default clustered instance). * FailoverClusterNetworkName - * When installation SQL Server database engine: + * FailoverClusterIPAddress + * _When installing Database Engine._ * InstallSQLDataDir * AgtSvcAccount * SQLSvcAccount - * When installing SQL Analysis Services + * SQLSysAdminAccounts + * _When installing Analysis Services._ + * ASSysAdminAccounts * AsSvcAccount #### Parameters From dbcaabed2502dfff3b10a36d571f2c11e73fe3ee Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Sun, 26 Feb 2017 09:26:18 +0100 Subject: [PATCH 10/10] Added new requirment to xWaitForAvailabilityGroup --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 24d30c82d..638ccb1ce 100644 --- a/README.md +++ b/README.md @@ -934,6 +934,7 @@ No description. #### Requirements * Target machine must be running Windows Server 2008 R2 or later. +* Target machine must be running SQL Server Database Engine 2012 or later. #### Parameters