diff --git a/CHANGELOG.md b/CHANGELOG.md index d375dfc2c..4ad0b8ba1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- SqlRole + - Major overhaul of resource + - BREAKING CHANGE: Removed decision making from get-TargetResource; this prevented a simple solution for + issue #550. it now just tels if a role exists or not. And what members are in that + role. MembersToInclude and MembersToExclude now always return $null + - Added sanitize function (Get-CorrectedMemberParameters) to make it so for the + sysadmin role SA does not get altered. ([issue #550](https://github.com/dsccommunity/SqlServerDsc/issues/550)) + - added lots of tests. + ### Added - SqlEndpoint diff --git a/source/DSCResources/DSC_SqlRole/DSC_SqlRole.psm1 b/source/DSCResources/DSC_SqlRole/DSC_SqlRole.psm1 index c20944e11..7a3db9e62 100644 --- a/source/DSCResources/DSC_SqlRole/DSC_SqlRole.psm1 +++ b/source/DSCResources/DSC_SqlRole/DSC_SqlRole.psm1 @@ -10,23 +10,22 @@ $script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' .SYNOPSIS This function gets the sql server role properties. - .PARAMETER Members - The members the server role should have. - - .PARAMETER MembersToInclude - The members the server role should include. + .PARAMETER ServerName + The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. - .PARAMETER MembersToExclude - The members the server role should exclude. + .PARAMETER InstanceName + The name of the SQL instance to be configured. .PARAMETER ServerRoleName The name of server role to be created or dropped. - .PARAMETER ServerName - The host name of the SQL Server to be configured. Default value is $env:COMPUTERNAME. + .Notes + Because the return of this function will always be the actual members in the role, + and not the desired members in a role, there is no point in returning $MembersToInclude and exclude. + You now get "present" if the role exists, and when it exists, you get the current members in that role. - .PARAMETER InstanceName - The name of the SQL instance to be configured. + The way it was: if a role does not exists, you still get $membersToInclude And $membersToExclude. + To me that seems like strange behavior. #> function Get-TargetResource { @@ -35,35 +34,24 @@ function Get-TargetResource param ( [Parameter()] - [System.String[]] - $Members, - - [Parameter()] - [System.String[]] - $MembersToInclude, - - [Parameter()] - [System.String[]] - $MembersToExclude, - - [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] - $ServerRoleName, + $ServerName = $env:COMPUTERNAME, - [Parameter()] + [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] - $ServerName = $env:COMPUTERNAME, + $InstanceName, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [System.String] - $InstanceName + $ServerRoleName ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - $ensure = 'Present' + $ensure = 'Absent' + $membersInRole = $null if ($sqlServerObject) { @@ -77,6 +65,7 @@ function Get-TargetResource try { [System.String[]] $membersInRole = $sqlServerRoleObject.EnumMemberNames() + $ensure = 'Present' } catch { @@ -85,76 +74,18 @@ function Get-TargetResource New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } - - if ($Members) - { - if ($MembersToInclude -or $MembersToExclude) - { - $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - New-InvalidOperationException -Message $errorMessage - } - - if ( $null -ne (Compare-Object -ReferenceObject $membersInRole -DifferenceObject $Members)) - { - Write-Verbose -Message ( - $script:localizedData.DesiredMembersNotPresent ` - -f $ServerRoleName - ) - - $ensure = 'Absent' - } - } - else - { - if ($MembersToInclude) - { - foreach ($memberToInclude in $MembersToInclude) - { - if ($membersInRole -notcontains $memberToInclude) - { - Write-Verbose -Message ( - $script:localizedData.MemberNotPresent ` - -f $ServerRoleName, $memberToInclude - ) - - $ensure = 'Absent' - } - } - } - - if ($MembersToExclude) - { - foreach ($memberToExclude in $MembersToExclude) - { - if ($membersInRole -contains $memberToExclude) - { - Write-Verbose -Message ( - $script:localizedData.MemberPresent ` - -f $ServerRoleName, $memberToExclude - ) - - $ensure = 'Absent' - } - } - } - } - } - else - { - $ensure = 'Absent' } } - $returnValue = @{ - Ensure = $ensure - Members = $membersInRole - MembersToInclude = $MembersToInclude - MembersToExclude = $MembersToExclude - ServerRoleName = $ServerRoleName - ServerName = $ServerName - InstanceName = $InstanceName + return @{ + ServerRoleName = $ServerRoleName + Ensure = $ensure + ServerName = $ServerName + InstanceName = $InstanceName + Members = $membersInRole + MembersToInclude = $null + MembersToExclude = $null } - $returnValue } <# @@ -221,6 +152,18 @@ function Set-TargetResource $InstanceName ) + $assertBoundParameterParameters = @{ + BoundParameterList = $PSBoundParameters + MutuallyExclusiveList1 = @( + 'Members' + ) + MutuallyExclusiveList2 = @( + 'MembersToExclude', 'MembersToInclude' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) @@ -283,19 +226,22 @@ function Set-TargetResource } } + $originalParameters = @{ + ServerRoleName = $ServerRoleName + Members = $Members + MembersToInclude = $MembersToInclude + MembersToExclude = $MembersToExclude + } + + $correctedParameters = Get-CorrectedMemberParameters @originalParameters + if ($Members) { - if ($MembersToInclude -or $MembersToExclude) - { - $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - New-InvalidOperationException -Message $errorMessage - } - $memberNamesInRoleObject = $sqlServerObject.Roles[$ServerRoleName].EnumMemberNames() foreach ($memberName in $memberNamesInRoleObject) { - if ($Members -notcontains $memberName) + if ($correctedParameters.Members -notcontains $memberName) { Remove-SqlDscServerRoleMember -SqlServerObject $sqlServerObject ` -SecurityPrincipal $memberName ` @@ -303,7 +249,7 @@ function Set-TargetResource } } - foreach ($memberToAdd in $Members) + foreach ($memberToAdd in $correctedParameters.Members) { if ($memberNamesInRoleObject -notcontains $memberToAdd) { @@ -319,7 +265,7 @@ function Set-TargetResource { $memberNamesInRoleObject = $sqlServerObject.Roles[$ServerRoleName].EnumMemberNames() - foreach ($memberToInclude in $MembersToInclude) + foreach ($memberToInclude in $correctedParameters.MembersToInclude) { if ($memberNamesInRoleObject -notcontains $memberToInclude) { @@ -334,7 +280,7 @@ function Set-TargetResource { $memberNamesInRoleObject = $sqlServerObject.Roles[$ServerRoleName].EnumMemberNames() - foreach ($memberToExclude in $MembersToExclude) + foreach ($memberToExclude in $correctedParameters.MembersToExclude) { if ($memberNamesInRoleObject -contains $memberToExclude) { @@ -420,13 +366,31 @@ function Test-TargetResource -f $ServerRoleName ) + $assertBoundParameterParameters = @{ + BoundParameterList = $PSBoundParameters + MutuallyExclusiveList1 = @( + 'Members' + ) + MutuallyExclusiveList2 = @( + 'MembersToExclude', 'MembersToInclude' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + + $originalParameters = @{ + ServerRoleName = $ServerRoleName + Members = $Members + MembersToInclude = $MembersToInclude + MembersToExclude = $MembersToExclude + } + + $correctedParameters = Get-CorrectedMemberParameters @originalParameters + $getTargetResourceParameters = @{ - InstanceName = $PSBoundParameters.InstanceName + InstanceName = $InstanceName ServerName = $ServerName - ServerRoleName = $PSBoundParameters.ServerRoleName - Members = $PSBoundParameters.Members - MembersToInclude = $PSBoundParameters.MembersToInclude - MembersToExclude = $PSBoundParameters.MembersToExclude + ServerRoleName = $ServerRoleName } $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters @@ -458,6 +422,56 @@ function Test-TargetResource $isServerRoleInDesiredState = $false } + else + { + if ($Members) + { + if ( $null -ne (Compare-Object -ReferenceObject $getTargetResourceResult.Members -DifferenceObject $correctedParameters.Members)) + { + Write-Verbose -Message ( + $script:localizedData.DesiredMembersNotPresent ` + -f $ServerRoleName + ) + + $isServerRoleInDesiredState = $false + } + } + else + { + if ($MembersToInclude) + { + foreach ($memberToInclude in $correctedParameters.MembersToInclude) + { + if ($getTargetResourceResult.Members -notcontains $memberToInclude) + { + Write-Verbose -Message ( + $script:localizedData.MemberNotPresent ` + -f $ServerRoleName, $memberToInclude + ) + + $isServerRoleInDesiredState = $false + } + } + + } + + if ($MembersToExclude) + { + foreach ($memberToExclude in $correctedParameters.MembersToExclude) + { + if ($getTargetResourceResult.Members -contains $memberToExclude) + { + Write-Verbose -Message ( + $script:localizedData.MemberPresent ` + -f $ServerRoleName, $memberToExclude + ) + + $isServerRoleInDesiredState = $false + } + } + } + } + } } } @@ -609,12 +623,75 @@ function Test-SqlSecurityPrincipal # Principal is neither a Login nor a Server role, raise exception New-ObjectNotFoundException -Message $errorMessage - - return $false } } return $true } +<# + .SYNOPSIS + This function sanitizes the parameters + If Members is filled, MembersToInclude and MembersToExclude should be empty. + If ServerRoleName is sysadmin, make sure we dont try to delete SA from it. + + .PARAMETER Members + The members the server role should have. + + .PARAMETER MembersToInclude + The members the server role should include. + + .PARAMETER MembersToExclude + The members the server role should exclude. + + .PARAMETER ServerRoleName + The name of server role to be created or dropped. +#> +function Get-CorrectedMemberParameters +{ + param + ( + [Parameter()] + [System.String[]] + $Members, + + [Parameter()] + [System.String[]] + $MembersToInclude, + + [Parameter()] + [System.String[]] + $MembersToExclude, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.String] + $ServerRoleName + ) + + if ($ServerRoleName -eq 'sysadmin') + { + if ($Members) + { + if ($Members -notcontains 'SA') + { + $Members += 'SA' + } + } + else + { + if ($MembersToExclude -contains 'SA') + { + $MembersToExclude = $MembersToExclude -ne 'SA' + } + } + } + + return @{ + Members = [System.String[]]$Members + MembersToInclude = [System.String[]]$MembersToInclude + MembersToExclude = [System.String[]]$MembersToExclude + } +} + Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_SqlRole/README.md b/source/DSCResources/DSC_SqlRole/README.md index 2c2401fab..1c312b26b 100644 --- a/source/DSCResources/DSC_SqlRole/README.md +++ b/source/DSCResources/DSC_SqlRole/README.md @@ -5,6 +5,10 @@ The `SqlRole` DSC resource is used to create a server role, when is set to `'Absent'`. The resource also manages members in both built-in and user created server roles. +When the target role is sysadmin the DSC resource will prevent the user +'sa' from being removed. This is done to keep the DSC resource from +throwing an error since SQL Server does not allow this user to be removed. + For more information about server roles, please read the below articles. * [Create a Server Role](https://msdn.microsoft.com/en-us/library/ee677627.aspx) diff --git a/source/DSCResources/DSC_SqlRole/en-US/DSC_SqlRole.strings.psd1 b/source/DSCResources/DSC_SqlRole/en-US/DSC_SqlRole.strings.psd1 index ada6aa051..78fcff4b0 100644 --- a/source/DSCResources/DSC_SqlRole/en-US/DSC_SqlRole.strings.psd1 +++ b/source/DSCResources/DSC_SqlRole/en-US/DSC_SqlRole.strings.psd1 @@ -5,7 +5,6 @@ ConvertFrom-StringData @' SetProperties = Setting properties of the SQL Server role '{0}'. TestProperties = Testing properties of the SQL Server role '{0}'. EnumMemberNamesServerRoleGetError = Failed to enumerate members of the server role named '{2}' on '{0}\\{1}'. - MembersToIncludeAndExcludeParamMustBeNull = The parameter MembersToInclude and/or MembersToExclude must not be set, or be set to $null, when parameter Members are used. DropServerRoleSetError = Failed to drop the server role named '{2}' on '{0}\\{1}'. CreateServerRoleSetError = Failed to create the server role named '{2}' on '{0}\\{1}'. AddMemberServerRoleSetError = Failed to add member '{3}' to the server role named '{2}' on '{0}\\{1}'. diff --git a/tests/Integration/DSC_SqlRole.Integration.Tests.ps1 b/tests/Integration/DSC_SqlRole.Integration.Tests.ps1 index 045dddb1d..5e20d4da2 100644 --- a/tests/Integration/DSC_SqlRole.Integration.Tests.ps1 +++ b/tests/Integration/DSC_SqlRole.Integration.Tests.ps1 @@ -32,30 +32,33 @@ try Describe "$($script:dscResourceName)_Integration" { BeforeAll { $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + $configurationName = "$($script:dscResourceName)_AddRole1_Config" } - $configurationName = "$($script:dscResourceName)_AddRole1_Config" - Context ('When using configuration {0}' -f $configurationName) { + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -76,37 +79,41 @@ try $resourceCurrentState.Ensure | Should -Be 'Present' $resourceCurrentState.ServerRoleName | Should -Be $ConfigurationData.AllNodes.Role1Name $resourceCurrentState.Members | Should -Be $ConfigurationData.AllNodes.User4Name - $resourceCurrentState.MembersToInclude | Should -Be $ConfigurationData.AllNodes.User4Name + $resourceCurrentState.MembersToInclude | Should -BeNullOrEmpty $resourceCurrentState.MembersToExclude | Should -BeNullOrEmpty } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_AddRole2_Config" Context ('When using configuration {0}' -f $configurationName) { + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -123,7 +130,6 @@ try -and $_.ResourceId -eq $resourceId } - $resourceCurrentState.Ensure | Should -Be 'Present' $resourceCurrentState.ServerRoleName | Should -Be $ConfigurationData.AllNodes.Role2Name $resourceCurrentState.Members | Should -BeNullOrEmpty @@ -132,32 +138,36 @@ try } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_AddRole3_Config" - Context ('When using configuration {0}' -f $configurationName) { + Context ('When using configuration {0}' -f $configurationName){ + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -186,32 +196,36 @@ try } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_Role1_ChangeMembers_Config" Context ('When using configuration {0}' -f $configurationName) { + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -240,32 +254,36 @@ try } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_Role2_AddMembers_Config" Context ('When using configuration {0}' -f $configurationName) { + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -282,7 +300,6 @@ try -and $_.ResourceId -eq $resourceId } - $resourceCurrentState.Ensure | Should -Be 'Present' $resourceCurrentState.ServerRoleName | Should -Be $ConfigurationData.AllNodes.Role2Name $resourceCurrentState.Members | Should -Be @( @@ -290,41 +307,32 @@ try $ConfigurationData.AllNodes.User2Name $ConfigurationData.AllNodes.User4Name ) - $resourceCurrentState.MembersToInclude | Should -Be @( - $ConfigurationData.AllNodes.User1Name - $ConfigurationData.AllNodes.User2Name - $ConfigurationData.AllNodes.User4Name - ) + $resourceCurrentState.MembersToInclude | Should -BeNullOrEmpty $resourceCurrentState.MembersToExclude | Should -BeNullOrEmpty } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_Role2_RemoveMembers_Config" Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing' { - { + BeforeAll { $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + } + It 'Should compile and apply the MOF without throwing' { + { & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -341,44 +349,44 @@ try -and $_.ResourceId -eq $resourceId } - $resourceCurrentState.Ensure | Should -Be 'Present' $resourceCurrentState.ServerRoleName | Should -Be $ConfigurationData.AllNodes.Role2Name $resourceCurrentState.Members | Should -Be $ConfigurationData.AllNodes.User4Name $resourceCurrentState.MembersToInclude | Should -BeNullOrEmpty - $resourceCurrentState.MembersToExclude | Should -Be @( - $ConfigurationData.AllNodes.User1Name - $ConfigurationData.AllNodes.User2Name - ) + $resourceCurrentState.MembersToExclude | Should -BeNullOrEmpty } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_RemoveRole3_Config" Context ('When using configuration {0}' -f $configurationName) { + BeforeAll { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + } + It 'Should compile and apply the MOF without throwing' { { - $configurationParameters = @{ - OutputPath = $TestDrive - # The variable $ConfigurationData was dot-sourced above. - ConfigurationData = $ConfigurationData - } - & $configurationName @configurationParameters + } | Should -Not -Throw - $startDscConfigurationParameters = @{ - Path = $TestDrive - ComputerName = 'localhost' - Wait = $true - Verbose = $true - Force = $true - ErrorAction = 'Stop' - } - + { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw } @@ -395,7 +403,6 @@ try -and $_.ResourceId -eq $resourceId } - $resourceCurrentState.Ensure | Should -Be 'Absent' $resourceCurrentState.ServerRoleName | Should -Be $ConfigurationData.AllNodes.Role3Name $resourceCurrentState.Members | Should -BeNullOrEmpty @@ -404,23 +411,18 @@ try } It 'Should return $true when Test-DscConfiguration is run' { - Test-DscConfiguration -Verbose | Should -Be 'True' + Test-DscConfiguration -Verbose | Should -BeTrue } } $configurationName = "$($script:dscResourceName)_AddNestedRole_Config" Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing an exception' { + BeforeAll { $configurationParameters = @{ OutputPath = $TestDrive ConfigurationData = $ConfigurationData } - - { & $configurationName @configurationParameters } | Should -Not -Throw - } - - It 'Should apply the configuration successfully' { $startDscConfigurationParameters = @{ Path = $TestDrive ComputerName = 'localhost' @@ -429,8 +431,16 @@ try Force = $true ErrorAction = 'Stop' } + } - { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw + It 'Should compile and apply the MOF without throwing' { + { + & $configurationName @configurationParameters + } | Should -Not -Throw + + { + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } It 'Should be able to call Get-DscConfiguration without throwing an exception' { @@ -465,7 +475,7 @@ try $currentState.Ensure | Should -Be 'Present' $currentState.Members | Should -Be @($testMemberName) - $currentState.MembersToInclude | Should -Be @($testMemberName) + $currentState.MembersToInclude | Should -BeNullOrEmpty $currentState.MembersToExclude | Should -BeNullOrEmpty } } @@ -473,16 +483,12 @@ try $configurationName = "$($script:dscResourceName)_RemoveNestedRole_Config" Context ('When using configuration {0}' -f $configurationName) { - It 'Should compile and apply the MOF without throwing an exception' { + BeforeAll { $configurationParameters = @{ OutputPath = $TestDrive ConfigurationData = $ConfigurationData } - { & $configurationName @configurationParameters } | Should -Not -Throw - } - - It 'Should apply the configuration successfully' { $startDscConfigurationParameters = @{ Path = $TestDrive ComputerName = 'localhost' @@ -491,13 +497,22 @@ try Force = $true ErrorAction = 'Stop' } + } + + It 'Should compile and apply the MOF without throwing' { + { + & $configurationName @configurationParameters + } | Should -Not -Throw - { Start-DscConfiguration @startDscConfigurationParameters } | Should -Not -Throw + { + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw } It 'Should be able to call Get-DscConfiguration without throwing an exception' { - { $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop } | - Should -Not -Throw + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw } It "Should have set the resource and all values should match for $($ConfigurationData.AllNodes.Role5Name)." { @@ -512,7 +527,7 @@ try $currentState.Ensure | Should -Be 'Present' $currentstate.Members | Should -BeNullOrEmpty $currentState.MembersToInclude | Should -BeNullOrEmpty - $currentState.MembersToExclude | Should -Be $testMemberName + $currentState.MembersToExclude | Should -BeNullOrEmpty } } } diff --git a/tests/Unit/DSC_SqlRole.Tests.ps1 b/tests/Unit/DSC_SqlRole.Tests.ps1 index 3749dc8d7..b84bdcb32 100644 --- a/tests/Unit/DSC_SqlRole.Tests.ps1 +++ b/tests/Unit/DSC_SqlRole.Tests.ps1 @@ -50,10 +50,17 @@ try $mockSqlServerLoginTwo = 'CONTOSO\Kelly' $mockSqlServerLoginThree = 'CONTOSO\Lucy' $mockSqlServerLoginFour = 'CONTOSO\Steve' + $mockSqlServerRoleSysAdmin = 'sysadmin' + $mockSqlServerSA = 'SA' $mockEnumMemberNames = @( $mockSqlServerLoginOne, $mockSqlServerLoginTwo ) + $mockEnumMemberNamesSysAdmin = @( + $mockSqlServerLoginOne, + $mockSqlServerLoginTwo, + $mockSqlServerSA + ) $mockSecurityPrincipals = @( $mockSqlServerLoginOne $mockSqlServerLoginTwo @@ -61,6 +68,14 @@ try $mockSqlServerLoginFour $mockSqlServerChildRole ) + $mockSecurityPrincipalsSysAdmin = @( + $mockSqlServerLoginOne + $mockSqlServerLoginTwo + $mockSqlServerLoginThree + $mockSqlServerLoginFour + $mockSqlServerChildRole + $mockSqlServerSA + ) $mockSqlServerLoginType = 'WindowsUser' $mockExpectedServerRoleToDrop = 'ServerRoleToDrop' $mockPrincipalsAsArrays = $false @@ -228,398 +243,86 @@ try } Context 'When the system is in the desired state and ensure is set to Absent' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = 'UnknownRoleName' + BeforeAll { + $testParameters = $mockDefaultParameters + $testParameters += @{ + ServerRoleName = 'UnknownRoleName' + } + + $result = Get-TargetResource @testParameters } It 'Should return the state as absent when the role does not exist' { - $result = Get-TargetResource @testParameters $result.Ensure | Should -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } It 'Should return the members as null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + $result.membersInRole | Should -BeNullOrEmpty } It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters $result.ServerName | Should -Be $testParameters.ServerName $result.InstanceName | Should -Be $testParameters.InstanceName $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When the system is not in the desired state and ensure is set to Absent' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - } - - It 'Should not return the state as absent when the role exist' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Not -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the members as not null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Not -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - # Regression test for issue #790 - It 'Should return the members as string array' { - $result = Get-TargetResource @testParameters - ($result.Members -is [System.String[]]) | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } - Context 'When passing values to parameters and throwing with EnumMemberNames method' { - It 'Should throw the correct error' { - $mockInvalidOperationForEnumMethod = $true + Context 'When the system is not in the desired state and ensure is set to Absent' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ ServerRoleName = $mockSqlServerRole } - $errorMessage = $script:localizedData.EnumMemberNamesServerRoleGetError ` - -f $mockServerName, $mockInstanceName, $mockSqlServerRole - - { Get-TargetResource @testParameters } | Should -Throw $errorMessage - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context - } - } - - Context 'When the system is in the desired state, parameter Members is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - Members = $mockEnumMemberNames - } - - It 'Should return the state as present when the members are correct' { $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Present' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the members as not null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Be $testParameters.Members - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - # Regression test for issue #790 - It 'Should return the members as string array' { - $result = Get-TargetResource @testParameters - ($result.Members -is [System.String[]]) | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } - } - - Context 'When the system is in the desired state, parameter MembersToInclude is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToInclude = $mockSqlServerLoginTwo - } - - It 'Should return the state as present when the correct members exist' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Present' - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should not return the state as absent when the role exist' { + $result.Ensure | Should -Not -Be 'Absent' } It 'Should return the members as not null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Not -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + $result.Members | Should -Not -BeNullOrEmpty } # Regression test for issue #790 It 'Should return the members as string array' { - $result = Get-TargetResource @testParameters - ($result.Members -is [System.String[]]) | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + ($result.Members -is [System.String[]]) | Should -BeTrue } It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters $result.ServerName | Should -Be $testParameters.ServerName $result.InstanceName | Should -Be $testParameters.InstanceName $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - $result.MembersToInclude | Should -Be $testParameters.MembersToInclude - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When the system is in the desired state, parameter MembersToExclude is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToExclude = $mockSqlServerLoginThree - } - - It 'Should return the state as present when the members does not exist' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Present' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It } - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - $result.MembersToExclude | Should -Be $testParameters.MembersToExclude - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } - Context 'When the system is not in the desired state, parameter MembersToInclude is assigned a value, parameter Members is assigned a value, and ensure is set to Present' { - It 'Should throw the correct error' { + Context 'When passing values to parameters and throwing with EnumMemberNames method' { + BeforeAll { + $mockInvalidOperationForEnumMethod = $true $testParameters = $mockDefaultParameters $testParameters += @{ - ServerRoleName = $mockSqlServerRole - Members = $mockEnumMemberNames - MembersToInclude = $mockSqlServerLoginThree + ServerRoleName = $mockSqlServerRole } - $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - - { Get-TargetResource @testParameters } | Should -Throw $errorMessage - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context + $errorMessage = $script:localizedData.EnumMemberNamesServerRoleGetError ` + -f $mockServerName, $mockInstanceName, $mockSqlServerRole } - } - - Context 'When the system is not in the desired state, parameter MembersToExclude is assigned a value, parameter Members is assigned a value, and ensure is set to Present' { It 'Should throw the correct error' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - Members = $mockEnumMemberNames - MembersToExclude = $mockSqlServerLoginThree - } - - $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - { Get-TargetResource @testParameters } | Should -Throw $errorMessage } - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context - } - } - - Context 'When the system is not in the desired state and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = 'UnknownRoleName' - } - - It 'Should return the state as absent when the role does not exist' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the members as null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When the system is not in the desired state, parameter Members is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - Members = @($mockSqlServerLoginOne, $mockSqlServerLoginThree) - } - - It 'Should return the state as absent when the members in the role are wrong' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the members as not null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Not -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - # Regression test for issue #790 - It 'Should return the members as string array' { - $result = Get-TargetResource @testParameters - ($result.Members -is [System.String[]]) | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When the system is not in the desired state, parameter MembersToInclude is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToInclude = $mockSqlServerLoginThree - } - - It 'Should return the state as absent when the members in the role are missing' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the members as not null' { - $result = Get-TargetResource @testParameters - $result.Members | Should -Not -Be $null - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - # Regression test for issue #790 - It 'Should return the members as string array' { - $result = Get-TargetResource @testParameters - ($result.Members -is [System.String[]]) | Should -Be $true - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - $result.MembersToInclude | Should -Be $testParameters.MembersToInclude - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When the system is not in the desired state, parameter MembersToExclude is assigned a value and ensure is set to Present' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToExclude = $mockSqlServerLoginTwo - } - - It 'Should return the state as absent when the members in the role are present' { - $result = Get-TargetResource @testParameters - $result.Ensure | Should -Be 'Absent' - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return the same values as passed as parameters' { - $result = Get-TargetResource @testParameters - $result.ServerName | Should -Be $testParameters.ServerName - $result.InstanceName | Should -Be $testParameters.InstanceName - $result.ServerRoleName | Should -Be $testParameters.ServerRoleName - $result.MembersToExclude | Should -Be $testParameters.MembersToExclude - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - } - - Context 'When evaluating role membership, case sensitivity should not be used. (Issue #1153)' { - It 'Should return Present when the MemberToInclude is a member of the role.' { - $testParameters = $mockDefaultParameters.Clone() - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToInclude = $mockSqlServerLoginOne.ToUpper() - } - - $result = Get-TargetResource @testParameters - - $result.Ensure | Should -Be 'Present' - $result.Members | Should -Contain $mockSqlServerLoginOne - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It - } - - It 'Should return Absent when the MembersToExclude is a member of the role.' { - $testParameters = $mockDefaultParameters.Clone() - $testParameters += @{ - ServerRoleName = $mockSqlServerRole - MembersToExclude = $mockSqlServerLoginOne.ToUpper() - } - - $result = Get-TargetResource @testParameters - - $result.Ensure | Should -Be 'Absent' - $result.Members | Should -Contain $mockSqlServerLoginOne - - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should call the mock function Connect-SQL' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } @@ -632,7 +335,7 @@ try } Context 'When the system is not in the desired state and ensure is set to Absent' { - It 'Should return false when desired server role exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Absent' @@ -640,14 +343,19 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $false + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return false when desired server role exist' { + $result | Should -BeFalse + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When the system is in the desired state and ensure is set to Absent' { - It 'Should return true when desired server role does not exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Absent' @@ -655,14 +363,19 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $true + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return true when desired server role does not exist' { + $result | Should -BeTrue + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When the system is in the desired state and ensure is set to Present' { - It 'Should return true when desired server role exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -670,14 +383,39 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $true + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return true when desired server role exist' { + $result | Should -BeTrue + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } - Context 'When the system is not in the desired state and ensure parameter is set to Present' { - It 'Should return false when desired members are not in desired server role' { + Context 'When the system is not in the desired state and ensure is set to Present' { + BeforeAll { + $testParameters = $mockDefaultParameters + $testParameters += @{ + Ensure = 'Present' + ServerRoleName = 'newServerRole' + } + + $result = Test-TargetResource @testParameters + } + + It 'Should return false when desired server role does not exist' { + $result | Should -BeFalse + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context + } + } + + Context 'When the system is not in the desired state and ensure is set to Present' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -686,14 +424,19 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $false + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return false when desired members are not in desired server role' { + $result | Should -BeFalse + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When both the parameters Members and MembersToInclude are assigned a value and ensure is set to Present' { - It 'Should throw the correct error' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -703,15 +446,19 @@ try } $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull + } - { Test-TargetResource @testParameters } | Should -Throw $errorMessage + It 'Should throw the correct error' { + { Test-TargetResource @testParameters } | Should -Throw '(DRC0010)' + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should not be executed' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope Context } } Context 'When parameter MembersToInclude is assigned a value, parameter Members is not assigned a value, and ensure is set to Present' { - It 'Should return true when desired server role exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -720,30 +467,40 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $true + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return true when desired server role exist' { + $result | Should -BeTrue + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When parameter MembersToInclude is assigned a value, parameter Members is not assigned a value, and ensure is set to Present' { - It 'Should return false when desired server role does not exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' - ServerRoleName = $mockSqlServerRole + ServerRoleName = 'RoleNotExist' # $mockSqlServerRole MembersToInclude = $mockSqlServerLoginThree } $result = Test-TargetResource @testParameters - $result | Should -Be $false + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return false when desired server role does not exist' { + $result | Should -BeFalse + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When both the parameters Members and MembersToExclude are assigned a value and ensure is set to Present' { - It 'Should throw the correct error' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -753,15 +510,19 @@ try } $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull + } - { Test-TargetResource @testParameters } | Should -Throw $errorMessage + It 'Should throw the correct error' { + {Test-TargetResource @testParameters} | Should -Throw '(DRC0010)' + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should not be executed' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope Context } } Context 'When parameter MembersToExclude is assigned a value, parameter Members is not assigned a value, and ensure is set to Present' { - It 'Should return true when desired server role does not exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -770,14 +531,19 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $true + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return true when desired server role does not exist' { + $result | Should -BeTrue + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } Context 'When parameter MembersToExclude is assigned a value, parameter Members is not assigned a value, and ensure is set to Present' { - It 'Should return false when desired server role exist' { + BeforeAll { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' @@ -786,9 +552,14 @@ try } $result = Test-TargetResource @testParameters - $result | Should -Be $false + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should return false when desired server role exist' { + $result | Should -BeFalse + } + + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } @@ -807,7 +578,7 @@ try } Context 'When the system is not in the desired state and ensure is set to Absent' { - It 'Should not throw when calling the drop method' { + BeforeAll { $mockSqlServerRole = 'ServerRoleToDrop' $mockExpectedServerRoleToDrop = 'ServerRoleToDrop' $testParameters = $mockDefaultParameters @@ -815,10 +586,14 @@ try Ensure = 'Absent' ServerRoleName = $mockSqlServerRole } + } + It 'Should not throw when calling the drop method' { { Set-TargetResource @testParameters } | Should -Not -Throw + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should be executed once' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } } @@ -898,11 +673,11 @@ try MembersToInclude = $mockSqlServerLoginThree } - $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - - { Set-TargetResource @testParameters } | Should -Throw $errorMessage + { Set-TargetResource @testParameters } | Should -Throw '(DRC0010)' + } - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + It 'Should should not call Connect-SQL' { + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope Context } } @@ -918,9 +693,9 @@ try $errorMessage = $script:localizedData.MembersToIncludeAndExcludeParamMustBeNull - { Set-TargetResource @testParameters } | Should -Throw $errorMessage + { Set-TargetResource @testParameters } | Should -Throw '(DRC0010)' - Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 0 -Scope It } } @@ -1104,7 +879,7 @@ try } Context 'When specifying a list of security principals to include in the Role.' { - It 'Should not throw when a member to inculde is a Role.' { + It 'Should not throw when a member to include is a Role.' { $mockExpectedMemberToAdd = $mockSqlServerChildRole $testParameters = $mockDefaultParameters.Clone() @@ -1231,41 +1006,16 @@ try { Test-SqlSecurityPrincipal @testParameters } | Should -Throw -ExpectedMessage $testErrorMessage } - - It 'Should return false when ErrorAction is set to SilentlyContinue' { - $testSecurityPrincipal = 'Nabrond' - - $testParameters = @{ - SqlServerObject = $testSqlServerObject - SecurityPrincipal = $testSecurityPrincipal - } - - <# - Pester will still see the error on the stack regardless of the value used for ErrorAction - Wrap this call in a try/catch to swallow the exception and capture the return value. - #> - try - { - $result = Test-SqlSecurityPrincipal @testParameters -ErrorAction SilentlyContinue - } - catch - { - continue; - } - - $result | Should -Be $false - } } Context 'When the security principal exists.' { It 'Should return true when the principal is a Login.' { - $testParameters = @{ SqlServerObject = $testSqlServerObject SecurityPrincipal = $mockSqlServerLoginOne } - Test-SqlSecurityPrincipal @testParameters | Should -Be $true + Test-SqlSecurityPrincipal @testParameters | Should -BeTrue } It 'Should return true when the principal is a Login and case does not match.' { @@ -1274,7 +1024,7 @@ try SecurityPrincipal = $mockSqlServerLoginOne.ToUpper() } - Test-SqlSecurityPrincipal @testParameters | Should -Be $true + Test-SqlSecurityPrincipal @testParameters | Should -BeTrue } It 'Should return true when the principal is a Role.' { @@ -1283,7 +1033,7 @@ try SecurityPrincipal = $mockSqlServerRole } - Test-SqlSecurityPrincipal @testParameters | Should -Be $true + Test-SqlSecurityPrincipal @testParameters | Should -BeTrue } It 'Should return true when the principal is a Role and case does not match.' { @@ -1292,7 +1042,273 @@ try SecurityPrincipal = $mockSqlServerRole.ToUpper() } - Test-SqlSecurityPrincipal @testParameters | Should -Be $true + Test-SqlSecurityPrincipal @testParameters | Should -BeTrue + } + } + } + + Describe 'DSC_SqlRole\Get-CorrectedMemberParameters' -Tag 'Helper' { + Context 'When parameter Members is assigned a value and the role is not sysadmin, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRole + Members = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.Members | Should -HaveCount 2 + } + + It 'Should return the same elements' { + $result.Members | Should -Be $mockEnumMemberNames + } + + It 'Should not return extra values' { + $result.MembersToInclude | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter Members is assigned a value and the role is sysadmin, if SA is in Members, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + Members = $mockEnumMemberNamesSysAdmin + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 3 elements' { + $result.Members | Should -HaveCount 3 + } + + It 'Should return the same elements' { + $result.Members | Should -Be $mockEnumMemberNamesSysAdmin + } + + It 'Should not return extra values' { + $result.MembersToInclude | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter Members is assigned a value and the role is sysadmin, if SA is not in Members, SA should be added to the output' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + Members = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 3 elements' { + $result.Members | Should -HaveCount 3 + } + + It 'Should have SA in Members' { + $result.Members | Should -Contain $mockSqlServerSA + } + + It 'Should not return extra values' { + $result.MembersToInclude | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToInclude is assigned a value and the role is not sysadmin, if SA is in MembersToInclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRole + MembersToInclude = $mockEnumMemberNamesSysAdmin + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 3 elements' { + $result.MembersToInclude | Should -HaveCount 3 + } + + It 'Should return the elements from Members' { + $result.MembersToInclude | Should -Be $mockEnumMemberNamesSysAdmin + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToInclude is assigned a value and the role is not sysadmin, if SA is not in MembersToInclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRole + MembersToInclude = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.MembersToInclude | Should -HaveCount 2 + } + + It 'Should return the elements from Members' { + $result.MembersToInclude | Should -Be $mockEnumMemberNames + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToInclude is assigned a value and the role is sysadmin, if SA is not in MembersToInclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + MembersToInclude = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.MembersToInclude | Should -HaveCount 2 + } + + It 'Should return the elements from Members' { + $result.MembersToInclude | Should -Be $mockEnumMemberNames + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToInclude is assigned a value and the role is sysadmin, if SA is in MembersToInclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + MembersToInclude = $mockEnumMemberNamesSysAdmin + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 3 elements' { + $result.MembersToInclude | Should -HaveCount 3 + } + + It 'Should return the elements from Members' { + $result.MembersToInclude | Should -Be $mockEnumMemberNamesSysAdmin + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToExclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToExclude is assigned a value and the role is not sysadmin, if SA is in MembersToExclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRole + MembersToExclude = $mockEnumMemberNamesSysAdmin + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 3 elements' { + $result.MembersToExclude | Should -HaveCount 3 + } + + It 'Should return the elements from Members' { + $result.MembersToExclude | Should -Be $mockEnumMemberNamesSysAdmin + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToInclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToExclude is assigned a value and the role is not sysadmin, if SA is not in MembersToExclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRole + MembersToExclude = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.MembersToExclude | Should -HaveCount 2 + } + + It 'Should return the elements from Members' { + $result.MembersToExclude | Should -Be $mockEnumMemberNames + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToInclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToExclude is assigned a value and the role is sysadmin, if SA is not in MembersToExclude, the output should be the same' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + MembersToExclude = $mockEnumMemberNames + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.MembersToExclude | Should -HaveCount 2 + } + + It 'Should return the elements from Members' { + $result.MembersToExclude | Should -Be $mockEnumMemberNames + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToInclude | Should -BeNullOrEmpty + } + } + + Context 'When parameter MembersToExclude is assigned a value and the role is sysadmin, if SA is in MembersToExclude, SA should be removed' { + BeforeAll { + $testParameters = @{ + ServerRoleName = $mockSqlServerRoleSysAdmin + MembersToExclude = $mockEnumMemberNamesSysAdmin + } + + $result = Get-CorrectedMemberParameters @testParameters + } + + It 'Should return an array with 2 elements' { + $result.MembersToExclude | Should -HaveCount 2 + } + + It 'Should return the elements from Members' { + $result.MembersToExclude | Should -Not -Contain $mockSqlServerSA + } + + It 'Should not return extra values' { + $result.Members | Should -BeNullOrEmpty + $result.MembersToInclude | Should -BeNullOrEmpty } } }