diff --git a/CHANGELOG.md b/CHANGELOG.md index cc668c8d3..336c9d06a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,92 @@ ## Unreleased +## 12.5.0.0 + +- Changes to SqlServerSecureConnection + - Updated README and added example for SqlServerSecureConnection, + instructing users to use the 'SYSTEM' service account instead of + 'LocalSystem'. +- Changes to SqlScript + - Correctly passes the `$VerbosePreference` to the helper function + `Invoke-SqlScript` so that `PRINT` statements is outputted correctly + when verbose output is requested, e.g + `Start-DscConfiguration -Verbose`. + - Added en-US localization ([issue #624](https://github.com/PowerShell/SqlServerDsc/issues/624)). + - Added additional unit tests for code coverage. +- Changes to SqlScriptQuery + - Correctly passes the `$VerbosePreference` to the helper function + `Invoke-SqlScript` so that `PRINT` statements is outputted correctly + when verbose output is requested, e.g + `Start-DscConfiguration -Verbose`. + - Added en-US localization. + - Added additional unit tests for code coverage. +- Changes to SqlSetup + - Concatenated Robocopy localization strings ([issue #694](https://github.com/PowerShell/SqlServerDsc/issues/694)). + - Made the error message more descriptive when the Set-TargetResource + function calls the Test-TargetResource function to verify the desired + state. +- Changes to SqlWaitForAG + - Added en-US localization ([issue #625](https://github.com/PowerShell/SqlServerDsc/issues/625)). +- Changes to SqlServerPermission + - Added en-US localization ([issue #619](https://github.com/PowerShell/SqlServerDsc/issues/619)). +- Changes to SqlServerMemory + - Added en-US localization ([issue #617](https://github.com/PowerShell/SqlServerDsc/issues/617)). + - No longer will the resource set the MinMemory value if it was provided + in a configuration that also set the `Ensure` parameter to 'Absent' + ([issue #1329](https://github.com/PowerShell/SqlServerDsc/issues/1329)). + - Refactored unit tests to simplify them add add slightly more code + coverage. +- Changes to SqlServerMaxDop + - Added en-US localization ([issue #616](https://github.com/PowerShell/SqlServerDsc/issues/616)). +- Changes to SqlRS + - Reporting Services are restarted after changing settings, unless + `$SuppressRestart` parameter is set ([issue #1331](https://github.com/PowerShell/SqlServerDsc/issues/1331)). + `$SuppressRestart` will also prevent Reporting Services restart after initialization. + - Fixed one of the error handling to use localization, and made the + error message more descriptive when the Set-TargetResource function + calls the Test-TargetResource function to verify the desired + state. *This was done prior to adding full en-US localization.* + - Fixed ([issue #1258](https://github.com/PowerShell/SqlServerDsc/issues/1258)). + When initializing Reporting Services, there is no need to execute `InitializeReportServer` + CIM method, since executing `SetDatabaseConnection` CIM method initializes + Reporting Services. + - [issue #864](https://github.com/PowerShell/SqlServerDsc/issues/864) SqlRs + can now initialise SSRS 2017 instances +- Changes to SqlServerLogin + - Added en-US localization ([issue #615](https://github.com/PowerShell/SqlServerDsc/issues/615)). + - Added unit tests to improved code coverage. +- Changes to SqlWindowsFirewall + - Added en-US localization ([issue #614](https://github.com/PowerShell/SqlServerDsc/issues/614)). +- Changes to SqlServerEndpoint + - Added en-US localization ([issue #611](https://github.com/PowerShell/SqlServerDsc/issues/611)). +- Changes to SqlServerEndpointPermission + - Added en-US localization ([issue #612](https://github.com/PowerShell/SqlServerDsc/issues/612)). +- Changes to SqlServerEndpointState + - Added en-US localization ([issue #613](https://github.com/PowerShell/SqlServerDsc/issues/613)). +- Changes to SqlDatabaseRole + - Added en-US localization ([issue #610](https://github.com/PowerShell/SqlServerDsc/issues/610)). +- Changes to SqlDatabaseRecoveryModel + - Added en-US localization ([issue #609](https://github.com/PowerShell/SqlServerDsc/issues/609)). +- Changes to SqlDatabasePermission + - Added en-US localization ([issue #608](https://github.com/PowerShell/SqlServerDsc/issues/608)). +- Changes to SqlDatabaseOwner + - Added en-US localization ([issue #607](https://github.com/PowerShell/SqlServerDsc/issues/607)). +- Changes to SqlDatabase + - Added en-US localization ([issue #606](https://github.com/PowerShell/SqlServerDsc/issues/606)). +- Changes to SqlAGListener + - Added en-US localization ([issue #604](https://github.com/PowerShell/SqlServerDsc/issues/604)). +- Changes to SqlAlwaysOnService + - Added en-US localization ([issue #603](https://github.com/PowerShell/SqlServerDsc/issues/608)). +- Changes to SqlAlias + - Added en-US localization ([issue #602](https://github.com/PowerShell/SqlServerDsc/issues/602)). + - Removed ShouldProcess for the code, since it has no purpose in a DSC + resource ([issue #242](https://github.com/PowerShell/SqlServerDsc/issues/242)). +- Changes to SqlServerReplication + - Added en-US localization ([issue #620](https://github.com/PowerShell/SqlServerDsc/issues/620)). + - Refactored Get-TargetResource slightly so it provide better verbose + messages. + ## 12.4.0.0 - Changes to SqlServerDsc diff --git a/DSCResources/MSFT_SqlAGListener/MSFT_SqlAGListener.psm1 b/DSCResources/MSFT_SqlAGListener/MSFT_SqlAGListener.psm1 index 2ca4e66df..5fcbc5617 100644 --- a/DSCResources/MSFT_SqlAGListener/MSFT_SqlAGListener.psm1 +++ b/DSCResources/MSFT_SqlAGListener/MSFT_SqlAGListener.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlAGListener' + <# .SYNOPSIS Returns the current state of the Availability Group listener. @@ -47,13 +49,19 @@ function Get-TargetResource $AvailabilityGroup ) + Write-Verbose -Message ( + $script:localizedData.GetAvailabilityGroupListener -f $Name, $AvailabilityGroup, $InstanceName + ) + try { $availabilityGroupListener = Get-SQLAlwaysOnAvailabilityGroupListener -Name $Name -AvailabilityGroup $AvailabilityGroup -ServerName $ServerName -InstanceName $InstanceName if ($null -ne $availabilityGroupListener) { - New-VerboseMessage -Message "Listener $Name exist." + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerIsPresent -f $Name + ) $ensure = 'Present' $port = [uint16]( $availabilityGroupListener | Select-Object -ExpandProperty PortNumber ) @@ -69,7 +77,9 @@ function Get-TargetResource } else { - New-VerboseMessage -Message "Listener $Name does not exist" + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerIsNotPresent -f $Name + ) $ensure = 'Absent' $port = 0 @@ -79,7 +89,8 @@ function Get-TargetResource } catch { - throw New-TerminatingError -ErrorType AvailabilityGroupListenerNotFound -FormatArgs @($Name) -ErrorCategory ObjectNotFound -InnerException $_.Exception + $errorMessage = $script:localizedData.AvailabilityGroupListenerNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage -ErrorRecord $_ } return @{ @@ -176,7 +187,9 @@ function Set-TargetResource { if ($Ensure -eq 'Present') { - New-VerboseMessage -Message "Create listener on $AvailabilityGroup" + Write-Verbose -Message ( + $script:localizedData.CreateAvailabilityGroupListener -f $Name, $AvailabilityGroup, $InstanceName + ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -190,7 +203,10 @@ function Set-TargetResource if ($Port) { - New-VerboseMessage -Message "Listener port set to $Port" + Write-Verbose -Message ( + $script:localizedData.SetAvailabilityGroupListenerPort -f $Port + ) + $newListenerParams += @{ Port = $Port } @@ -198,33 +214,42 @@ function Set-TargetResource if ($DHCP -and $IpAddress.Count -gt 0) { - New-VerboseMessage -Message "Listener set to DHCP with subnet $IpAddress" + Write-Verbose -Message ( + $script:localizedData.SetAvailabilityGroupListenerDhcp -f $IpAddress + ) + $newListenerParams += @{ DhcpSubnet = [System.String] $IpAddress } } elseif (-not $DHCP -and $IpAddress.Count -gt 0) { - New-VerboseMessage -Message "Listener set to static IP-address(es); $($IpAddress -join ', ')" + Write-Verbose -Message ( + $script:localizedData.SetAvailabilityGroupListenerStaticIpAddress -f ($IpAddress -join ', ') + ) + $newListenerParams += @{ StaticIp = $IpAddress } } else { - New-VerboseMessage -Message 'Listener using DHCP with server default subnet' + Write-Verbose -Message $script:localizedData.SetAvailabilityGroupListenerDhcpDefaultSubnet } New-SqlAvailabilityGroupListener @newListenerParams -ErrorAction Stop | Out-Null } else { - throw New-TerminatingError -ErrorType AvailabilityGroupNotFound -FormatArgs @($AvailabilityGroup, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } } else { - New-VerboseMessage -Message "Remove listener from $AvailabilityGroup" + Write-Verbose -Message ( + $script:localizedData.DropAvailabilityGroupListener -f $Name, $AvailabilityGroup, $InstanceName + ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -238,27 +263,29 @@ function Set-TargetResource } else { - throw New-TerminatingError -ErrorType AvailabilityGroupListenerNotFound -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupListenerNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } } else { - throw New-TerminatingError -ErrorType AvailabilityGroupNotFound -FormatArgs @($AvailabilityGroup, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } } } else { - if ($Ensure -ne '') - { - New-VerboseMessage -Message "State is already $Ensure" - } - if ($availabilityGroupListenerState.Ensure -eq 'Present') { + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerIsPresent -f $Name + ) + if (-not $DHCP -and $availabilityGroupListenerState.IpAddress.Count -lt $IpAddress.Count) # Only able to add a new IP-address, not change existing ones. { - New-VerboseMessage -Message 'Found at least one new IP-address.' + Write-Verbose -Message $script:localizedData.FoundNewIpAddress + $ipAddressEqual = $false } else @@ -270,13 +297,15 @@ function Set-TargetResource } else { - throw New-TerminatingError -ErrorType AvailabilityGroupListenerIPChangeError -FormatArgs @($($IpAddress -join ', '), $($availabilityGroupListenerState.IpAddress -join ', ')) -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.AvailabilityGroupListenerIPChangeError -f ($IpAddress -join ', '), ($availabilityGroupListenerState.IpAddress -join ', ') + New-InvalidOperationException -Message $errorMessage } } if ($($PSBoundParameters.ContainsKey('DHCP')) -and $availabilityGroupListenerState.DHCP -ne $DHCP) { - throw New-TerminatingError -ErrorType AvailabilityGroupListenerDHCPChangeError -FormatArgs @( $DHCP, $($availabilityGroupListenerState.DHCP) ) -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.AvailabilityGroupListenerDHCPChangeError -f $DHCP, $availabilityGroupListenerState.DHCP + New-InvalidOperationException -Message $errorMessage } $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -289,11 +318,15 @@ function Set-TargetResource { if ($availabilityGroupListenerState.Port -ne $Port -or -not $ipAddressEqual) { - New-VerboseMessage -Message 'Listener differ in configuration.' + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerNotInDesiredState -f $Name, $AvailabilityGroup, $InstanceName + ) if ($availabilityGroupListenerState.Port -ne $Port) { - New-VerboseMessage -Message 'Changing port configuration' + Write-Verbose -Message ( + $script:localizedData.ChangingAvailabilityGroupListenerPort -f $Port + ) $setListenerParams = @{ InputObject = $availabilityGroupListenerObject @@ -305,14 +338,16 @@ function Set-TargetResource if (-not $ipAddressEqual) { - New-VerboseMessage -Message 'Adding IP-address(es)' - $newIpAddress = @() foreach ($currentIpAddress in $IpAddress) { if (-not ( $availabilityGroupListenerState.IpAddress -contains $currentIpAddress)) { + Write-Verbose -Message ( + $script:localizedData.AddingAvailabilityGroupListenerIpAddress -f $currentIpAddress + ) + $newIpAddress += $currentIpAddress } } @@ -327,24 +362,29 @@ function Set-TargetResource } else { - New-VerboseMessage -Message 'Listener configuration is already correct.' + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerInDesiredState -f $Name, $AvailabilityGroup, $InstanceName + ) } } else { - throw New-TerminatingError -ErrorType AvailabilityGroupListenerNotFound -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupListenerNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } } else { - throw New-TerminatingError -ErrorType AvailabilityGroupNotFound -FormatArgs @($AvailabilityGroup, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } } } } else { - throw New-TerminatingError -ErrorType UnexpectedErrorFromGet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.UnexpectedErrorFromGet + New-InvalidResultException -Message $errorMessage } } @@ -424,7 +464,9 @@ function Test-TargetResource AvailabilityGroup = [System.String] $AvailabilityGroup } - New-VerboseMessage -Message "Testing state of listener $Name" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $AvailabilityGroup, $InstanceName + ) $availabilityGroupListenerState = Get-TargetResource @parameters if ($null -ne $availabilityGroupListenerState) @@ -459,7 +501,21 @@ function Test-TargetResource } else { - throw New-TerminatingError -ErrorType UnexpectedErrorFromGet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.UnexpectedErrorFromGet + New-InvalidResultException -Message $errorMessage + } + + if ($result) + { + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerInDesiredState -f $Name, $AvailabilityGroup, $InstanceName + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.AvailabilityGroupListenerNotInDesiredState -f $Name, $AvailabilityGroup, $InstanceName + ) } return $result @@ -488,7 +544,9 @@ function Get-SQLAlwaysOnAvailabilityGroupListener $ServerName ) - Write-Debug "Connecting to availability group $Name as $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)" + Write-Debug -Message ( + $script:localizedData.DebugConnectingAvailabilityGroup -f $Name, [System.Security.Principal.WindowsIdentity]::GetCurrent().Name + ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -499,7 +557,8 @@ function Get-SQLAlwaysOnAvailabilityGroupListener } else { - throw New-TerminatingError -ErrorType AvailabilityGroupNotFound -FormatArgs @($AvailabilityGroup, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.AvailabilityGroupNotFound -f $AvailabilityGroup, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } return $availabilityGroupListener diff --git a/DSCResources/MSFT_SqlAGListener/en-US/MSFT_SqlAGListener.strings.psd1 b/DSCResources/MSFT_SqlAGListener/en-US/MSFT_SqlAGListener.strings.psd1 new file mode 100644 index 000000000..a6ab5755e --- /dev/null +++ b/DSCResources/MSFT_SqlAGListener/en-US/MSFT_SqlAGListener.strings.psd1 @@ -0,0 +1,23 @@ +ConvertFrom-StringData @' + GetAvailabilityGroupListener = Get the current state of the Availability Group listener '{0}' for the Availability Group '{1}' on the instance '{2}'. + AvailabilityGroupListenerIsPresent = The Availability Group listener '{0}' exist. + AvailabilityGroupListenerIsNotPresent = The Availability Group listener '{0}' does not exist. + AvailabilityGroupListenerNotFound = Trying to make a change to a listener that does not exist. + CreateAvailabilityGroupListener = Create Availability Group listener '{0}' for the Availability Group '{1}' on the instance '{2}'. + SetAvailabilityGroupListenerPort = Availability Group listener port is set to '{0}'. + SetAvailabilityGroupListenerDhcp = Availability Group listener is using DHCP with the subnet '{0}'. + SetAvailabilityGroupListenerDhcpDefaultSubnet = Availability Group listener is using DHCP with the server default subnet. + SetAvailabilityGroupListenerStaticIpAddress = Availability Group listener is using static IP address(es) '{0}'. + DropAvailabilityGroupListener = Remove the Availability Group listener '{0}' from the Availability Group '{1}' on the instance '{2}'. + AvailabilityGroupNotFound = Unable to locate the Availability Group '{0}' on the instance '{1}'. + FoundNewIpAddress = Found at least one new IP-address. + AvailabilityGroupListenerIPChangeError = IP-address configuration mismatch. Expecting the IP-address(es) '{0}', but found '{1}'. Resource does not support changing IP-address. Listener needs to be removed and then created again. + AvailabilityGroupListenerDHCPChangeError = DHCP configuration mismatch. Expecting '{0}' found '{1}'. Resource does not support changing between static IP and DHCP. Listener needs to be removed and then created again. + AvailabilityGroupListenerInDesiredState = Availability Group listener '{0}' is in desired state for the Availability Group '{1}' on the instance '{2}'. + AvailabilityGroupListenerNotInDesiredState = Availability Group listener '{0}' is not in desired state for the Availability Group '{1}' on the instance '{2}'. + ChangingAvailabilityGroupListenerPort = Changing Availability Group listener port to '{0}'. + AddingAvailabilityGroupListenerIpAddress = Adding Availability Group listener IP address '{0}'. + UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. + TestingConfiguration = Determines the current state for the Availability Group listener '{0}' for the Availability Group '{1}' on the instance '{2}'.. + DebugConnectingAvailabilityGroup = Connecting to Availability Group listener '{0}' as the user '{1}'. +'@ diff --git a/DSCResources/MSFT_SqlAlias/MSFT_SqlAlias.psm1 b/DSCResources/MSFT_SqlAlias/MSFT_SqlAlias.psm1 index de21afa39..df1a144b8 100644 --- a/DSCResources/MSFT_SqlAlias/MSFT_SqlAlias.psm1 +++ b/DSCResources/MSFT_SqlAlias/MSFT_SqlAlias.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlAlias' + function Get-TargetResource { [CmdletBinding()] @@ -37,14 +39,19 @@ function Get-TargetResource $protocolTcp = 'DBMSSOCN' $protocolNamedPipes = 'DBNMPNTW' - Write-Verbose -Message "Getting the SQL Server Client Alias $Name" + Write-Verbose -Message ( + $script:localizedData.GetClientAlias -f $Name + ) + $itemValue = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\MSSQLServer\Client\ConnectTo' ` -Name $Name ` -ErrorAction SilentlyContinue if (((Get-CimInstance -ClassName win32_OperatingSystem).OSArchitecture) -eq '64-bit') { - Write-Verbose -Message "64-bit Operating System. Also get the client alias $Name from Wow6432Node" + Write-Verbose -Message ( + $script:localizedData.OSArchitecture64Bit -f $Name + ) $isWow6432Node = $true $itemValueWow6432Node = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\MSSQLServer\Client\ConnectTo' ` @@ -97,7 +104,7 @@ function Get-TargetResource function Set-TargetResource { - [CmdletBinding(SupportsShouldProcess)] + [CmdletBinding()] param ( [Parameter(Mandatory = $true)] @@ -129,8 +136,6 @@ function Set-TargetResource $Ensure = 'Present' ) - Write-Verbose -Message "Setting the SQL Server Client Alias $Name" - if ($Protocol -eq 'NP') { $itemValue = "DBNMPNTW,\\$ServerName\PIPE\sql\query" @@ -139,7 +144,7 @@ function Set-TargetResource if ($Protocol -eq 'TCP') { $itemValue = "DBMSSOCN,$ServerName" - if (!$UseDynamicTcpPort) + if (-not $UseDynamicTcpPort) { $itemValue += ",$TcpPort" } @@ -150,53 +155,53 @@ function Set-TargetResource if ($Ensure -eq 'Present') { - Write-Verbose -Message "Adding the SQL Server Client Alias $Name" + Write-Verbose -Message ( + $script:localizedData.AddClientAlias64Bit -f $Name + ) - if ($PSCmdlet.ShouldProcess($Name, 'Setting the client alias')) + if (-not (Test-Path -Path $registryPath)) { - if (!(Test-Path -Path $registryPath)) - { - New-Item -Path $registryPath -Force | Out-Null - } - - Set-ItemProperty -Path $registryPath -Name $Name -Value $itemValue | Out-Null + New-Item -Path $registryPath -Force | Out-Null } + Set-ItemProperty -Path $registryPath -Name $Name -Value $itemValue | Out-Null + # If this is a 64-bit OS then also update Wow6432Node if (((Get-CimInstance -ClassName win32_OperatingSystem).OSArchitecture) -eq '64-bit') { - if ($PSCmdlet.ShouldProcess($Name, 'Setting the client alias (32-bit)')) - { - if (!(Test-Path -Path $registryPathWow6432Node)) - { - New-Item -Path $registryPathWow6432Node -Force | Out-Null - } + Write-Verbose -Message ( + $script:localizedData.AddClientAlias32Bit -f $Name + ) - Set-ItemProperty -Path $registryPathWow6432Node -Name $Name -Value $itemValue | Out-Null + if (-not (Test-Path -Path $registryPathWow6432Node)) + { + New-Item -Path $registryPathWow6432Node -Force | Out-Null } + + Set-ItemProperty -Path $registryPathWow6432Node -Name $Name -Value $itemValue | Out-Null } } if ($Ensure -eq 'Absent') { - Write-Verbose -Message "Removing the SQL Server Client Alias $Name" + Write-Verbose -Message ( + $script:localizedData.RemoveClientAlias64Bit -f $Name + ) - if ($PSCmdlet.ShouldProcess($Name, 'Remove the client alias')) + if (Test-Path -Path $registryPath) { - if (Test-Path -Path $registryPath) - { - Remove-ItemProperty -Path $registryPath -Name $Name - } + Remove-ItemProperty -Path $registryPath -Name $Name } # If this is a 64-bit OS then also remove from Wow6432Node if (((Get-CimInstance -ClassName win32_OperatingSystem).OSArchitecture) -eq '64-bit' ` -and (Test-Path -Path $registryPathWow6432Node)) { - if ($PSCmdlet.ShouldProcess($Name, 'Remove the client alias (32-bit)')) - { - Remove-ItemProperty -Path $registryPathWow6432Node -Name $Name - } + Write-Verbose -Message ( + $script:localizedData.RemoveClientAlias32Bit -f $Name + ) + + Remove-ItemProperty -Path $registryPathWow6432Node -Name $Name } } } @@ -236,7 +241,9 @@ function Test-TargetResource $Ensure = 'Present' ) - Write-Verbose -Message "Testing the SQL Server Client Alias $Name" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name + ) $result = $false @@ -251,11 +258,17 @@ function Test-TargetResource { if( $Ensure -eq 'Absent' ) { + Write-Verbose -Message ( + $script:localizedData.ClientAliasMissing -f $Name + ) + $result = $true } else { - Write-Verbose -Message 'Ensure is in the desired state. Verifying values.' + Write-Verbose -Message ( + $script:localizedData.ClientAliasPresent -f $Name + ) if ($Protocol -eq $currentValues.Protocol) { @@ -283,11 +296,15 @@ function Test-TargetResource if ($result) { - Write-Verbose -Message 'In the desired state' + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name + ) } else { - Write-Verbose -Message 'Not in the desired state' + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState -f $Name + ) } return $result diff --git a/DSCResources/MSFT_SqlAlias/en-US/MSFT_SqlAlias.strings.psd1 b/DSCResources/MSFT_SqlAlias/en-US/MSFT_SqlAlias.strings.psd1 new file mode 100644 index 000000000..3dd378e02 --- /dev/null +++ b/DSCResources/MSFT_SqlAlias/en-US/MSFT_SqlAlias.strings.psd1 @@ -0,0 +1,13 @@ +ConvertFrom-StringData @' + GetClientAlias = Getting the SQL Server Client Alias '{0}'. + OSArchitecture64Bit = Current node is a 64-bit operating system, so will get the SQL Server Client Alias '{0}' from Wow6432Node too. + AddClientAlias64Bit = Adding the SQL Server Client Alias '{0}' (64-bit). + AddClientAlias32Bit = Adding the SQL Server Client Alias '{0}' (32-bit). + RemoveClientAlias64Bit = Removing the SQL Server Client Alias '{0}' (64-bit). + RemoveClientAlias32Bit = Removing the SQL Server Client Alias '{0}' (32-bit). + TestingConfiguration = Determines if the SQL Server Client Alias is in desired state. + ClientAliasMissing = The SQL Server Client Alias '{0}' does not exist. + ClientAliasPresent = The SQL Server Client Alias '{0}' exist, verifying values. + InDesiredState = The SQL Server Client Alias '{0}' is in desired state. + NotInDesiredState = The SQL Server Client Alias '{0}' is not in desired state. +'@ diff --git a/DSCResources/MSFT_SqlAlwaysOnService/MSFT_SqlAlwaysOnService.psm1 b/DSCResources/MSFT_SqlAlwaysOnService/MSFT_SqlAlwaysOnService.psm1 index 5c7683c38..199161bbe 100644 --- a/DSCResources/MSFT_SqlAlwaysOnService/MSFT_SqlAlwaysOnService.psm1 +++ b/DSCResources/MSFT_SqlAlwaysOnService/MSFT_SqlAlwaysOnService.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlAlwaysOnService' + <# .SYNOPSIS Gets the current value of the SQL Server Always On high availability and @@ -57,7 +59,9 @@ function Get-TargetResource $statusString = 'disabled' } - New-VerboseMessage -Message ( 'SQL Always On is {0} on "{1}\{2}".' -f $statusString, $ServerName, $InstanceName ) + Write-Verbose -Message ( + $script:localizedData.GetAlwaysOnServiceState -f $statusString, $ServerName, $InstanceName + ) return @{ IsHadrEnabled = $isAlwaysOnEnabled @@ -121,19 +125,32 @@ function Set-TargetResource { 'Absent' { + $statusString = 'disabled' + # Disable Always On without restarting the services. - New-VerboseMessage -Message "Disabling Always On for the instance $serverInstance" + Write-Verbose -Message ( + $script:localizedData.DisableAlwaysOnAvailabilityGroup -f $ServerName, $InstanceName + ) + Disable-SqlAlwaysOn -ServerInstance $serverInstance -NoServiceRestart } + 'Present' { + $statusString = 'enabled' + # Enable Always On without restarting the services. - New-VerboseMessage -Message "Enabling Always On for the instance $serverInstance" + Write-Verbose -Message ( + $script:localizedData.EnableAlwaysOnAvailabilityGroup -f $ServerName, $InstanceName + ) + Enable-SqlAlwaysOn -ServerInstance $serverInstance -NoServiceRestart } } - New-VerboseMessage -Message ( 'SQL Always On has been {0} on "{1}\{2}". Restarting the service.' -f @{Absent = 'disabled'; Present = 'enabled'}[$Ensure], $ServerName, $InstanceName ) + Write-Verbose -Message ( + $script:localizedData.DisableAlwaysOnAvailabilityGroup -f $statusString, $ServerName, $InstanceName + ) # Now restart the SQL service so that all dependent services are also returned to their previous state Restart-SqlService -SQLServer $ServerName -SQLInstanceName $InstanceName -Timeout $RestartTimeout @@ -141,7 +158,8 @@ function Set-TargetResource # Verify always on was set if ( -not ( Test-TargetResource @PSBoundParameters ) ) { - throw New-TerminatingError -ErrorType AlterAlwaysOnServiceFailed -FormatArgs $Ensure, $serverInstance -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.AlterAlwaysOnServiceFailed -f $statusString, $ServerName, $InstanceName + New-InvalidResultException -Message $errorMessage } } @@ -190,6 +208,10 @@ function Test-TargetResource $RestartTimeout = 120 ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $ServerName, $InstanceName + ) + # Determine the current state of Always On $getTargetResourceParameters = @{ Ensure = $Ensure @@ -199,15 +221,34 @@ function Test-TargetResource $state = Get-TargetResource @getTargetResourceParameters - # Determine what the desired state of Always On is - $hadrDesiredState = @{ 'Present' = $true; 'Absent' = $false }[$Ensure] - - # Determine whether the value matches the desired state - $desiredStateMet = $state.IsHadrEnabled -eq $hadrDesiredState + $isInDesiredState = $true - New-VerboseMessage -Message ( 'SQL Always On is in the desired state for "{0}\{1}": {2}.' -f $ServerName, $InstanceName, $desiredStateMet ) + if ($state.IsHadrEnabled) + { + if ($Ensure -eq 'Present') + { + Write-Verbose -Message $script:localizedData.AlwaysOnAvailabilityGroupEnabled + } + else + { + Write-Verbose -Message $script:localizedData.AlwaysOnAvailabilityGroupNotInDesiredStateDisabled + $isInDesiredState = $false + } + } + else + { + if ($Ensure -eq 'Absent') + { + Write-Verbose -Message $script:localizedData.AlwaysOnAvailabilityGroupDisabled + } + else + { + Write-Verbose -Message $script:localizedData.AlwaysOnAvailabilityGroupNotInDesiredStateEnabled + $isInDesiredState = $false + } + } - return $desiredStateMet + return $isInDesiredState } Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_SqlAlwaysOnService/en-US/MSFT_SqlAlwaysOnService.strings.psd1 b/DSCResources/MSFT_SqlAlwaysOnService/en-US/MSFT_SqlAlwaysOnService.strings.psd1 new file mode 100644 index 000000000..bce52b142 --- /dev/null +++ b/DSCResources/MSFT_SqlAlwaysOnService/en-US/MSFT_SqlAlwaysOnService.strings.psd1 @@ -0,0 +1,12 @@ +ConvertFrom-StringData @' + GetAlwaysOnServiceState = Always On Availability Groups is {0} on the instance '{1}\\{2}'. + DisableAlwaysOnAvailabilityGroup = Disabling Always On Availability Groups for the instance '{0}\\{1}'. + EnableAlwaysOnAvailabilityGroup = Enabling Always On Availability Groups for the instance '{0}\\{1}'. + RestartingService = Always On Availability Groups has been {0} on the instance '{1}\\{2}'. Restarting the service. + AlterAlwaysOnServiceFailed = Failed to change the Always On Availability Groups to {0} on the instance '{1}\\{2}'. + TestingConfiguration = Determines if the current state of Always On Availability Groups on the instance '{0}\\{1}'. + AlwaysOnAvailabilityGroupDisabled = Always On Availability Groups is disabled. + AlwaysOnAvailabilityGroupEnabled = Always On Availability Groups is enabled. + AlwaysOnAvailabilityGroupNotInDesiredStateEnabled = Always On Availability Groups is disabled, but expected it to be enabled. + AlwaysOnAvailabilityGroupNotInDesiredStateDisabled = Always On Availability Groups is enabled, but expected it to be disabled. +'@ diff --git a/DSCResources/MSFT_SqlDatabase/MSFT_SqlDatabase.psm1 b/DSCResources/MSFT_SqlDatabase/MSFT_SqlDatabase.psm1 index afa5a205b..f57a17233 100644 --- a/DSCResources/MSFT_SqlDatabase/MSFT_SqlDatabase.psm1 +++ b/DSCResources/MSFT_SqlDatabase/MSFT_SqlDatabase.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlDatabase' + <# .SYNOPSIS This function gets the sql database. @@ -62,25 +64,34 @@ function Get-TargetResource $Collation ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.GetDatabase -f $Name, $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { $sqlDatabaseCollation = $sqlServerObject.Collation - Write-Verbose -Message 'Getting SQL Databases' + # Check database exists $sqlDatabaseObject = $sqlServerObject.Databases[$Name] if ($sqlDatabaseObject) { - Write-Verbose -Message "SQL Database name $Name is present" $Ensure = 'Present' $sqlDatabaseCollation = $sqlDatabaseObject.Collation + + Write-Verbose -Message ( + $script:localizedData.DatabasePresent -f $Name, $sqlDatabaseCollation + ) } else { - Write-Verbose -Message "SQL Database name $Name is absent" $Ensure = 'Absent' + + Write-Verbose -Message ( + $script:localizedData.DatabaseAbsent -f $Name + ) } } @@ -149,7 +160,6 @@ function Set-TargetResource ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { if ($Ensure -eq 'Present') @@ -160,49 +170,51 @@ function Set-TargetResource } elseif ($Collation -notin $sqlServerObject.EnumCollations().Name) { - throw New-TerminatingError -ErrorType InvalidCollationError ` - -FormatArgs @($ServerName, $InstanceName, $Name, $Collation) ` - -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.InvalidCollation -f $Collation, $InstanceName + New-ObjectNotFoundException -Message $errorMessage } $sqlDatabaseObject = $sqlServerObject.Databases[$Name] - if ($sqlDatabaseObject) { + Write-Verbose -Message ( + $script:localizedData.SetDatabase -f $Name, $InstanceName + ) + try { - Write-Verbose -Message "Updating the database $Name with specified settings." + Write-Verbose -Message ( + $script:localizedData.UpdatingCollation -f $Collation + ) + $sqlDatabaseObject.Collation = $Collation $sqlDatabaseObject.Alter() - New-VerboseMessage -Message "Updated Database $Name." } catch { - throw New-TerminatingError -ErrorType UpdateDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToUpdateDatabase -f $Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } else { try { - $sqlDatabaseObjectToCreate = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Database -ArgumentList $sqlServerObject, $Name + $sqlDatabaseObjectToCreate = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Database' -ArgumentList $sqlServerObject, $Name if ($sqlDatabaseObjectToCreate) { - Write-Verbose -Message "Adding to SQL the database $Name." + Write-Verbose -Message ( + $script:localizedData.CreateDatabase -f $Name + ) + $sqlDatabaseObjectToCreate.Collation = $Collation $sqlDatabaseObjectToCreate.Create() - New-VerboseMessage -Message "Created Database $Name." } } catch { - throw New-TerminatingError -ErrorType CreateDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToCreateDatabase -f $Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -213,17 +225,17 @@ function Set-TargetResource $sqlDatabaseObjectToDrop = $sqlServerObject.Databases[$Name] if ($sqlDatabaseObjectToDrop) { - Write-Verbose -Message "Deleting to SQL the database $Name." + Write-Verbose -Message ( + $script:localizedData.DropDatabase -f $Name + ) + $sqlDatabaseObjectToDrop.Drop() - New-VerboseMessage -Message "Dropped Database $Name." } } catch { - throw New-TerminatingError -ErrorType DropDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToDropDatabase -f $Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -283,7 +295,9 @@ function Test-TargetResource $Collation ) - Write-Verbose -Message "Checking if database named $Name is present or absent" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $InstanceName + ) $getTargetResourceResult = Get-TargetResource @PSBoundParameters $isDatabaseInDesiredState = $true @@ -299,7 +313,10 @@ function Test-TargetResource { if ($getTargetResourceResult.Ensure -ne 'Absent') { - New-VerboseMessage -Message "Ensure is set to Absent. The database $Name should be dropped" + Write-Verbose -Message ( + $script:localizedData.NotInDesiredStateAbsent -f $Name + ) + $isDatabaseInDesiredState = $false } } @@ -308,18 +325,24 @@ function Test-TargetResource { if ($getTargetResourceResult.Ensure -ne 'Present') { - New-VerboseMessage -Message "Ensure is set to Present. The database $Name should be created" + Write-Verbose -Message ( + $script:localizedData.NotInDesiredStatePresent -f $Name + ) + $isDatabaseInDesiredState = $false } elseif ($getTargetResourceResult.Collation -ne $Collation) { - New-VerboseMessage -Message 'Database exist but has the wrong collation.' + Write-Verbose -Message ( + $script:localizedData.CollationWrong -f $Name, $getTargetResourceResult.Collation, $Collation + ) + $isDatabaseInDesiredState = $false } } } - $isDatabaseInDesiredState + return $isDatabaseInDesiredState } Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_SqlDatabase/en-US/MSFT_SqlDatabase.strings.psd1 b/DSCResources/MSFT_SqlDatabase/en-US/MSFT_SqlDatabase.strings.psd1 new file mode 100644 index 000000000..2212ea442 --- /dev/null +++ b/DSCResources/MSFT_SqlDatabase/en-US/MSFT_SqlDatabase.strings.psd1 @@ -0,0 +1,17 @@ +ConvertFrom-StringData @' + GetDatabase = Get the state of the database '{0}' on the instance '{1}'. + DatabasePresent = There is a database '{0}' present, and has the collation '{1}'. + DatabaseAbsent = It does not exist a database named '{0}'. + InvalidCollation = The specified collation '{0}' is not a valid collation for the instance '{1}'. + SetDatabase = Changing properties of the database '{0}' on the instance '{1}'. + UpdatingCollation = Changing the database collation to '{0}'. + FailedToUpdateDatabase = Failed to update database {0} with specified changes. + CreateDatabase = Creating the database '{0}'. + DropDatabase = Removing the database '{0}'. + FailedToCreateDatabase = Failed to create the database '{0}'. + FailedToDropDatabase = Failed to remove the database '{0}' + TestingConfiguration = Determines the state of the database '{0}' on the instance '{1}'. + NotInDesiredStateAbsent = Expected the database '{0}' to absent, but it was present. + NotInDesiredStatePresent = Expected the database '{0}' to present, but it was absent + CollationWrong = The database '{0}' exist and has the collation '{1}', but expected it to have the collation '{2}'. +'@ diff --git a/DSCResources/MSFT_SqlDatabaseOwner/MSFT_SqlDatabaseOwner.psm1 b/DSCResources/MSFT_SqlDatabaseOwner/MSFT_SqlDatabaseOwner.psm1 index c1005ebce..0be438038 100644 --- a/DSCResources/MSFT_SqlDatabaseOwner/MSFT_SqlDatabaseOwner.psm1 +++ b/DSCResources/MSFT_SqlDatabaseOwner/MSFT_SqlDatabaseOwner.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlDatabaseOwner' + <# .SYNOPSIS This function gets the owner of the desired sql database. @@ -50,31 +52,34 @@ function Get-TargetResource $InstanceName ) - Write-Verbose -Message "Getting owner of database $Database" - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.GetCurrentDatabaseOwner -f $Database, $InstanceName + ) - if ($sqlServerObject) + try { - # Check database exists - if ( -not ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + if ($sqlServerObject) { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Database, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound - } + # Check database exists + if ( -not ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) ) + { + $errorMessage = $script:localizedData.DatabaseNotFound -f $Database + New-ObjectNotFoundException -Message $errorMessage + } - try - { $sqlDatabaseOwner = $sqlDatabaseObject.Owner - New-VerboseMessage -Message "Owner for SQL Database name $Database is $sqlDatabaseOwner" - } - catch - { - throw New-TerminatingError -ErrorType FailedToGetOwnerDatabase ` - -FormatArgs @($Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation + + Write-Verbose -Message ( + $script:localizedData.CurrentDatabaseOwner -f $Database, $sqlDatabaseOwner + ) } } + catch + { + $errorMessage = $script:localizedData.FailedToGetOwnerDatabase -f $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ + } $returnValue = @{ Database = $Database @@ -128,34 +133,39 @@ function Set-TargetResource $InstanceName ) - Write-Verbose -Message "Setting owner $Name of database $Database" $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { # Check database exists if ( -not ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) ) { - throw New-TerminatingError -ErrorType NoDatabase -FormatArgs @($Database, $ServerName, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.DatabaseNotFound -f $Database + New-ObjectNotFoundException -Message $errorMessage } # Check login exists if ( -not ($sqlServerObject.Logins[$Name]) ) { - throw New-TerminatingError -ErrorType LoginNotFound -FormatArgs @($Name, $ServerName, $InstanceName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.LoginNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } + Write-Verbose -Message ( + $script:localizedData.SetDatabaseOwner -f $Database, $InstanceName + ) + try { $sqlDatabaseObject.SetOwner($Name) - New-VerboseMessage -Message "Owner of SQL Database name $Database is now $Name" + + Write-Verbose -Message ( + $script:localizedData.NewOwner -f $Name + ) } catch { - throw New-TerminatingError -ErrorType FailedToSetOwnerDatabase ` - -FormatArgs @($Name, $Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToSetOwnerDatabase -f $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -203,7 +213,9 @@ function Test-TargetResource $InstanceName ) - Write-Verbose -Message "Testing owner $Name of database $Database" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Database, $InstanceName + ) $currentValues = Get-TargetResource @PSBoundParameters return Test-DscParameterState -CurrentValues $CurrentValues ` diff --git a/DSCResources/MSFT_SqlDatabaseOwner/en-US/MSFT_SqlDatabaseOwner.strings.psd1 b/DSCResources/MSFT_SqlDatabaseOwner/en-US/MSFT_SqlDatabaseOwner.strings.psd1 new file mode 100644 index 000000000..2c7b458ec --- /dev/null +++ b/DSCResources/MSFT_SqlDatabaseOwner/en-US/MSFT_SqlDatabaseOwner.strings.psd1 @@ -0,0 +1,11 @@ +ConvertFrom-StringData @' + GetCurrentDatabaseOwner = Get the current owner of the database '{0}' on the instance '{1}'. + DatabaseNotFound = The database '{0}' does not exist. + FailedToGetOwnerDatabase = Failed to get owner of the database '{0}'. + CurrentDatabaseOwner = The current owner of the database '{0}' is the login '{1}'. + LoginNotFound = The login '{0}' does not exist on the instance. + SetDatabaseOwner = Setting a new owner of the database '{0}' on the instance '{1}'. + NewOwner = The owner was change to '{0}'. + FailedToSetOwnerDatabase = Failed to set the new owner of the database '{0}'. + TestingConfiguration = Determines if the correct login owns the database '{0}' in the instance '{1}'. +'@ diff --git a/DSCResources/MSFT_SqlDatabasePermission/MSFT_SqlDatabasePermission.psm1 b/DSCResources/MSFT_SqlDatabasePermission/MSFT_SqlDatabasePermission.psm1 index 6904f0bb4..07aac0450 100644 --- a/DSCResources/MSFT_SqlDatabasePermission/MSFT_SqlDatabasePermission.psm1 +++ b/DSCResources/MSFT_SqlDatabasePermission/MSFT_SqlDatabasePermission.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlDatabasePermission' + <# .SYNOPSIS Returns the current permissions for the user in the database @@ -66,11 +68,13 @@ function Get-TargetResource $InstanceName ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.GetDatabasePermission -f $Name, $Database, $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message "Getting permissions for user $Name in database $Database" $currentEnsure = 'Absent' if ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) @@ -101,27 +105,21 @@ function Get-TargetResource } catch { - throw New-TerminatingError -ErrorType FailedToEnumDatabasePermissions ` - -FormatArgs @($Name, $Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToEnumDatabasePermissions -f $Name, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } else { - throw New-TerminatingError -ErrorType LoginNotFound ` - -FormatArgs @($Name, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.LoginNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } } else { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidResult ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.DatabaseNotFound -f $Database + New-ObjectNotFoundException -Message $errorMessage } if ($getSqlDatabasePermissionResult) @@ -135,7 +133,7 @@ function Get-TargetResource } } - $returnValue = @{ + return @{ Ensure = $currentEnsure Database = $Database Name = $Name @@ -144,8 +142,6 @@ function Get-TargetResource ServerName = $ServerName InstanceName = $InstanceName } - - $returnValue } <# @@ -215,10 +211,11 @@ function Set-TargetResource ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { - Write-Verbose -Message "Setting permissions of database $Database for login $Name" + Write-Verbose -Message ( + $script:localizedData.ChangePermissionForUser -f $Name, $Database, $InstanceName + ) if ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) { @@ -228,17 +225,20 @@ function Set-TargetResource { try { - New-VerboseMessage -Message "Adding SQL login $Name as a user of database $Database" - $sqlDatabaseUser = New-Object -TypeName Microsoft.SqlServer.Management.Smo.User -ArgumentList ($sqlDatabaseObject, $Name) + Write-Verbose -Message ( + '{0} {1}' -f + ($script:localizedData.LoginIsNotUser -f $Name, $Database), + $script:localizedData.AddingLoginAsUser + ) + + $sqlDatabaseUser = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.User' -ArgumentList ($sqlDatabaseObject, $Name) $sqlDatabaseUser.Login = $Name $sqlDatabaseUser.Create() } catch { - throw New-TerminatingError -ErrorType AddLoginDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name, $Database) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToAddUser -f $Name, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } @@ -246,7 +246,7 @@ function Set-TargetResource { try { - $permissionSet = New-Object -TypeName Microsoft.SqlServer.Management.Smo.DatabasePermissionSet + $permissionSet = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.DatabasePermissionSet' foreach ($permission in $permissions) { @@ -257,8 +257,9 @@ function Set-TargetResource { 'Present' { - New-VerboseMessage -Message ('{0} the permissions ''{1}'' to the database {2} on the server {3}\{4}' ` - -f $PermissionState, ($Permissions -join ','), $Database, $ServerName, $InstanceName) + Write-Verbose -Message ( + $script:localizedData.AddPermission -f $PermissionState, ($Permissions -join ','), $Database + ) switch ($PermissionState) { @@ -281,8 +282,9 @@ function Set-TargetResource 'Absent' { - New-VerboseMessage -Message ('Revoking {0} permissions {1} to the database {2} on the server {3}\{4}' ` - -f $PermissionState, ($Permissions -join ','), $Database, $ServerName, $InstanceName) + Write-Verbose -Message ( + $script:localizedData.DropPermission -f $PermissionState, ($Permissions -join ','), $Database + ) if ($PermissionState -eq 'GrantWithGrant') { @@ -297,27 +299,21 @@ function Set-TargetResource } catch { - throw New-TerminatingError -ErrorType FailedToSetPermissionDatabase ` - -FormatArgs @($Name, $Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToSetPermissionDatabase -f $Name, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } else { - throw New-TerminatingError -ErrorType LoginNotFound ` - -FormatArgs @($Name, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.LoginNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } } else { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Database, $ServerName, $InstanceName) ` - -ErrorCategory InvalidResult ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.DatabaseNotFound -f $Database + New-ObjectNotFoundException -Message $errorMessage } } } @@ -389,7 +385,10 @@ function Test-TargetResource $InstanceName = 'MSSQLSERVER' ) - Write-Verbose -Message "Testing permissions for user $Name in database $Database." + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $Database, $InstanceName + ) + $getTargetResourceParameters = @{ InstanceName = $PSBoundParameters.InstanceName ServerName = $PSBoundParameters.ServerName diff --git a/DSCResources/MSFT_SqlDatabasePermission/en-US/MSFT_SqlDatabasePermission.strings.psd1 b/DSCResources/MSFT_SqlDatabasePermission/en-US/MSFT_SqlDatabasePermission.strings.psd1 new file mode 100644 index 000000000..26cbb9983 --- /dev/null +++ b/DSCResources/MSFT_SqlDatabasePermission/en-US/MSFT_SqlDatabasePermission.strings.psd1 @@ -0,0 +1,14 @@ +ConvertFrom-StringData @' + GetDatabasePermission = Get permissions for the user '{0}' in the database '{1}' on the instance '{2}'. + DatabaseNotFound = The database '{0}' does not exist. + LoginNotFound = The login '{0}' does not exist on the instance. + FailedToEnumDatabasePermissions = Failed to get the permission for the user '{0}' in the database '{1}'. + ChangePermissionForUser = Changing the permission for the user '{0}' in the database '{1}' on the instance '{2}'. + LoginIsNotUser = The login '{0}' is not a user in the database '{1}'. + AddingLoginAsUser = Adding the login as a user of the database. + FailedToAddUser = Failed to add the login '{0}' as a user of the database '{1}'. + AddPermission = {0} the permissions '{1}' to the database '{2}'. + DropPermission = Revoking the {0} permissions '{1}' from the database '{2}'. + FailedToSetPermissionDatabase = Failed to set the permissions for the login '{0}' in the database '{1}'. + TestingConfiguration = Determines if the user '{0}' has the correct permissions in the database '{1}' on the instance '{2}'. +'@ diff --git a/DSCResources/MSFT_SqlDatabaseRecoveryModel/MSFT_SqlDatabaseRecoveryModel.psm1 b/DSCResources/MSFT_SqlDatabaseRecoveryModel/MSFT_SqlDatabaseRecoveryModel.psm1 index 4d2c52792..bc8a9b180 100644 --- a/DSCResources/MSFT_SqlDatabaseRecoveryModel/MSFT_SqlDatabaseRecoveryModel.psm1 +++ b/DSCResources/MSFT_SqlDatabaseRecoveryModel/MSFT_SqlDatabaseRecoveryModel.psm1 @@ -7,11 +7,13 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlDatabaseRecoveryModel' + <# .SYNOPSIS This function gets all Key properties defined in the resource schema file - .PARAMETER Database + .PARAMETER Name This is the SQL database .PARAMETER RecoveryModel @@ -51,41 +53,42 @@ function Get-TargetResource $Name ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.GetRecoveryModel -f $Name, $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message "Getting RecoveryModel of SQL database '$Name'" $sqlDatabaseObject = $sqlServerObject.Databases[$Name] - if ($sqlDatabaseObject) { $sqlDatabaseRecoveryModel = $sqlDatabaseObject.RecoveryModel - New-VerboseMessage -Message "The current recovery model used by database $Name is '$sqlDatabaseRecoveryModel'" + + Write-Verbose -Message ( + $script:localizedData.CurrentRecoveryModel -f $sqlDatabaseRecoveryModel, $Name + ) } else { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Name, $ServerName, $InstanceName) ` - -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.DatabaseNotFound -f $Name + New-InvalidResultException -Message $errorMessage } } - $returnValue = @{ + return @{ Name = $Name RecoveryModel = $sqlDatabaseRecoveryModel ServerName = $ServerName InstanceName = $InstanceName } - - $returnValue } <# .SYNOPSIS This function gets all Key properties defined in the resource schema file - .PARAMETER Database + .PARAMETER Name This is the SQL database .PARAMETER RecoveryModel @@ -125,26 +128,29 @@ function Set-TargetResource ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { - Write-Verbose -Message "Setting RecoveryModel of SQL database '$Name'" - $sqlDatabaseObject = $sqlServerObject.Databases[$Name] + Write-Verbose -Message ( + $script:localizedData.SetRecoveryModel -f $Name + ) + $sqlDatabaseObject = $sqlServerObject.Databases[$Name] if ($sqlDatabaseObject) { if ($sqlDatabaseObject.RecoveryModel -ne $RecoveryModel) { $sqlDatabaseObject.RecoveryModel = $RecoveryModel $sqlDatabaseObject.Alter() - New-VerboseMessage -Message "The recovery model for the database $Name is changed to '$RecoveryModel'." + + Write-Verbose -Message ( + $script:localizedData.ChangeRecoveryModel -f $Name, $RecoveryModel + ) } } else { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Name, $ServerName, $InstanceName) ` - -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.DatabaseNotFound -f $Name + New-InvalidResultException -Message $errorMessage } } } @@ -153,7 +159,7 @@ function Set-TargetResource .SYNOPSIS This function gets all Key properties defined in the resource schema file - .PARAMETER Database + .PARAMETER Name This is the SQL database .PARAMETER RecoveryModel @@ -193,7 +199,9 @@ function Test-TargetResource $Name ) - Write-Verbose -Message "Testing RecoveryModel of database '$Name'" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $InstanceName + ) $currentValues = Get-TargetResource @PSBoundParameters diff --git a/DSCResources/MSFT_SqlDatabaseRecoveryModel/en-US/MSFT_SqlDatabaseRecoveryModel.strings.psd1 b/DSCResources/MSFT_SqlDatabaseRecoveryModel/en-US/MSFT_SqlDatabaseRecoveryModel.strings.psd1 new file mode 100644 index 000000000..121e5b0ac --- /dev/null +++ b/DSCResources/MSFT_SqlDatabaseRecoveryModel/en-US/MSFT_SqlDatabaseRecoveryModel.strings.psd1 @@ -0,0 +1,8 @@ +ConvertFrom-StringData @' + GetRecoveryModel = Get the current recovery model of the database '{0}' in the instance '{1}'. + CurrentRecoveryModel = The current recovery model is '{0}' for the database '{1}'. + DatabaseNotFound = The database '{0}' does not exist. + SetRecoveryModel = Setting the recovery model of database '{0}'. + ChangeRecoveryModel = The recovery model for the database '{0}' was changed to '{1}'. + TestingConfiguration = Determines if the database '{0}' on the instance '{1}' has the desired recovery model. +'@ diff --git a/DSCResources/MSFT_SqlDatabaseRole/MSFT_SqlDatabaseRole.psm1 b/DSCResources/MSFT_SqlDatabaseRole/MSFT_SqlDatabaseRole.psm1 index 8ddbb884d..9dabd35cf 100644 --- a/DSCResources/MSFT_SqlDatabaseRole/MSFT_SqlDatabaseRole.psm1 +++ b/DSCResources/MSFT_SqlDatabaseRole/MSFT_SqlDatabaseRole.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlDatabaseRole' + <# .SYNOPSIS Returns the current state of the user memberships in the role(s). @@ -61,18 +63,18 @@ function Get-TargetResource $Role ) - Write-Verbose -Message "Getting SQL Database role for $Name" + Write-Verbose -Message ( + $script:localizedData.GetDatabaseRole -f $Name, $Database, $InstanceName + ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { # Check database exists if ( -not ($sqlDatabaseObject = $sqlServerObject.Databases[$Database]) ) { - throw New-TerminatingError -ErrorType NoDatabase ` - -FormatArgs @($Database, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.DatabaseNotFound -f $Database + New-ObjectNotFoundException -Message $errorMessage } # Check role exists @@ -80,18 +82,16 @@ function Get-TargetResource { if ( -not ($sqlDatabaseObject.Roles[$currentRole]) ) { - throw New-TerminatingError -ErrorType RoleNotFound ` - -FormatArgs @($currentRole, $Database, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.RoleNotFound -f $currentRole, $Database + New-ObjectNotFoundException -Message $errorMessage } } # Check login exists if ( -not ($sqlServerObject.Logins[$Name]) ) { - throw New-TerminatingError -ErrorType LoginNotFound ` - -FormatArgs @($Name, $ServerName, $InstanceName) ` - -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.LoginNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } $ensure = 'Absent' @@ -103,15 +103,17 @@ function Get-TargetResource { if ($sqlDatabaseUser.IsMember($currentRole)) { - New-VerboseMessage -Message ("The login '$Name' is a member of the role '$currentRole' on the " + ` - "database '$Database', on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + $script:localizedData.IsMember -f $Name, $currentRole, $Database + ) $grantedRole += $currentRole } else { - New-VerboseMessage -Message ("The login '$Name' is not a member of the role '$currentRole' on the " + ` - "database '$Database', on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + $script:localizedData.IsNotMember -f $Name, $currentRole, $Database + ) } } @@ -122,8 +124,9 @@ function Get-TargetResource } else { - New-VerboseMessage -Message ("The login '$Name' is not a user of the database " + ` - "'$Database' on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + $script:localizedData.LoginIsNotUser -f $Name, $Database + ) } } @@ -201,10 +204,7 @@ function Set-TargetResource $Role ) - Write-Verbose -Message "Setting SQL Database role for $Name" - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { $sqlDatabaseObject = $sqlServerObject.Databases[$Database] @@ -218,20 +218,21 @@ function Set-TargetResource { try { - New-VerboseMessage -Message ("Adding the login '$Name' as a user of the database " + ` - "'$Database', on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + '{0} {1}' -f + ($script:localizedData.LoginIsNotUser -f $Name, $Database), + $script:localizedData.AddingLoginAsUser + ) - $sqlDatabaseUser = New-Object -TypeName Microsoft.SqlServer.Management.Smo.User ` + $sqlDatabaseUser = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.User' ` -ArgumentList $sqlDatabaseObject, $Name $sqlDatabaseUser.Login = $Name $sqlDatabaseUser.Create() } catch { - throw New-TerminatingError -ErrorType AddLoginDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name, $Database) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToAddUser -f $Name, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } @@ -240,18 +241,17 @@ function Set-TargetResource { try { - New-VerboseMessage -Message ("Adding the login '$Name' to the role '$currentRole' on the " + ` - "database '$Database', on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + $script:localizedData.AddUserToRole -f $Name, $currentRole, $Database + ) $sqlDatabaseRole = $sqlDatabaseObject.Roles[$currentRole] $sqlDatabaseRole.AddMember($Name) } catch { - throw New-TerminatingError -ErrorType AddMemberDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name, $Role, $Database) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToAddUserToRole -f $Name, $currentRole, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -262,8 +262,9 @@ function Set-TargetResource { foreach ($currentRole in $Role) { - New-VerboseMessage -Message ("Removing the login '$Name' to the role '$currentRole' on the " + ` - "database '$Database', on the instance $ServerName\$InstanceName") + Write-Verbose -Message ( + $script:localizedData.DropUserFromRole -f $Name, $currentRole, $Database + ) $sqlDatabaseRole = $sqlDatabaseObject.Roles[$currentRole] $sqlDatabaseRole.DropMember($Name) @@ -271,10 +272,8 @@ function Set-TargetResource } catch { - throw New-TerminatingError -ErrorType DropMemberDatabaseSetError ` - -FormatArgs @($ServerName, $InstanceName, $Name, $Role, $Database) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.FailedToDropUserFromRole -f $Name, $currentRole, $Database + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -341,7 +340,9 @@ function Test-TargetResource $Role ) - Write-Verbose -Message "Testing SQL Database role for $Name" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $Database, $InstanceName + ) $getTargetResourceParameters = @{ InstanceName = $PSBoundParameters.InstanceName @@ -361,7 +362,10 @@ function Test-TargetResource { if ($getTargetResourceResult.Ensure -ne 'Absent') { - New-VerboseMessage -Message "Ensure is set to Absent. The existing role for $Name should be dropped" + Write-Verbose -Message ( + $script:localizedData.NotInDesiredStateAbsent -f $Name, $Database + ) + $isDatabaseRoleInDesiredState = $false } } @@ -370,13 +374,23 @@ function Test-TargetResource { if ($getTargetResourceResult.Ensure -ne 'Present') { - New-VerboseMessage -Message "Ensure is set to Present. The missing role for $Name should be added" + Write-Verbose -Message ( + $script:localizedData.NotInDesiredStatePresent -f $Name, $Database + ) + $isDatabaseRoleInDesiredState = $false } } } - $isDatabaseRoleInDesiredState + if ($isDatabaseRoleInDesiredState) + { + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name, $Database + ) + } + + return $isDatabaseRoleInDesiredState } Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_SqlDatabaseRole/en-US/MSFT_SqlDatabaseRole.strings.psd1 b/DSCResources/MSFT_SqlDatabaseRole/en-US/MSFT_SqlDatabaseRole.strings.psd1 new file mode 100644 index 000000000..b377825a8 --- /dev/null +++ b/DSCResources/MSFT_SqlDatabaseRole/en-US/MSFT_SqlDatabaseRole.strings.psd1 @@ -0,0 +1,19 @@ +ConvertFrom-StringData @' + GetDatabaseRole = Getting current role(s) for the user '{0}' of the database '{1}' on the instance '{2}'. + DatabaseNotFound = The database '{0}' does not exist. + RoleNotFound = The role '{0}' does not exist in the database '{1}'. + LoginNotFound = The login '{0}' does not exist on the instance. + IsMember = The login '{0}' is a member of the role '{1}' in the database '{2}'. + IsNotMember = The login '{0}' is not a member of the role '{1}' in the database '{2}'. + LoginIsNotUser = The login '{0}' is not a user in the database '{1}'. + AddingLoginAsUser = Adding the login as a user of the database. + FailedToAddUser = Failed to add the login '{0}' as a user of the database '{1}'. + AddUserToRole = Adding the user (login) '{0}' to the role '{1}' in the database '{2}'. + FailedToAddUserToRole = Failed to add the user {0} to the role {1} in the database {2}. + DropUserFromRole = Removing the user (login) '{0}' from the role '{1}' in the database '{2}'. + FailedToDropUserFromRole = Failed to remove the login {0} from the role {1} in the database {2}. + TestingConfiguration = Determines if the the user '{0}' of the database '{1}' on the instance '{2}' is a member of the desired role(s). + InDesiredState = The user '{0}' of the database '{1}' is member of the specified role(s). + NotInDesiredStateAbsent = Expected the user '{0}' to not be a member of the specified role(s) in the database '{1}', but the user was member of at least one of the roles. + NotInDesiredStatePresent = Expected the user '{0}' to be a member of the specified role(s) in the database '{1}', but the user was not a member of at least one of the roles. +'@ diff --git a/DSCResources/MSFT_SqlRS/MSFT_SqlRS.psm1 b/DSCResources/MSFT_SqlRS/MSFT_SqlRS.psm1 index 2f96ed6d2..77623cd7c 100644 --- a/DSCResources/MSFT_SqlRS/MSFT_SqlRS.psm1 +++ b/DSCResources/MSFT_SqlRS/MSFT_SqlRS.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlRS' + <# .SYNOPSIS Gets the SQL Reporting Services initialization status. @@ -152,6 +154,11 @@ function Get-TargetResource parameter is not assigned a value, the default is that Reporting Services does not use SSL. + .PARAMETER SuppressRestart + Reporting Services need to be restarted after initialization or + settings change. If this parameter is set to $true, Reporting Services + will not be restarted, even after initialisation. + .NOTES To find out the parameter names for the methods in the class MSReportServer_ConfigurationSetting it's easy to list them using the @@ -224,14 +231,34 @@ function Set-TargetResource [Parameter()] [System.Boolean] - $UseSsl + $UseSsl, + + [Parameter()] + [System.Boolean] + $SuppressRestart ) $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName if ( $null -ne $reportingServicesData.Configuration ) { - if ( $InstanceName -eq 'MSSQLSERVER' ) + if ( $reportingServicesData.SqlVersion -ge 14 ) + { + if ( [string]::IsNullOrEmpty($ReportServerVirtualDirectory) ) + { + $ReportServerVirtualDirectory = 'ReportServer' + } + + if ( [string]::IsNullOrEmpty($ReportsVirtualDirectory) ) + { + $ReportsVirtualDirectory = 'Reports' + } + + $reportingServicesServiceName = 'SQLServerReportingServices' + $reportingServicesDatabaseName = 'ReportServer' + + } + elseif ( $InstanceName -eq 'MSSQLSERVER' ) { if ( [System.String]::IsNullOrEmpty($ReportServerVirtualDirectory) ) { @@ -278,11 +305,15 @@ function Set-TargetResource } $language = $wmiOperatingSystem.OSLanguage + $restartReportingService = $false if ( -not $reportingServicesData.Configuration.IsInitialized ) { New-VerboseMessage -Message "Initializing Reporting Services on $DatabaseServerName\$DatabaseInstanceName." + # We will restart Reporting Services after initialization (unless SuppressRestart is set) + $restartReportingService = $true + # If no Report Server reserved URLs have been specified, use the default one. if ( $null -eq $ReportServerReservedUrl ) { @@ -430,15 +461,26 @@ function Set-TargetResource Invoke-RsCimMethod @invokeRsCimMethodParameters - $invokeRsCimMethodParameters = @{ - CimInstance = $reportingServicesData.Configuration - MethodName = 'InitializeReportServer' - Arguments = @{ - InstallationId = $reportingServicesData.Configuration.InstallationID + $reportingServicesData = Get-ReportingServicesData -InstanceName $InstanceName + + <# + Only execute InitializeReportServer if SetDatabaseConnection hasn't + initialized Reporting Services already. Otherwise, executing + InitializeReportServer will fail on SQL Server Standard and + lower editions. + #> + if ( -not $reportingServicesData.Configuration.IsInitialized ) + { + $invokeRsCimMethodParameters = @{ + CimInstance = $reportingServicesData.Configuration + MethodName = 'InitializeReportServer' + Arguments = @{ + InstallationId = $reportingServicesData.Configuration.InstallationID + } } - } - Invoke-RsCimMethod @invokeRsCimMethodParameters + Invoke-RsCimMethod @invokeRsCimMethodParameters + } if ( $PSBoundParameters.ContainsKey('UseSsl') -and $UseSsl -ne $currentConfig.UseSsl ) { @@ -454,8 +496,6 @@ function Set-TargetResource Invoke-RsCimMethod @invokeRsCimMethodParameters } - - Restart-ReportingServicesService -SQLInstanceName $InstanceName -WaitTime 30 } else { @@ -490,6 +530,8 @@ function Set-TargetResource { New-VerboseMessage -Message "Setting report server virtual directory on $DatabaseServerName\$DatabaseInstanceName to $ReportServerVirtualDirectory." + $restartReportingService = $true + $currentConfig.ReportServerReservedUrl | ForEach-Object -Process { $invokeRsCimMethodParameters = @{ CimInstance = $reportingServicesData.Configuration @@ -535,6 +577,8 @@ function Set-TargetResource { New-VerboseMessage -Message "Setting reports virtual directory on $DatabaseServerName\$DatabaseInstanceName to $ReportServerVirtualDirectory." + $restartReportingService = $true + $currentConfig.ReportsReservedUrl | ForEach-Object -Process { $invokeRsCimMethodParameters = @{ CimInstance = $reportingServicesData.Configuration @@ -583,6 +627,8 @@ function Set-TargetResource if ( ($null -ne $ReportServerReservedUrl) -and ($null -ne (Compare-Object @compareParameters)) ) { + $restartReportingService = $true + $currentConfig.ReportServerReservedUrl | ForEach-Object -Process { $invokeRsCimMethodParameters = @{ CimInstance = $reportingServicesData.Configuration @@ -620,6 +666,8 @@ function Set-TargetResource if ( ($null -ne $ReportsReservedUrl) -and ($null -ne (Compare-Object @compareParameters)) ) { + $restartReportingService = $true + $currentConfig.ReportsReservedUrl | ForEach-Object -Process { $invokeRsCimMethodParameters = @{ CimInstance = $reportingServicesData.Configuration @@ -655,6 +703,8 @@ function Set-TargetResource { New-VerboseMessage -Message "Changing value for using SSL to '$UseSsl'." + $restartReportingService = $true + $invokeRsCimMethodParameters = @{ CimInstance = $reportingServicesData.Configuration MethodName = 'SetSecureConnectionLevel' @@ -666,11 +716,22 @@ function Set-TargetResource Invoke-RsCimMethod @invokeRsCimMethodParameters } } + + if ( $restartReportingService -and $SuppressRestart ) + { + Write-Warning -Message $script:localizedData.SuppressRestart + } + elseif ( $restartReportingService -and (-not $SuppressRestart) ) + { + Write-Verbose -Message $script:localizedData.Restart + Restart-ReportingServicesService -SQLInstanceName $InstanceName -WaitTime 30 + } } if ( -not (Test-TargetResource @PSBoundParameters) ) { - throw New-TerminatingError -ErrorType TestFailedAfterSet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.TestFailedAfterSet + New-InvalidResultException -Message $errorMessage } } @@ -705,6 +766,11 @@ function Set-TargetResource If connections to the Reporting Services must use SSL. If this parameter is not assigned a value, the default is that Reporting Services does not use SSL. + + .PARAMETER SuppressRestart + Reporting Services need to be restarted after initialization or + settings change. If this parameter is set to $true, Reporting Services + will not be restarted, even after initialisation. #> function Test-TargetResource { @@ -742,7 +808,11 @@ function Test-TargetResource [Parameter()] [System.Boolean] - $UseSsl + $UseSsl, + + [Parameter()] + [System.Boolean] + $SuppressRestart ) $result = $true @@ -828,7 +898,15 @@ function Get-ReportingServicesData if ( Get-ItemProperty -Path $instanceNamesRegistryKey -Name $InstanceName -ErrorAction SilentlyContinue ) { $instanceId = (Get-ItemProperty -Path $instanceNamesRegistryKey -Name $InstanceName).$InstanceName - $sqlVersion = [System.Int32]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\Setup" -Name 'Version').Version).Split('.')[0] + + if( Test-Path -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\MSSQLServer\CurrentVersion" ) + { + # SQL Server 2017 SSRS stores current SQL Server version to a different Registry path. + $sqlVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$InstanceId\MSSQLServer\CurrentVersion" -Name "CurrentVersion").CurrentVersion).Split(".")[0] + } + else { + $sqlVersion = [int]((Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\Setup" -Name "Version").Version).Split(".")[0] + } $reportingServicesConfiguration = Get-CimInstance -ClassName MSReportServer_ConfigurationSetting -Namespace "root\Microsoft\SQLServer\ReportServer\RS_$InstanceName\v$sqlVersion\Admin" $reportingServicesConfiguration = $reportingServicesConfiguration | Where-Object -FilterScript { $_.InstanceName -eq $InstanceName @@ -851,6 +929,7 @@ function Get-ReportingServicesData @{ Configuration = $reportingServicesConfiguration ReportsApplicationName = $reportsApplicationName + SqlVersion = $sqlVersion } } @@ -892,7 +971,7 @@ function Invoke-RsCimMethod ErrorAction = 'Stop' } - if ($PSBoundParameters.ContainsKey('Arguments')) + if ( $PSBoundParameters.ContainsKey('Arguments') ) { $invokeCimMethodParameters['Arguments'] = $Arguments } @@ -903,9 +982,9 @@ function Invoke-RsCimMethod If an general error occur in the Invoke-CimMethod, like calling a method that does not exist, returns $null in $invokeCimMethodResult. #> - if ($invokeCimMethodResult -and $invokeCimMethodResult.HRESULT -ne 0) + if ( $invokeCimMethodResult -and $invokeCimMethodResult.HRESULT -ne 0 ) { - if ($invokeCimMethodResult | Get-Member -Name 'ExtendedErrors') + if ( $invokeCimMethodResult | Get-Member -Name 'ExtendedErrors' ) { <# The returned object property ExtendedErrors is an array diff --git a/DSCResources/MSFT_SqlRS/MSFT_SqlRS.schema.mof b/DSCResources/MSFT_SqlRS/MSFT_SqlRS.schema.mof index 2c0a1669e..74aaf20ab 100644 --- a/DSCResources/MSFT_SqlRS/MSFT_SqlRS.schema.mof +++ b/DSCResources/MSFT_SqlRS/MSFT_SqlRS.schema.mof @@ -9,5 +9,6 @@ class MSFT_SqlRS : OMI_BaseResource [Write, Description("Report Server URL reservations. Optional. If not specified, 'http://+:80' URL reservation will be used.")] String ReportServerReservedUrl[]; [Write, Description("Report Manager/Report Web App URL reservations. Optional. If not specified, 'http://+:80' URL reservation will be used.")] String ReportsReservedUrl[]; [Write, Description("If connections to the Reporting Services must use SSL. If this parameter is not assigned a value, the default is that Reporting Services does not use SSL.")] Boolean UseSsl; + [Write, Description("Reporting Services need to be restarted after initialization or settings change. If this parameter is set to $true, Reporting Services will not be restarted, even after initialisation.")] Boolean SuppressRestart; [Read, Description("Is the Reporting Services instance initialized.")] Boolean IsInitialized; }; diff --git a/DSCResources/MSFT_SqlRS/en-US/MSFT_SqlRS.strings.psd1 b/DSCResources/MSFT_SqlRS/en-US/MSFT_SqlRS.strings.psd1 new file mode 100644 index 000000000..e657f651e --- /dev/null +++ b/DSCResources/MSFT_SqlRS/en-US/MSFT_SqlRS.strings.psd1 @@ -0,0 +1,5 @@ +ConvertFrom-StringData @' + Restart = Restarting Reporting Services. + SuppressRestart = Suppressing restart of Reporting Services. + TestFailedAfterSet = Test-TargetResource function returned false when Set-TargetResource function verified the desired state. This indicates that the Set-TargetResource did not correctly set set the desired state, or that the function Test-TargetResource does not correctly evaluates the desired state. +'@ diff --git a/DSCResources/MSFT_SqlRSSetup/en-US/MSFT_SqlRSSetup.strings.psd1 b/DSCResources/MSFT_SqlRSSetup/en-US/MSFT_SqlRSSetup.strings.psd1 index f29d8ea1b..74a389e48 100644 --- a/DSCResources/MSFT_SqlRSSetup/en-US/MSFT_SqlRSSetup.strings.psd1 +++ b/DSCResources/MSFT_SqlRSSetup/en-US/MSFT_SqlRSSetup.strings.psd1 @@ -1,5 +1,3 @@ -# Localized resources for SqlSetup - ConvertFrom-StringData @' TestingConfiguration = Determines if the Microsoft SQL Server Reporting Service instance is installed. FoundInstance = Found Microsoft SQL Server Reporting Service instance named '{0}'. diff --git a/DSCResources/MSFT_SqlScript/MSFT_SqlScript.psm1 b/DSCResources/MSFT_SqlScript/MSFT_SqlScript.psm1 index f2abc4936..bc2b8e4be 100644 --- a/DSCResources/MSFT_SqlScript/MSFT_SqlScript.psm1 +++ b/DSCResources/MSFT_SqlScript/MSFT_SqlScript.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlScript' + <# .SYNOPSIS Returns the current state of the SQL Server features. @@ -82,13 +84,18 @@ function Get-TargetResource $invokeParameters = @{ ServerInstance = $ServerInstance - InputFile = $GetFilePath - Credential = $Credential - Variable = $Variable - QueryTimeout = $QueryTimeout - ErrorAction = 'Stop' + InputFile = $GetFilePath + Credential = $Credential + Variable = $Variable + QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference + ErrorAction = 'Stop' } + Write-Verbose -Message ( + $script:localizedData.ExecutingGetScript -f $GetFilePath, $ServerInstance + ) + $result = Invoke-SqlScript @invokeParameters $getResult = Out-String -InputObject $result @@ -176,13 +183,18 @@ function Set-TargetResource $Variable ) + Write-Verbose -Message ( + $script:localizedData.ExecutingSetScript -f $SetFilePath, $ServerInstance + ) + $invokeParameters = @{ ServerInstance = $ServerInstance - InputFile = $SetFilePath - Credential = $Credential - Variable = $Variable - QueryTimeout = $QueryTimeout - ErrorAction = 'Stop' + InputFile = $SetFilePath + Credential = $Credential + Variable = $Variable + QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference + ErrorAction = 'Stop' } Invoke-SqlScript @invokeParameters @@ -259,25 +271,42 @@ function Test-TargetResource $Variable ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration + ) + try { + Write-Verbose -Message ( + $script:localizedData.ExecutingTestScript -f $TestFilePath, $ServerInstance + ) + $invokeParameters = @{ ServerInstance = $ServerInstance - InputFile = $TestFilePath - Credential = $Credential - Variable = $Variable - QueryTimeout = $QueryTimeout - ErrorAction = 'Stop' + InputFile = $TestFilePath + Credential = $Credential + Variable = $Variable + QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference + ErrorAction = 'Stop' } $result = Invoke-SqlScript @invokeParameters if ($null -eq $result) { + Write-Verbose -Message ( + $script:localizedData.InDesiredState + ) + return $true } else { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState + ) + return $false } } diff --git a/DSCResources/MSFT_SqlScript/en-US/MSFT_SqlScript.strings.psd1 b/DSCResources/MSFT_SqlScript/en-US/MSFT_SqlScript.strings.psd1 new file mode 100644 index 000000000..dbc267805 --- /dev/null +++ b/DSCResources/MSFT_SqlScript/en-US/MSFT_SqlScript.strings.psd1 @@ -0,0 +1,8 @@ +ConvertFrom-StringData @' + ExecutingGetScript = Executing the Get script from the file path '{0}' on the instance '{1}'. + ExecutingSetScript = Executing the Set script from the file path '{0}' on the instance '{1}'. + ExecutingTestScript = Executing the Test script from the file path '{0}' on the instance '{1}'. + TestingConfiguration = Determines if the configuration in the Set script is in desired state. + InDesiredState = The configuration is in desired state. + NotInDesiredState = The configuration is not in desired state. +'@ diff --git a/DSCResources/MSFT_SqlScriptQuery/MSFT_SqlScriptQuery.psm1 b/DSCResources/MSFT_SqlScriptQuery/MSFT_SqlScriptQuery.psm1 index 6a88c1b54..0a55000d1 100644 --- a/DSCResources/MSFT_SqlScriptQuery/MSFT_SqlScriptQuery.psm1 +++ b/DSCResources/MSFT_SqlScriptQuery/MSFT_SqlScriptQuery.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlScriptQuery' + <# .SYNOPSIS Returns the current state of the SQL Server features. @@ -80,12 +82,17 @@ function Get-TargetResource $Variable ) + Write-Verbose -Message ( + $script:localizedData.ExecutingGetQuery -f $ServerInstance + ) + $invokeParameters = @{ Query = $GetQuery ServerInstance = $ServerInstance Credential = $Credential Variable = $Variable QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference ErrorAction = 'Stop' } @@ -176,12 +183,17 @@ function Set-TargetResource $Variable ) + Write-Verbose -Message ( + $script:localizedData.ExecutingSetQuery -f $ServerInstance + ) + $invokeParameters = @{ Query = $SetQuery ServerInstance = $ServerInstance Credential = $Credential Variable = $Variable QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference ErrorAction = 'Stop' } @@ -259,14 +271,23 @@ function Test-TargetResource $Variable ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration + ) + try { + Write-Verbose -Message ( + $script:localizedData.ExecutingTestQuery -f $ServerInstance + ) + $invokeParameters = @{ Query = $TestQuery ServerInstance = $ServerInstance Credential = $Credential Variable = $Variable QueryTimeout = $QueryTimeout + Verbose = $VerbosePreference ErrorAction = 'Stop' } @@ -274,10 +295,18 @@ function Test-TargetResource if ($null -eq $result) { + Write-Verbose -Message ( + $script:localizedData.InDesiredState + ) + return $true } else { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState + ) + return $false } } diff --git a/DSCResources/MSFT_SqlScriptQuery/en-US/MSFT_SqlScriptQuery.strings.psd1 b/DSCResources/MSFT_SqlScriptQuery/en-US/MSFT_SqlScriptQuery.strings.psd1 new file mode 100644 index 000000000..7b2f46709 --- /dev/null +++ b/DSCResources/MSFT_SqlScriptQuery/en-US/MSFT_SqlScriptQuery.strings.psd1 @@ -0,0 +1,8 @@ +ConvertFrom-StringData @' + ExecutingGetQuery = Executing the Get query on the instance '{0}'. + ExecutingSetQuery = Executing the Set query on the instance '{0}'. + ExecutingTestQuery = Executing the Test query on the instance '{0}'. + TestingConfiguration = Determines if the configuration in the Set query is in desired state. + InDesiredState = The configuration is in desired state. + NotInDesiredState = The configuration is not in desired state. +'@ diff --git a/DSCResources/MSFT_SqlServerEndpoint/MSFT_SqlServerEndpoint.psm1 b/DSCResources/MSFT_SqlServerEndpoint/MSFT_SqlServerEndpoint.psm1 index 927d250f2..4b7e3e698 100644 --- a/DSCResources/MSFT_SqlServerEndpoint/MSFT_SqlServerEndpoint.psm1 +++ b/DSCResources/MSFT_SqlServerEndpoint/MSFT_SqlServerEndpoint.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerEndpoint' + <# .SYNOPSIS Returns the current state of the endpoint. @@ -39,6 +41,10 @@ function Get-TargetResource $InstanceName ) + Write-Verbose -Message ( + $script:localizedData.GetEndpoint -f $EndpointName, $InstanceName + ) + $getTargetResourceReturnValues = @{ ServerName = $ServerName InstanceName = $InstanceName @@ -52,16 +58,17 @@ function Get-TargetResource $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message ('Connected to {0}\{1}' -f $ServerName, $InstanceName) + Write-Verbose -Message ( + $script:localizedData.ConnectedToInstance -f $ServerName, $InstanceName + ) $endpointObject = $sqlServerObject.Endpoints[$EndpointName] if ($endpointObject.Name -eq $EndpointName) { if ($sqlServerObject.Endpoints[$EndPointName].EndpointType -ne 'DatabaseMirroring') { - throw New-TerminatingError -ErrorType EndpointFoundButWrongType ` - -FormatArgs @($EndpointName) ` - -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.EndpointFoundButWrongType -f $EndpointName + New-InvalidOperationException -Message $errorMessage } $getTargetResourceReturnValues.Ensure = 'Present' @@ -81,9 +88,8 @@ function Get-TargetResource } else { - throw New-TerminatingError -ErrorType NotConnectedToInstance ` - -FormatArgs @($ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.NotConnectedToInstance -f $ServerName, $InstanceName + New-InvalidOperationException -Message $errorMessage } return $getTargetResourceReturnValues @@ -156,7 +162,9 @@ function Set-TargetResource { if ($Ensure -eq 'Present' -and $getTargetResourceResult.Ensure -eq 'Absent') { - Write-Verbose -Message ('Creating endpoint {0}.' -f $EndpointName) + Write-Verbose -Message ( + $script:localizedData.CreateEndpoint -f $EndpointName, $InstanceName + ) $endpointObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Endpoint -ArgumentList $sqlServerObject, $EndpointName $endpointObject.EndpointType = [Microsoft.SqlServer.Management.Smo.EndpointType]::DatabaseMirroring @@ -177,56 +185,72 @@ function Set-TargetResource } elseif ($Ensure -eq 'Present' -and $getTargetResourceResult.Ensure -eq 'Present') { + Write-Verbose -Message ( + $script:localizedData.SetEndpoint -f $EndpointName, $InstanceName + ) + # The endpoint already exist, verifying supported endpoint properties so they are in desired state. $endpointObject = $sqlServerObject.Endpoints[$EndpointName] if ($endpointObject) { if ($endpointObject.Protocol.Tcp.ListenerIPAddress -ne $IpAddress) { - Write-Verbose -Message ('Updating endpoint {0} IP address to {1}.' -f $EndpointName, $IpAddress) + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointIPAddress -f $IpAddress + ) + $endpointObject.Protocol.Tcp.ListenerIPAddress = $IpAddress $endpointObject.Alter() } if ($endpointObject.Protocol.Tcp.ListenerPort -ne $Port) { - Write-Verbose -Message ('Updating endpoint {0} port to {1}.' -f $EndpointName, $Port) + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointPort -f $Port + ) + $endpointObject.Protocol.Tcp.ListenerPort = $Port $endpointObject.Alter() } if ($endpointObject.Owner -ne $Owner) { - Write-Verbose -Message ('Updating endpoint {0} Owner to {1}.' -f $EndpointName, $Owner) + Write-Verbose -Message ( + $script:localizedData.UpdatingEndpointOwner -f $Owner + ) + $endpointObject.Owner = $Owner $endpointObject.Alter() } } else { - throw New-TerminatingError -ErrorType EndpointNotFound -FormatArgs @($EndpointName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.EndpointNotFound -f $EndpointName + New-ObjectNotFoundException -Message $errorMessage } } elseif ($Ensure -eq 'Absent' -and $getTargetResourceResult.Ensure -eq 'Present') { - Write-Verbose -Message ('Dropping endpoint {0}.' -f $EndpointName) - $endpointObject = $sqlServerObject.Endpoints[$EndpointName] if ($endpointObject) { + Write-Verbose -Message ( + $script:localizedData.DropEndpoint -f $EndpointName, $InstanceName + ) + $endpointObject.Drop() } else { - throw New-TerminatingError -ErrorType EndpointNotFound -FormatArgs @($EndpointName) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.EndpointNotFound -f $EndpointName + New-ObjectNotFoundException -Message $errorMessage } } } else { - throw New-TerminatingError -ErrorType NotConnectedToInstance ` - -FormatArgs @($ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation + $errorMessage = $script:localizedData.NotConnectedToInstance -f $ServerName, $InstanceName + New-InvalidOperationException -Message $errorMessage } } @@ -291,6 +315,10 @@ function Test-TargetResource $Owner ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $EndpointName, $InstanceName + ) + $getTargetResourceResult = Get-TargetResource -EndpointName $EndpointName -ServerName $ServerName -InstanceName $InstanceName if ($getTargetResourceResult.Ensure -eq $Ensure) { @@ -317,6 +345,19 @@ function Test-TargetResource $result = $false } + if ($result) + { + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $EndpointName + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState -f $EndpointName + ) + } + return $result } diff --git a/DSCResources/MSFT_SqlServerEndpoint/en-US/MSFT_SqlServerEndpoint.strings.psd1 b/DSCResources/MSFT_SqlServerEndpoint/en-US/MSFT_SqlServerEndpoint.strings.psd1 new file mode 100644 index 000000000..fc20c5c6f --- /dev/null +++ b/DSCResources/MSFT_SqlServerEndpoint/en-US/MSFT_SqlServerEndpoint.strings.psd1 @@ -0,0 +1,16 @@ +ConvertFrom-StringData @' + GetEndpoint = Getting the current values of the endpoint with the name '{0}' for the instance '{1}'. + EndpointFoundButWrongType = Endpoint '{0}' does exist, but it is not of type 'DatabaseMirroring'. + ConnectedToInstance = Connect to the instance '{0}\\{1}'. + NotConnectedToInstance = Was unable to connect to the instance '{0}\\{1}'. + SetEndpoint = Changing the values of the endpoint with the name '{0}' for the instance '{1}'. + CreateEndpoint = Creating the endpoint '{0}' on the instance '{1}'. + UpdatingEndpointIPAddress = Updating the endpoint IP address to '{0}'. + UpdatingEndpointPort = Updating the endpoint port to '{0}'. + UpdatingEndpointOwner = Updating the endpoint owner to '{0}'. + EndpointNotFound = The endpoint with the name '{0}' does not exist. + DropEndpoint = Removing the endpoint '{0}' on the instance '{1}'. + TestingConfiguration = Determines if the endpoint with the name '{0}' for the instance '{1}' is in desired state. + InDesiredState = The endpoint '{0}' is the desired state. + NotInDesiredState = The endpoint '{0}' is not in the desired state. +'@ diff --git a/DSCResources/MSFT_SqlServerEndpointPermission/MSFT_SqlServerEndpointPermission.psm1 b/DSCResources/MSFT_SqlServerEndpointPermission/MSFT_SqlServerEndpointPermission.psm1 index 5c8b5a060..1c7853c60 100644 --- a/DSCResources/MSFT_SqlServerEndpointPermission/MSFT_SqlServerEndpointPermission.psm1 +++ b/DSCResources/MSFT_SqlServerEndpointPermission/MSFT_SqlServerEndpointPermission.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerEndpointPermission' + <# .SYNOPSIS Returns the current state of the permissions for the principal (login). @@ -46,6 +48,10 @@ function Get-TargetResource $Principal ) + Write-Verbose -Message ( + $script:localizedData.GetEndpointPermission -f $EndpointName, $InstanceName + ) + try { $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -53,11 +59,14 @@ function Get-TargetResource $endpointObject = $sqlServerObject.Endpoints[$Name] if ( $null -ne $endpointObject ) { - New-VerboseMessage -Message "Enumerating permissions for endpoint $Name" + $permissionSet = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.ObjectPermissionSet' -Property @{ + Connect = $true + } - $permissionSet = New-Object -Property @{ Connect = $true } -TypeName Microsoft.SqlServer.Management.Smo.ObjectPermissionSet + $endpointPermission = $endpointObject.EnumObjectPermissions($permissionSet) | Where-Object -FilterScript { + $_.PermissionState -eq 'Grant' -and $_.Grantee -eq $Principal + } - $endpointPermission = $endpointObject.EnumObjectPermissions( $permissionSet ) | Where-Object { $_.PermissionState -eq "Grant" -and $_.Grantee -eq $Principal } if ($endpointPermission.Count -ne 0) { $Ensure = 'Present' @@ -71,12 +80,14 @@ function Get-TargetResource } else { - throw New-TerminatingError -ErrorType EndpointNotFound -FormatArgs @($Name) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.EndpointNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } } catch { - throw New-TerminatingError -ErrorType UnexpectedErrorFromGet -FormatArgs @($Name) -ErrorCategory ObjectNotFound -InnerException $_.Exception + $errorMessage = $script:localizedData.UnexpectedErrorFromGet -f $Name + New-ObjectNotFoundException -Message $errorMessage -ErrorRecord $_ } return @{ @@ -153,33 +164,47 @@ function Set-TargetResource $getTargetResourceResult = Get-TargetResource @parameters if ($getTargetResourceResult.Ensure -ne $Ensure) { + Write-Verbose -Message ( + $script:localizedData.SetEndpointPermission -f $EndpointName, $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName $endpointObject = $sqlServerObject.Endpoints[$Name] if ($null -ne $endpointObject) { - $permissionSet = New-Object -Property @{ Connect = $true } -TypeName Microsoft.SqlServer.Management.Smo.ObjectPermissionSet + $permissionSet = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.ObjectPermissionSet' -Property @{ + Connect = $true + } if ($Ensure -eq 'Present') { - New-VerboseMessage -Message "Grant permission to $Principal on endpoint $Name" + Write-Verbose -Message ( + $script:localizedData.GrantPermission -f $Principal + ) $endpointObject.Grant($permissionSet, $Principal) } else { - New-VerboseMessage -Message "Revoke permission to $Principal on endpoint $Name" + Write-Verbose -Message ( + $script:localizedData.RevokePermission -f $Principal + ) + $endpointObject.Revoke($permissionSet, $Principal) } } else { - throw New-TerminatingError -ErrorType EndpointNotFound -FormatArgs @($Name) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.EndpointNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } } else { - New-VerboseMessage -Message "State is already $Ensure" + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name + ) } } @@ -245,11 +270,28 @@ function Test-TargetResource Principal = [System.String] $Principal } - New-VerboseMessage -Message "Testing state of endpoint permission for $Principal" + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $InstanceName + ) $getTargetResourceResult = Get-TargetResource @parameters - return $getTargetResourceResult.Ensure -eq $Ensure + $isInDesiredState = $getTargetResourceResult.Ensure -eq $Ensure + + if ($isInDesiredState) + { + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState -f $Name + ) + } + + return $isInDesiredState } Export-ModuleMember -Function *-TargetResource diff --git a/DSCResources/MSFT_SqlServerEndpointPermission/en-US/MSFT_SqlServerEndpointPermission.strings.psd1 b/DSCResources/MSFT_SqlServerEndpointPermission/en-US/MSFT_SqlServerEndpointPermission.strings.psd1 new file mode 100644 index 000000000..917c57680 --- /dev/null +++ b/DSCResources/MSFT_SqlServerEndpointPermission/en-US/MSFT_SqlServerEndpointPermission.strings.psd1 @@ -0,0 +1,11 @@ +ConvertFrom-StringData @' + GetEndpointPermission = Enumerating the current permissions for the endpoint with the name '{0}' for the instance '{1}'. + EndpointNotFound = The endpoint with the name '{0}' does not exist. + UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. + SetEndpointPermission = Changing the permissions of the endpoint with the name '{0}' for the instance '{1}'. + GrantPermission = Grant permission to '{0}'. + RevokePermission = Revoke permission for '{0}'. + InDesiredState = The endpoint '{0}' is in the desired state. + NotInDesiredState = The endpoint '{0}' is not in the desired state. + TestingConfiguration = Determines the state of the endpoint with the name '{0}' for the instance '{1}'. +'@ diff --git a/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 b/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 index 35df74894..32a509e95 100644 --- a/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 +++ b/DSCResources/MSFT_SqlServerEndpointState/MSFT_SqlServerEndpointState.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerEndpointState' + <# .SYNOPSIS Returns the current state of an endpoint. @@ -39,7 +41,9 @@ function Get-TargetResource $Name ) - New-VerboseMessage -Message "Getting state of endpoint $Name" + Write-Verbose -Message ( + $script:localizedData.GetEndpointState -f $Name, $InstanceName + ) try { @@ -49,15 +53,21 @@ function Get-TargetResource if ($null -ne $endpointObject) { $currentState = $endpointObject.EndpointState + + Write-Verbose -Message ( + $script:localizedData.CurrentState -f $currentState + ) } else { - throw New-TerminatingError -ErrorType EndpointNotFound -FormatArgs @($Name) -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.EndpointNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } } catch { - throw New-TerminatingError -ErrorType EndpointErrorVerifyExist -FormatArgs @($Name) -ErrorCategory ObjectNotFound -InnerException $_.Exception + $errorMessage = $script:localizedData.EndpointErrorVerifyExist -f $Name + New-ObjectNotFoundException -Message $errorMessage -ErrorRecord $_ } return @{ @@ -107,6 +117,10 @@ function Set-TargetResource $State = 'Started' ) + Write-Verbose -Message ( + $script:localizedData.SetEndpointState -f $Name, $InstanceName + ) + $parameters = @{ InstanceName = [System.String] $InstanceName ServerName = [System.String] $ServerName @@ -118,7 +132,9 @@ function Set-TargetResource { if ($getTargetResourceResult.State -ne $State) { - New-VerboseMessage -Message ('Changing state of endpoint ''{0}''' -f $Name) + Write-Verbose -Message ( + $script:localizedData.ChangeState -f $State + ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName @@ -129,16 +145,19 @@ function Set-TargetResource State = $State } - Set-SqlHADREndpoint @setEndpointParams -ErrorAction Stop | Out-Null + Set-SqlHADREndpoint @setEndpointParams -ErrorAction 'Stop' | Out-Null } else { - New-VerboseMessage -Message ('Endpoint ''{0}'' state is already correct.' -f $Name) + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name, $State + ) } } else { - throw New-TerminatingError -ErrorType UnexpectedErrorFromGet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.UnexpectedErrorFromGet + New-InvalidResultException -Message $errorMessage } } @@ -182,27 +201,40 @@ function Test-TargetResource $State = 'Started' ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $InstanceName + ) + $parameters = @{ InstanceName = $InstanceName ServerName = $ServerName Name = $Name } - New-VerboseMessage -Message "Testing state $State on endpoint '$Name'" - $getTargetResourceResult = Get-TargetResource @parameters if ($null -ne $getTargetResourceResult) { - $result = $false - if ($getTargetResourceResult.State -eq $State) { + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Name, $getTargetResourceResult.State + ) + $result = $true } + else + { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState -f $Name, $getTargetResourceResult.State, $State + ) + + $result = $false + } } else { - throw New-TerminatingError -ErrorType UnexpectedErrorFromGet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.UnexpectedErrorFromGet + New-InvalidResultException -Message $errorMessage } return $result diff --git a/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 b/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 new file mode 100644 index 000000000..2962cc004 --- /dev/null +++ b/DSCResources/MSFT_SqlServerEndpointState/en-US/MSFT_SqlServerEndpointState.strings.psd1 @@ -0,0 +1,12 @@ +ConvertFrom-StringData @' + GetEndpointState = Getting state of the endpoint with the name '{0}' for the instance '{1}'. + EndpointNotFound = The endpoint with the name '{0}' does not exist. + EndpointErrorVerifyExist = Unexpected result when trying to verify existence of the endpoint with the name '{0}'. + UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. + CurrentState = The current state of the endpoint is '{0}'. + SetEndpointState = Changing the state of the endpoint with the name '{0}' for the instance '{1}'. + ChangeState = Changing the state of endpoint to '{0}'. + InDesiredState = The endpoint '{0}' is in the desired state, the state is '{1}'. + NotInDesiredState = The endpoint '{0}' has the state '{1}', but expected the state to be '{2}'. + TestingConfiguration = Determines the state of the endpoint with the name '{0}' for the instance '{1}'. +'@ diff --git a/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 b/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 index 1c7269d0f..2bdce6b9c 100644 --- a/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 +++ b/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerLogin' + <# .SYNOPSIS Gets the specified login by name. @@ -39,26 +41,31 @@ function Get-TargetResource $InstanceName ) - $serverObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - - Write-Verbose 'Getting SQL logins' - New-VerboseMessage -Message "Getting the login '$Name' from '$ServerName\$InstanceName'" - - $login = $serverObject.Logins[$Name] + Write-Verbose -Message ( + $script:localizedData.GetLogin -f $Name, $ServerName, $InstanceName + ) - if ( $login ) - { - $Ensure = 'Present' - } - else + $serverObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + if ($serverObject) { - $Ensure = 'Absent' + $login = $serverObject.Logins[$Name] + + if ($login) + { + $ensure = 'Present' + } + else + { + $ensure = 'Absent' + } } - New-VerboseMessage -Message "The login '$Name' is $ensure from the '$ServerName\$InstanceName' instance." + Write-Verbose -Message ( + $script:localizedData.LoginCurrentState -f $Name, $ensure, $ServerName, $InstanceName + ) $returnValue = @{ - Ensure = $Ensure + Ensure = $ensure Name = $Name LoginType = $login.LoginType ServerName = $ServerName @@ -66,7 +73,7 @@ function Get-TargetResource Disabled = $login.IsDisabled } - if ( $login.LoginType -eq 'SqlLogin' ) + if ($login.LoginType -eq 'SqlLogin') { $returnValue.Add('LoginMustChangePassword', $login.MustChangePassword) $returnValue.Add('LoginPasswordExpirationEnabled', $login.PasswordExpirationEnabled) @@ -180,14 +187,20 @@ function Set-TargetResource { if ( $login.PasswordExpirationEnabled -ne $LoginPasswordExpirationEnabled ) { - New-VerboseMessage -Message "Setting PasswordExpirationEnabled to '$LoginPasswordExpirationEnabled' for the login '$Name' on the '$ServerName\$InstanceName' instance." + Write-Verbose -Message ( + $script:localizedData.SetPasswordExpirationEnabled -f $LoginPasswordExpirationEnabled, $Name, $ServerName, $InstanceName + ) + $login.PasswordExpirationEnabled = $LoginPasswordExpirationEnabled Update-SQLServerLogin -Login $login } if ( $login.PasswordPolicyEnforced -ne $LoginPasswordPolicyEnforced ) { - New-VerboseMessage -Message "Setting PasswordPolicyEnforced to '$LoginPasswordPolicyEnforced' for the login '$Name' on the '$ServerName\$InstanceName' instance." + Write-Verbose -Message ( + $script:localizedData.SetPasswordPolicyEnforced -f $LoginPasswordPolicyEnforced, $Name, $ServerName, $InstanceName + ) + $login.PasswordPolicyEnforced = $LoginPasswordPolicyEnforced Update-SQLServerLogin -Login $login } @@ -195,19 +208,30 @@ function Set-TargetResource # Set the password if it is specified if ( $LoginCredential ) { + Write-Verbose -Message ( + $script:localizedData.SetPassword -f $Name, $ServerName, $InstanceName + ) + Set-SQLServerLoginPassword -Login $login -SecureString $LoginCredential.Password } } if ( $PSBoundParameters.ContainsKey('Disabled') -and ($login.IsDisabled -ne $Disabled) ) { - New-VerboseMessage -Message "Setting IsDisabled to '$Disabled' for the login '$Name' on the '$ServerName\$InstanceName' instance." if ( $Disabled ) { + Write-Verbose -Message ( + $script:localizedData.SetDisabled -f $Name, $ServerName, $InstanceName + ) + $login.Disable() } else { + Write-Verbose -Message ( + $script:localizedData.SetEnabled -f $Name, $ServerName, $InstanceName + ) + $login.Enable() } } @@ -217,17 +241,21 @@ function Set-TargetResource # Some login types need additional work. These will need to be fleshed out more in the future if ( @('Certificate', 'AsymmetricKey', 'ExternalUser', 'ExternalGroup') -contains $LoginType ) { - throw New-TerminatingError -ErrorType LoginTypeNotImplemented -FormatArgs $LoginType -ErrorCategory NotImplemented + $errorMessage = $script:localizedData.LoginTypeNotImplemented -f $LoginType + New-NotImplementedException -Message $errorMessage } if ( ( $LoginType -eq 'SqlLogin' ) -and ( -not $LoginCredential ) ) { - throw New-TerminatingError -ErrorType LoginCredentialNotFound -FormatArgs $Name -ErrorCategory ObjectNotFound + $errorMessage = $script:localizedData.LoginCredentialNotFound -f $Name + New-ObjectNotFoundException -Message $errorMessage } - New-VerboseMessage -Message "Adding the login '$Name' to the '$ServerName\$InstanceName' instance." + Write-Verbose -Message ( + $script:localizedData.CreateLogin -f $Name, $LoginType, $ServerName, $InstanceName + ) - $login = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Login -ArgumentList $serverObject, $Name + $login = New-Object -TypeName 'Microsoft.SqlServer.Management.Smo.Login' -ArgumentList $serverObject, $Name $login.LoginType = $LoginType switch ($LoginType) @@ -237,7 +265,8 @@ function Set-TargetResource # Verify the instance is in Mixed authentication mode if ( $serverObject.LoginMode -notmatch 'Mixed|Normal' ) { - throw New-TerminatingError -ErrorType IncorrectLoginMode -FormatArgs $ServerName, $InstanceName, $serverObject.LoginMode -ErrorCategory NotImplemented + $errorMessage = $script:localizedData.IncorrectLoginMode -f $ServerName, $InstanceName, $serverObject.LoginMode + New-InvalidOperationException -Message $errorMessage } $login.PasswordPolicyEnforced = $LoginPasswordPolicyEnforced @@ -263,6 +292,10 @@ function Set-TargetResource # we can only disable the login once it's been created if ( $Disabled ) { + Write-Verbose -Message ( + $script:localizedData.SetDisabled -f $Name, $ServerName, $InstanceName + ) + $login.Disable() } } @@ -272,7 +305,10 @@ function Set-TargetResource { if ( $serverObject.Logins[$Name] ) { - New-VerboseMessage -Message "Dropping the login '$Name' from the '$ServerName\$InstanceName' instance." + Write-Verbose -Message ( + $script:localizedData.DropLogin -f $Name, $ServerName, $InstanceName + ) + Remove-SQLServerLogin -Login $serverObject.Logins[$Name] } } @@ -369,6 +405,10 @@ function Test-TargetResource $Disabled ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name, $ServerName, $InstanceName + ) + # Assume the test will pass $testPassed = $true @@ -382,7 +422,10 @@ function Test-TargetResource if ( $Ensure -ne $loginInfo.Ensure ) { - New-VerboseMessage -Message "The login '$Name' on the instance '$ServerName\$InstanceName' is $($loginInfo.Ensure) rather than $Ensure" + Write-Verbose -Message ( + $script:localizedData.WrongEnsureState -f $Name, $loginInfo.Ensure, $Ensure + ) + $testPassed = $false } @@ -390,13 +433,28 @@ function Test-TargetResource { if ( $LoginType -ne $loginInfo.LoginType ) { - New-VerboseMessage -Message "The login '$Name' on the instance '$ServerName\$InstanceName' is a $($loginInfo.LoginType) rather than $LoginType" + Write-Verbose -Message ( + $script:localizedData.WrongLoginType -f $Name, $loginInfo.LoginType, $LoginType + ) + $testPassed = $false } if ( $PSBoundParameters.ContainsKey('Disabled') -and ($loginInfo.Disabled -ne $Disabled) ) { - New-VerboseMessage -Message "The login '$Name' on the instance '$ServerName\$InstanceName' has IsDisabled set to $($loginInfo.Disabled) rather than $Disabled" + if ($Disabled) + { + Write-Verbose -Message ( + $script:localizedData.ExpectedDisabled -f $Name + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.ExpectedEnabled -f $Name + ) + } + $testPassed = $false } @@ -404,13 +462,37 @@ function Test-TargetResource { if ( $LoginPasswordExpirationEnabled -ne $loginInfo.LoginPasswordExpirationEnabled ) { - New-VerboseMessage -Message "The login '$Name' on the instance '$ServerName\$InstanceName' has PasswordExpirationEnabled set to $($loginInfo.LoginPasswordExpirationEnabled) rather than $LoginPasswordExpirationEnabled" + if ($LoginPasswordExpirationEnabled) + { + Write-Verbose -Message ( + $script:localizedData.ExpectedLoginPasswordExpirationEnabled -f $Name + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.ExpectedLoginPasswordExpirationDisabled -f $Name + ) + } + $testPassed = $false } if ( $LoginPasswordPolicyEnforced -ne $loginInfo.LoginPasswordPolicyEnforced ) { - New-VerboseMessage -Message "The login '$Name' on the instance '$ServerName\$InstanceName' has PasswordPolicyEnforced set to $($loginInfo.LoginPasswordPolicyEnforced) rather than $LoginPasswordPolicyEnforced" + if ($LoginPasswordPolicyEnforced) + { + Write-Verbose -Message ( + $script:localizedData.ExpectedLoginPasswordPolicyEnforcedEnabled -f $Name + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.ExpectedLoginPasswordPolicyEnforcedDisabled -f $Name + ) + } + $testPassed = $false } @@ -439,26 +521,34 @@ function Test-TargetResource #> if ((Find-ExceptionByNumber -ExceptionToSearch $_.Exception -ErrorNumber 18470)) { - New-VerboseMessage -Message "Password valid, but '$Name' is disabled." + Write-Verbose -Message ( + $script:localizedData.PasswordValidButLoginDisabled -f $Name + ) } elseif ((Find-ExceptionByNumber -ExceptionToSearch $_.Exception -ErrorNumber 18456)) { - New-VerboseMessage -Message $_.Exception.message + Write-Verbose -Message ( + '{0} {1}' -f + ($script:localizedData.PasswordValidationFailed -f $Name), + ($script:localizedData.PasswordValidationFailedMessage -f $_.Exception.message) + ) # The password was not correct, password validation failed $testPassed = $false } else { - New-VerboseMessage -Message "Unknown error: $($_.Exception.message)" - # Something else went wrong, rethrow error - throw + $errorMessage = $script:localizedData.PasswordValidationError + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } else { - New-VerboseMessage -Message "Password validation failed for the login '$Name'." + Write-Verbose -Message ( + $script:localizedData.PasswordValidationFailed -f $Name + ) + $testPassed = $false } } @@ -497,7 +587,8 @@ function Update-SQLServerLogin } catch { - throw New-TerminatingError -ErrorType AlterLoginFailed -FormatArgs $Login.Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.AlterLoginFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } finally { @@ -561,16 +652,19 @@ function New-SQLServerLogin { if ( $_.Exception.InnerException.InnerException.InnerException -match 'Password validation failed' ) { - throw New-TerminatingError -ErrorType PasswordValidationFailed -FormatArgs $Name, $_.Exception.InnerException.InnerException.InnerException -ErrorCategory SecurityError + $errorMessage = $script:localizedData.CreateLoginFailedOnPassword -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } else { - throw New-TerminatingError -ErrorType LoginCreationFailedFailedOperation -FormatArgs $Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.CreateLoginFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } catch { - throw New-TerminatingError -ErrorType LoginCreationFailedSqlNotSpecified -FormatArgs $Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.CreateLoginFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } finally { @@ -589,7 +683,8 @@ function New-SQLServerLogin } catch { - throw New-TerminatingError -ErrorType LoginCreationFailedWindowsNotSpecified -FormatArgs $Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.CreateLoginFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } finally { @@ -627,7 +722,8 @@ function Remove-SQLServerLogin } catch { - throw New-TerminatingError -ErrorType DropLoginFailed -FormatArgs $Login.Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.DropLoginFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } finally { @@ -672,16 +768,19 @@ function Set-SQLServerLoginPassword { if ( $_.Exception.InnerException.InnerException.InnerException -match 'Password validation failed' ) { - throw New-TerminatingError -ErrorType PasswordValidationFailed -FormatArgs $Name, $_.Exception.InnerException.InnerException.InnerException -ErrorCategory SecurityError + $errorMessage = $script:localizedData.SetPasswordValidationFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } else { - throw New-TerminatingError -ErrorType PasswordChangeFailed -FormatArgs $Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.SetPasswordFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } catch { - throw New-TerminatingError -ErrorType PasswordChangeFailed -FormatArgs $Name -ErrorCategory NotSpecified + $errorMessage = $script:localizedData.SetPasswordFailed -f $Login.Name + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } finally { diff --git a/DSCResources/MSFT_SqlServerLogin/en-US/MSFT_SqlServerLogin.strings.psd1 b/DSCResources/MSFT_SqlServerLogin/en-US/MSFT_SqlServerLogin.strings.psd1 new file mode 100644 index 000000000..a5d61cd0d --- /dev/null +++ b/DSCResources/MSFT_SqlServerLogin/en-US/MSFT_SqlServerLogin.strings.psd1 @@ -0,0 +1,35 @@ +# Localized resources for SqlSetup + +ConvertFrom-StringData @' + GetLogin = Getting the login '{0}' from the instance '{1}\\{2}'. + LoginCurrentState = The login '{0}' is {1} at the instance '{2}\\{3}'. + SetPasswordExpirationEnabled = Setting password expiration enabled to '{0}' for the login '{1}' on the instance '{2}\\{3}'. + SetPasswordPolicyEnforced = Setting password policy enforced to '{0}' for the login '{1}' on the instance '{2}\\{3}'. + SetPassword = Setting the password for the login '{0}' on the instance '{1}\\{2}'. + SetDisabled = Disabling the the login '{0}' on the instance '{1}\\{2}'. + SetEnabled = Enabling the the login '{0}' on the instance '{1}\\{2}'. + LoginTypeNotImplemented = The login type '{0}' is not implemented in this resource. + LoginCredentialNotFound = To create the SQL login '{0}', the login credentials must also be provided. + CreateLogin = Creating the login '{0}', with the login type '{1}', on the instance '{2}\\{3}'. + IncorrectLoginMode = The instance '{0}\\{1}' is currently in '{2}' authentication mode. To create a SQL Login, it must be set to 'Mixed' authentication mode. + DropLogin = Removing the login '{0}' from the instance '{1}\\{2}'. + TestingConfiguration = Determines if the login '{0}' at the instance '{1}\\{2}' has the correct state. + WrongEnsureState = The login '{0}' is {1}, but expected it to be {2}. + WrongLoginType = The login '{0}' has the login type '{1}', but expected it to have the login type '{2}'. + ExpectedDisabled = Expected the login '{0}' to be disabled, but it is enabled. + ExpectedEnabled = Expected the login '{0}' to be enabled, but it is disabled. + ExpectedLoginPasswordExpirationDisabled = The login '{0}' has the password expiration enabled, but expected it to be disabled. + ExpectedLoginPasswordExpirationEnabled = The login '{0}' has the password expiration disabled, but expected it to be enabled. + ExpectedLoginPasswordPolicyEnforcedDisabled = The login '{0}' has the password policy enforced enabled, but expected it to be disabled. + ExpectedLoginPasswordPolicyEnforcedEnabled = The login '{0}' has the password policy enforced disabled, but expected it to be enabled. + PasswordValidButLoginDisabled = The password for the login '{0}' is valid, but the login is disabled. + PasswordValidationFailed = The password was not correct, password validation failed for the login '{0}'. + PasswordValidationFailedMessage = The returned error message was: {0} + PasswordValidationError = Password validation failed with an error. + AlterLoginFailed = Altering the login '{0}' failed. + CreateLoginFailedOnPassword = Creation of the login '{0}' failed due to a problem with the password. + CreateLoginFailed = Creation of the login '{0}' failed. + DropLoginFailed = Removal of the login '{0}' failed. + SetPasswordValidationFailed = Setting the password failed for the login '{0}' because of password validation error. + SetPasswordFailed = Setting the password failed for the login '{0}'. +'@ diff --git a/DSCResources/MSFT_SqlServerMaxDop/MSFT_SqlServerMaxDop.psm1 b/DSCResources/MSFT_SqlServerMaxDop/MSFT_SqlServerMaxDop.psm1 index e7f84fcc9..cad9eed78 100644 --- a/DSCResources/MSFT_SqlServerMaxDop/MSFT_SqlServerMaxDop.psm1 +++ b/DSCResources/MSFT_SqlServerMaxDop/MSFT_SqlServerMaxDop.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerMaxDop' + <# .SYNOPSIS This function gets the max degree of parallelism server configuration option. @@ -34,14 +36,16 @@ function Get-TargetResource $ServerName = $env:COMPUTERNAME ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - - # Is this node actively hosting the SQL instance? - $isActiveNode = Test-ActiveNode -ServerObject $sqlServerObject + Write-Verbose -Message ( + $script:localizedData.GetConfiguration -f $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message 'Getting the max degree of parallelism server configuration option' + # Is this node actively hosting the SQL instance? + $isActiveNode = Test-ActiveNode -ServerObject $sqlServerObject + $currentMaxDop = $sqlServerObject.Configuration.MaxDegreeOfParallelism.ConfigValue } @@ -115,10 +119,12 @@ function Set-TargetResource ) $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName - if ($sqlServerObject) { - Write-Verbose -Message 'Setting the max degree of parallelism server configuration option' + Write-Verbose -Message ( + $script:localizedData.SetConfiguration -f $InstanceName + ) + switch ($Ensure) { 'Present' @@ -127,13 +133,15 @@ function Set-TargetResource { if ($MaxDop) { - throw New-TerminatingError -ErrorType MaxDopParamMustBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxDopParamMustBeNull + New-InvalidArgumentException -ArgumentName 'MaxDop' -Message $errorMessage } $targetMaxDop = Get-SqlDscDynamicMaxDop -SqlServerObject $sqlServerObject - New-VerboseMessage -Message "Dynamic MaxDop is $targetMaxDop." + + Write-Verbose -Message ( + $script:localizedData.DynamicMaxDop -f $targetMaxDop + ) } else { @@ -144,7 +152,10 @@ function Set-TargetResource 'Absent' { $targetMaxDop = 0 - New-VerboseMessage -Message 'Desired state should be absent - MAXDOP is reset to the default value.' + + Write-Verbose -Message ( + $script:localizedData.SettingDefaultValue -f $targetMaxDop + ) } } @@ -152,14 +163,15 @@ function Set-TargetResource { $sqlServerObject.Configuration.MaxDegreeOfParallelism.ConfigValue = $targetMaxDop $sqlServerObject.Alter() - New-VerboseMessage -Message "Setting MAXDOP value to $targetMaxDop." + + Write-Verbose -Message ( + $script:localizedData.ChangeValue -f $targetMaxDop + ) } catch { - throw New-TerminatingError -ErrorType MaxDopSetError ` - -FormatArgs @($ServerName, $InstanceName, $targetMaxDop) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.MaxDopSetError + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -223,7 +235,9 @@ function Test-TargetResource $ProcessOnlyOnActiveNode ) - Write-Verbose -Message 'Testing the max degree of parallelism server configuration option' + Write-Verbose -Message ( + $script:localizedData.EvaluationConfiguration -f $targetMaxDop + ) $parameters = @{ InstanceName = $InstanceName @@ -241,7 +255,10 @@ function Test-TargetResource #> if ( $ProcessOnlyOnActiveNode -and -not $getTargetResourceResult.IsActiveNode ) { - New-VerboseMessage -Message ( 'The node "{0}" is not actively hosting the instance "{1}". Exiting the test.' -f $env:COMPUTERNAME, $InstanceName ) + Write-Verbose -Message ( + $script:localizedData.NotActiveNode -f $env:COMPUTERNAME, $InstanceName + ) + return $isMaxDopInDesiredState } @@ -249,39 +266,42 @@ function Test-TargetResource { 'Absent' { - if ($getMaxDop -ne 0) + $defaultMaxDopValue = 0 + + if ($getMaxDop -ne $defaultMaxDopValue) { - New-VerboseMessage -Message "Current MaxDop is $getMaxDop should be updated to 0" + Write-Verbose -Message ( + $script:localizedData.WrongMaxDop -f $getMaxDop, $defaultMaxDopValue + ) + $isMaxDopInDesiredState = $false } } + 'Present' { if ($DynamicAlloc) { if ($MaxDop) { - throw New-TerminatingError -ErrorType MaxDopParamMustBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxDopParamMustBeNull + New-InvalidArgumentException -ArgumentName 'MaxDop' -Message $errorMessage } - $dynamicMaxDop = Get-SqlDscDynamicMaxDop - New-VerboseMessage -Message "Dynamic MaxDop is $dynamicMaxDop." + $MaxDop = Get-SqlDscDynamicMaxDop - if ($getMaxDop -ne $dynamicMaxDop) - { - New-VerboseMessage -Message "Current MaxDop is $getMaxDop should be updated to $dynamicMaxDop" - $isMaxDopInDesiredState = $false - } + Write-Verbose -Message ( + $script:localizedData.DynamicMaxDop -f $MaxDop + ) } - else + + if ($getMaxDop -ne $MaxDop) { - if ($getMaxDop -ne $MaxDop) - { - New-VerboseMessage -Message "Current MaxDop is $getMaxDop should be updated to $MaxDop" - $isMaxDopInDesiredState = $false - } + Write-Verbose -Message ( + $script:localizedData.WrongMaxDop -f $getMaxDop, $MaxDop + ) + + $isMaxDopInDesiredState = $false } } } diff --git a/DSCResources/MSFT_SqlServerMaxDop/en-US/MSFT_SqlServerMaxDop.strings.psd1 b/DSCResources/MSFT_SqlServerMaxDop/en-US/MSFT_SqlServerMaxDop.strings.psd1 new file mode 100644 index 000000000..b1c096d17 --- /dev/null +++ b/DSCResources/MSFT_SqlServerMaxDop/en-US/MSFT_SqlServerMaxDop.strings.psd1 @@ -0,0 +1,12 @@ +ConvertFrom-StringData @' + GetConfiguration = Getting the max degree of parallelism server configuration option for instance '{0}'. + SetConfiguration = Setting the max degree of parallelism server configuration option for instance '{0}'. + DynamicMaxDop = The dynamically calculated value for max degree of parallelism is '{0}'. + MaxDopParamMustBeNull = The parameter max degree of parallelism must be set to $null or not assigned if the parameter DynamicAlloc is set to $true. + MaxDopSetError = Unexpected result when trying to configure the max degree of parallelism server configuration option. + SettingDefaultValue = Desired state should be absent, so max degree of parallelism will be reset to the default value '{0}'. + ChangeValue = Changed the value for max degree of parallelism to '{0}'. + EvaluationConfiguration = Determines the current value for the max degree of parallelism server configuration option. + NotActiveNode = The node '{0}' is not actively hosting the instance '{1}'. Will always return success for this resource on this node, until this node is actively hosting the instance. + WrongMaxDop = The current value for max degree of parallelism is '{0}', but expected '{1}'. +'@ diff --git a/DSCResources/MSFT_SqlServerMemory/MSFT_SqlServerMemory.psm1 b/DSCResources/MSFT_SqlServerMemory/MSFT_SqlServerMemory.psm1 index c792f7791..83d10cb63 100644 --- a/DSCResources/MSFT_SqlServerMemory/MSFT_SqlServerMemory.psm1 +++ b/DSCResources/MSFT_SqlServerMemory/MSFT_SqlServerMemory.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerMemory' + <# .SYNOPSIS This function gets the value of the min and max memory server configuration option. @@ -35,11 +37,13 @@ function Get-TargetResource $ServerName = $env:COMPUTERNAME ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.GetMemoryValues -f $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message 'Getting the value for minimum and maximum SQL server memory.' $minMemory = $sqlServerObject.Configuration.MinServerMemory.ConfigValue $maxMemory = $sqlServerObject.Configuration.MaxServerMemory.ConfigValue @@ -123,11 +127,13 @@ function Set-TargetResource $ProcessOnlyOnActiveNode ) - $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName + Write-Verbose -Message ( + $script:localizedData.SetNewValues -f $InstanceName + ) + $sqlServerObject = Connect-SQL -ServerName $ServerName -InstanceName $InstanceName if ($sqlServerObject) { - Write-Verbose -Message 'Setting the minimum and maximum memory used by the instance.' switch ($Ensure) { 'Present' @@ -136,53 +142,67 @@ function Set-TargetResource { if ($MaxMemory) { - throw New-TerminatingError -ErrorType MaxMemoryParamMustBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxMemoryParamMustBeNull + New-InvalidArgumentException -ArgumentName 'MaxMemory' -Message $errorMessage } $MaxMemory = Get-SqlDscDynamicMaxMemory - New-VerboseMessage -Message "Dynamic maximum memory has been calculated to $($MaxMemory)MB." + + Write-Verbose -Message ( + $script:localizedData.DynamicMemoryValue -f $MaxMemory + ) } else { if (-not $MaxMemory) { - throw New-TerminatingError -ErrorType MaxMemoryParamMustNotBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxMemoryParamMustNotBeNull + New-InvalidArgumentException -ArgumentName 'MaxMemory' -Message $errorMessage } } $sqlServerObject.Configuration.MaxServerMemory.ConfigValue = $MaxMemory - New-VerboseMessage -Message "Maximum memory used by the instance has been limited to $($MaxMemory)MB." + + Write-Verbose -Message ( + $script:localizedData.DynamicMaxMemoryValue -f $InstanceName, $MaxMemory + ) + + if ($MinMemory) + { + $sqlServerObject.Configuration.MinServerMemory.ConfigValue = $MinMemory + + Write-Verbose -Message ( + $script:localizedData.MinimumMemoryLimited -f $InstanceName, $MinMemory + ) + } } 'Absent' { - $sqlServerObject.Configuration.MaxServerMemory.ConfigValue = 2147483647 - $sqlServerObject.Configuration.MinServerMemory.ConfigValue = 0 - New-VerboseMessage -Message ('Ensure is set to absent. Minimum and maximum server memory' + ` - 'values used by the instance are reset to the default values.') + $defaultMaxMemory = 2147483647 + $defaultMinMemory = 0 + + Write-Verbose -Message ( + $script:localizedData.DefaultValues -f $defaultMinMemory, $defaultMaxMemory + ) + + $sqlServerObject.Configuration.MaxServerMemory.ConfigValue = $defaultMaxMemory + $sqlServerObject.Configuration.MinServerMemory.ConfigValue = $defaultMinMemory + + Write-Verbose -Message ( + $script:localizedData.ResetDefaultValues -f $InstanceName + ) } } try { - if ($MinMemory) - { - $sqlServerObject.Configuration.MinServerMemory.ConfigValue = $MinMemory - New-VerboseMessage -Message "Minimum memory used by the instance is set to $($MinMemory)MB." - } - $sqlServerObject.Alter() } catch { - throw New-TerminatingError -ErrorType AlterServerMemoryFailed ` - -FormatArgs @($ServerName, $InstanceName) ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.AlterServerMemoryFailed -f $ServerName, $InstanceName + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } } @@ -252,7 +272,9 @@ function Test-TargetResource $ProcessOnlyOnActiveNode ) - Write-Verbose -Message 'Testing the values of the minimum and maximum memory server configuration option set to be used by the instance.' + Write-Verbose -Message ( + $script:localizedData.EvaluatingMinAndMaxMemory -f $InstanceName + ) $getTargetResourceParameters = @{ InstanceName = $InstanceName @@ -269,10 +291,12 @@ function Test-TargetResource If this is supposed to process only the active node, and this is not the active node, don't bother evaluating the test. #> - if ( $ProcessOnlyOnActiveNode -and -not $getTargetResourceResult.IsActiveNode ) + if ($ProcessOnlyOnActiveNode -and -not $getTargetResourceResult.IsActiveNode) { - # Use localization if the resource has been converted - New-VerboseMessage -Message ( 'The node "{0}" is not actively hosting the instance "{1}". Exiting the test.' -f $env:COMPUTERNAME, $InstanceName ) + Write-Verbose -Message ( + $script:localizedData.NotActiveNode -f $env:COMPUTERNAME, $InstanceName + ) + return $isServerMemoryInDesiredState } @@ -282,13 +306,19 @@ function Test-TargetResource { if ($currentMaxMemory -ne 2147483647) { - New-VerboseMessage -Message "Current maximum server memory used by the instance is $($currentMaxMemory)MB. Expected 2147483647MB." + Write-Verbose -Message ( + $script:localizedData.WrongMaximumMemory -f $currentMaxMemory, '2147483647' + ) + $isServerMemoryInDesiredState = $false } if ($currentMinMemory -ne 0) { - New-VerboseMessage -Message "Current minimum server memory used by the instance is $($currentMinMemory)MB. Expected 0MB." + Write-Verbose -Message ( + $script:localizedData.WrongMinimumMemory -f $currentMinMemory, '0' + ) + $isServerMemoryInDesiredState = $false } } @@ -299,28 +329,31 @@ function Test-TargetResource { if ($MaxMemory) { - throw New-TerminatingError -ErrorType MaxMemoryParamMustBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxMemoryParamMustBeNull + New-InvalidArgumentException -ArgumentName 'MaxMemory' -Message $errorMessage } $MaxMemory = Get-SqlDscDynamicMaxMemory - New-VerboseMessage -Message "Dynamic maximum memory has been calculated to $($MaxMemory)MB." + + Write-Verbose -Message ( + $script:localizedData.DynamicMaxMemoryValue -f $MaxMemory + ) } else { if (-not $MaxMemory) { - throw New-TerminatingError -ErrorType MaxMemoryParamMustNotBeNull ` - -FormatArgs @( $ServerName, $InstanceName ) ` - -ErrorCategory InvalidArgument + $errorMessage = $script:localizedData.MaxMemoryParamMustNotBeNull + New-InvalidArgumentException -ArgumentName 'MaxMemory' -Message $errorMessage } } if ($MaxMemory -ne $currentMaxMemory) { - New-VerboseMessage -Message ("Current maximum server memory used by the instance " + ` - "is $($currentMaxMemory)MB. Expected $($MaxMemory)MB.") + Write-Verbose -Message ( + $script:localizedData.WrongMaximumMemory -f $currentMaxMemory, $MaxMemory + ) + $isServerMemoryInDesiredState = $false } @@ -328,8 +361,10 @@ function Test-TargetResource { if ($MinMemory -ne $currentMinMemory) { - New-VerboseMessage -Message ("Current minimum server memory used by the instance " + ` - "is $($currentMinMemory)MB. Expected $($MinMemory)MB.") + Write-Verbose -Message ( + $script:localizedData.WrongMinimumMemory -f $currentMinMemory, $MinMemory + ) + $isServerMemoryInDesiredState = $false } } @@ -392,9 +427,8 @@ function Get-SqlDscDynamicMaxMemory } catch { - throw New-TerminatingError -ErrorType ErrorGetDynamicMaxMemory ` - -ErrorCategory InvalidOperation ` - -InnerException $_.Exception + $errorMessage = $script:localizedData.ErrorGetDynamicMaxMemory + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } $maxMemory diff --git a/DSCResources/MSFT_SqlServerMemory/en-US/MSFT_SqlServerMemory.strings.psd1 b/DSCResources/MSFT_SqlServerMemory/en-US/MSFT_SqlServerMemory.strings.psd1 new file mode 100644 index 000000000..c33a7fec5 --- /dev/null +++ b/DSCResources/MSFT_SqlServerMemory/en-US/MSFT_SqlServerMemory.strings.psd1 @@ -0,0 +1,17 @@ +ConvertFrom-StringData @' + GetMemoryValues = Getting the current values for minimum and maximum SQL server memory for instance '{0}'. + SetNewValues = Setting the minimum and maximum memory that will be used by the instance '{0}'. + MaxMemoryParamMustBeNull = The parameter MaxMemory must be null when the parameter DynamicAlloc is set to true. + MaxMemoryParamMustNotBeNull = The parameter MaxMemory must not be null when the parameter DynamicAlloc is set to false. + DynamicMaxMemoryValue = Dynamic maximum memory has been calculated to {0}MB. + MaximumMemoryLimited = Maximum memory used by the instance '{0}' has been limited to {1}MB. + MinimumMemoryLimited = Minimum memory used by the instance '{0}' has been set to {1}MB. + DefaultValues = Resetting to the default values; MinMemory = {0}, MaxMemory = {1}. + ResetDefaultValues = Minimum and maximum server memory values used by the instance {0} has been reset to the default values. + AlterServerMemoryFailed = Failed to alter the server configuration memory for {0}\\{1}. + ErrorGetDynamicMaxMemory = Failed to calculate dynamically the maximum memory. + EvaluatingMinAndMaxMemory = Determines the values of the minimum and maximum memory server configuration option for the instance '{0}'. + NotActiveNode = The node '{0}' is not actively hosting the instance '{1}'. Will always return success for this resource on this node, until this node is actively hosting the instance. + WrongMaximumMemory = Current maximum server memory used by the instance is {0}MB, but expected {1}MB. + WrongMinimumMemory = Current minimum server memory used by the instance is {0}MB, but expected {1}MB. +'@ diff --git a/DSCResources/MSFT_SqlServerPermission/MSFT_SqlServerPermission.psm1 b/DSCResources/MSFT_SqlServerPermission/MSFT_SqlServerPermission.psm1 index e458479a7..fdad8738d 100644 --- a/DSCResources/MSFT_SqlServerPermission/MSFT_SqlServerPermission.psm1 +++ b/DSCResources/MSFT_SqlServerPermission/MSFT_SqlServerPermission.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerPermission' + <# .SYNOPSIS Returns the current state of the permissions for the principal (login). @@ -47,7 +49,9 @@ function Get-TargetResource $Permission ) - New-VerboseMessage -Message "Enumerating permissions for $Principal" + Write-Verbose -Message ( + $script:localizedData.EnumeratingPermission -f $Principal + ) try { @@ -83,7 +87,8 @@ function Get-TargetResource } catch { - throw New-TerminatingError -ErrorType PermissionGetError -FormatArgs @($Principal) -ErrorCategory InvalidOperation -InnerException $_.Exception + $errorMessage = $script:localizedData.PermissionGetError -f $Principal + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } return @{ @@ -161,25 +166,32 @@ function Set-TargetResource if ($Ensure -eq 'Present') { - Write-Verbose -Message ('Grant permission for ''{0}''' -f $Principal) + Write-Verbose -Message ( + $script:localizedData.GrantPermission -f $Principal + ) $sqlServerObject.Grant($permissionSet, $Principal) } else { - Write-Verbose -Message ('Revoke permission for ''{0}''' -f $Principal) + Write-Verbose -Message ( + $script:localizedData.RevokePermission -f $Principal + ) $sqlServerObject.Revoke($permissionSet, $Principal) } } catch { - throw New-TerminatingError -ErrorType ChangingPermissionFailed -FormatArgs @($Principal) -ErrorCategory InvalidOperation -InnerException $_.Exception + $errorMessage = $script:localizedData.ChangingPermissionFailed -f $Principal + New-InvalidOperationException -Message $errorMessage -ErrorRecord $_ } } else { - New-VerboseMessage -Message "State is already $Ensure" + Write-Verbose -Message ( + $script:localizedData.InDesiredState -f $Ensure + ) } } @@ -238,7 +250,9 @@ function Test-TargetResource Permission = $Permission } - New-VerboseMessage -Message "Verifying permissions for $Principal" + Write-Verbose -Message ( + $script:localizedData.EvaluatingPermission -f $Principal + ) $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters diff --git a/DSCResources/MSFT_SqlServerPermission/en-US/MSFT_SqlServerPermission.strings.psd1 b/DSCResources/MSFT_SqlServerPermission/en-US/MSFT_SqlServerPermission.strings.psd1 new file mode 100644 index 000000000..df3d1217a --- /dev/null +++ b/DSCResources/MSFT_SqlServerPermission/en-US/MSFT_SqlServerPermission.strings.psd1 @@ -0,0 +1,9 @@ +ConvertFrom-StringData @' + EnumeratingPermission = Enumerating permissions for '{0}'. + GrantPermission = Grant permission for '{0}'. + RevokePermission = Revoke permission for '{0}'. + ChangingPermissionFailed = Changing permission for principal '{0}' failed. + PermissionGetError = Unexpected result when trying to get permissions for '{0}'. + InDesiredState = The state is already {0}. + EvaluatingPermission = Determines the permissions for the principal '{0}'. +'@ diff --git a/DSCResources/MSFT_SqlServerReplication/MSFT_SqlServerReplication.psm1 b/DSCResources/MSFT_SqlServerReplication/MSFT_SqlServerReplication.psm1 index a4be6d8a9..548a266af 100644 --- a/DSCResources/MSFT_SqlServerReplication/MSFT_SqlServerReplication.psm1 +++ b/DSCResources/MSFT_SqlServerReplication/MSFT_SqlServerReplication.psm1 @@ -1,10 +1,22 @@ +$script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent +$script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules' + +$script:localizationModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.LocalizationHelper' +Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'DscResource.LocalizationHelper.psm1') + +$script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' +Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') + +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerReplication' + $dom = [AppDomain]::CreateDomain('SqlServerReplication') function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, @@ -44,7 +56,9 @@ function Get-TargetResource $UninstallWithForce = $true ) - $Ensure = 'Absent' + Write-Verbose -Message ( + $script:localizedData.GetCurrentState -f $InstanceName + ) $sqlMajorVersion = Get-SqlServerMajorVersion -InstanceName $InstanceName $localSqlName = Get-SqlLocalServerName -InstanceName $InstanceName @@ -52,31 +66,45 @@ function Get-TargetResource $localServerConnection = New-ServerConnection -SqlMajorVersion $sqlMajorVersion -SqlServerName $localSqlName $localReplicationServer = New-ReplicationServer -SqlMajorVersion $sqlMajorVersion -ServerConnection $localServerConnection + $currentEnsure = 'Present' + if ($localReplicationServer.IsDistributor -eq $true) { - $Ensure = 'Present' - $DistributorMode = 'Local' + $currentDistributorMode = 'Local' } elseif ($localReplicationServer.IsPublisher -eq $true) { - $Ensure = 'Present' - $DistributorMode = 'Remote' + $currentDistributorMode = 'Remote' + } + else + { + $currentEnsure = 'Absent' } - if ($Ensure -eq 'Present') + if ($currentEnsure -eq 'Present') + { + Write-Verbose -Message ( + $script:localizedData.DistributorMode -f $DistributorMode, $InstanceName + ) + + $currentDistributionDBName = $localReplicationServer.DistributionDatabase + $currentRemoteDistributor = $localReplicationServer.DistributionServer + $currentWorkingDirectory = $localReplicationServer.WorkingDirectory + } + else { - $DistributionDBName = $localReplicationServer.DistributionDatabase - $RemoteDistributor = $localReplicationServer.DistributionServer - $WorkingDirectory = $localReplicationServer.WorkingDirectory + Write-Verbose -Message ( + $script:localizedData.NoDistributorMode -f $InstanceName + ) } $returnValue = @{ InstanceName = $InstanceName - Ensure = $Ensure - DistributorMode = $DistributorMode - DistributionDBName = $DistributionDBName - RemoteDistributor = $RemoteDistributor - WorkingDirectory = $WorkingDirectory + Ensure = $currentEnsure + DistributorMode = $currentDistributorMode + DistributionDBName = $currentDistributionDBName + RemoteDistributor = $currentRemoteDistributor + WorkingDirectory = $currentWorkingDirectory } return $returnValue @@ -85,7 +113,8 @@ function Get-TargetResource function Set-TargetResource { [CmdletBinding()] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, @@ -127,7 +156,8 @@ function Set-TargetResource if (($DistributorMode -eq 'Remote') -and (-not $RemoteDistributor)) { - throw "RemoteDistributor parameter cannot be empty when DistributorMode = 'Remote'!" + $errorMessage = $script:localizedData.NoRemoteDistributor + New-InvalidArgumentException -ArgumentName 'RemoteDistributor' -Message $errorMessage } $sqlMajorVersion = Get-SqlServerMajorVersion -InstanceName $InstanceName @@ -140,7 +170,9 @@ function Set-TargetResource { if ($DistributorMode -eq 'Local' -and $localReplicationServer.IsDistributor -eq $false) { - Write-Verbose "Local distribution will be configured ..." + Write-Verbose -Message ( + $script:localizedData.ConfigureLocalDistributor + ) $distributionDB = New-DistributionDatabase ` -SqlMajorVersion $sqlMajorVersion ` @@ -163,7 +195,9 @@ function Set-TargetResource if ($DistributorMode -eq 'Remote' -and $localReplicationServer.IsPublisher -eq $false) { - Write-Verbose "Remote distribution will be configured ..." + Write-Verbose -Message ( + $script:localizedData.ConfigureRemoteDistributor + ) $remoteConnection = New-ServerConnection -SqlMajorVersion $sqlMajorVersion -SqlServerName $RemoteDistributor @@ -185,12 +219,17 @@ function Set-TargetResource { if ($localReplicationServer.IsDistributor -eq $true -or $localReplicationServer.IsPublisher -eq $true) { - Write-Verbose "Distribution will be removed ..." + Write-Verbose -Message ( + $script:localizedData.RemoveDistributor + ) + Uninstall-Distributor -ReplicationServer $localReplicationServer -UninstallWithForce $UninstallWithForce } else { - Write-Verbose "Distribution is not configured on this instance." + Write-Verbose -Message ( + $script:localizedData.NoDistributorMode -f $InstanceName + ) } } } @@ -199,7 +238,8 @@ function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $InstanceName, @@ -239,6 +279,10 @@ function Test-TargetResource $UninstallWithForce = $true ) + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration + ) + $result = $false $state = Get-TargetResource @PSBoundParameters @@ -259,7 +303,8 @@ function New-ServerConnection { [CmdletBinding()] [OutputType([System.Object])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, @@ -279,7 +324,8 @@ function New-ReplicationServer { [CmdletBinding()] [OutputType([System.Object])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, @@ -299,7 +345,8 @@ function New-DistributionDatabase { [CmdletBinding()] [OutputType([System.Object])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, @@ -314,7 +361,11 @@ function New-DistributionDatabase ) $rmo = Get-RmoAssembly -SqlMajorVersion $SqlMajorVersion - Write-Verbose "Creating DistributionDatabase object $DistributionDBName" + + Write-Verbose -Message ( + $script:localizedData.CreateDistributionDatabase -f $DistributionDBName + ) + $distributionDB = New-Object $rmo.GetType('Microsoft.SqlServer.Replication.DistributionDatabase') $DistributionDBName, $ServerConnection return $distributionDB @@ -324,7 +375,8 @@ function New-DistributionPublisher { [CmdletBinding()] [OutputType([System.Object])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, @@ -347,7 +399,8 @@ function New-DistributionPublisher function Install-RemoteDistributor { [CmdletBinding()] - param( + param + ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, @@ -361,14 +414,18 @@ function Install-RemoteDistributor $AdminLinkCredentials ) - Write-Verbose "Calling InstallDistributor with RemoteDistributor = $RemoteDistributor" + Write-Verbose -Message ( + $script:localizedData.InstallRemoteDistributor -f $RemoteDistributor + ) + $ReplicationServer.InstallDistributor($RemoteDistributor, $AdminLinkCredentials.Password) } function Install-LocalDistributor { [CmdletBinding()] - param( + param + ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, @@ -382,14 +439,18 @@ function Install-LocalDistributor $DistributionDB ) - Write-Verbose "Calling method InstallDistributor() with DistributionDB" + Write-Verbose -Message ( + $script:localizedData.InstallLocalDistributor + ) + $ReplicationServer.InstallDistributor($AdminLinkCredentials.Password, $DistributionDB) } function Uninstall-Distributor { [CmdletBinding()] - param( + param + ( [Parameter(Mandatory = $true)] [System.Object] $ReplicationServer, @@ -398,14 +459,19 @@ function Uninstall-Distributor [System.Boolean] $UninstallWithForce ) - Write-Verbose 'Calling method UninstallDistributor() on ReplicationServer object' + + Write-Verbose -Message ( + $script:localizedData.UninstallDistributor + ) + $ReplicationServer.UninstallDistributor($UninstallWithForce) } function Register-DistributorPublisher { [CmdletBinding()] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion, @@ -431,7 +497,9 @@ function Register-DistributorPublisher $UseTrustedConnection ) - Write-Verbose "Creating DistributorPublisher $PublisherName on $($ServerConnection.ServerInstance)" + Write-Verbose -Message ( + $script:localizedData.CreateDistributorPublisher -f $PublisherName, $ServerConnection.ServerInstance + ) $distributorPublisher = New-DistributionPublisher ` -SqlMajorVersion $SqlMajorVersion ` @@ -448,14 +516,18 @@ function Get-ConnectionInfoAssembly { [CmdletBinding()] [OutputType([System.Reflection.Assembly])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion ) $connInfo = $dom.Load("Microsoft.SqlServer.ConnectionInfo, Version=$SqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91") - Write-Verbose "Loaded assembly: $($connInfo.FullName)" + + Write-Verbose -Message ( + $script:localizedData.LoadAssembly -f $connInfo.FullName + ) return $connInfo } @@ -464,14 +536,18 @@ function Get-RmoAssembly { [CmdletBinding()] [OutputType([System.Reflection.Assembly])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $SqlMajorVersion ) $rmo = $dom.Load("Microsoft.SqlServer.Rmo, Version=$SqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91") - Write-Verbose "Loaded assembly: $($rmo.FullName)" + + Write-Verbose -Message ( + $script:localizedData.LoadAssembly -f $rmo.FullName + ) return $rmo } @@ -480,7 +556,8 @@ function Get-SqlServerMajorVersion { [CmdletBinding()] [OutputType([System.String])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $InstanceName @@ -488,11 +565,14 @@ function Get-SqlServerMajorVersion $instanceId = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL").$InstanceName $sqlVersion = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\$instanceId\Setup").Version + $sqlMajorVersion = $sqlVersion.Split(".")[0] if (-not $sqlMajorVersion) { - throw "Unable to detect version for sql server instance: $InstanceName!" + $errorMessage = $script:localizedData.FailedToDetectSqlVersion -f $InstanceName + New-InvalidResultException -Message $errorMessage } + return $sqlMajorVersion } @@ -500,13 +580,14 @@ function Get-SqlLocalServerName { [CmdletBinding()] [OutputType([System.String])] - param( + param + ( [Parameter(Mandatory = $true)] [System.String] $InstanceName ) - if ($InstanceName -eq "MSSQLSERVER") + if ($InstanceName -eq 'MSSQLSERVER') { return $env:COMPUTERNAME } diff --git a/DSCResources/MSFT_SqlServerReplication/en-US/MSFT_SqlServerReplication.strings.psd1 b/DSCResources/MSFT_SqlServerReplication/en-US/MSFT_SqlServerReplication.strings.psd1 new file mode 100644 index 000000000..81a4ec333 --- /dev/null +++ b/DSCResources/MSFT_SqlServerReplication/en-US/MSFT_SqlServerReplication.strings.psd1 @@ -0,0 +1,17 @@ +ConvertFrom-StringData @' + GetCurrentState = Get the current state of the server replication configuration for the instance '{0}'. + DistributorMode = The distributor mode is currently '{0}' for the instance '{1}'. + NoDistributorMode = There are currently no distributor mode set for the instance '{0}'. + NoRemoteDistributor = The parameter RemoteDistributor cannot be empty when DistributorMode is set to 'Remote'. + ConfigureLocalDistributor = The local distribution will be configured. + ConfigureRemoteDistributor = The remote distribution will be configured. + RemoveDistributor = The distribution will be removed. + TestingConfiguration = Determines if the distribution is configured in desired state. + CreateDistributionDatabase = Creating the distribution database object '{0}'. + InstallRemoteDistributor = Installing the remote distributor '{0}'. + InstallLocalDistributor = Installing the local distributor. + UninstallDistributor = Uninstalling the distributor. + CreateDistributorPublisher = Creating the distributor publisher '{0}' on the instance '{1}'. + LoadAssembly = Loaded assembly: {0} + FailedToDetectSqlVersion = Unable to detect version for the SQL Server instance '{0}'. +'@ diff --git a/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.psm1 b/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.psm1 index 6eb02e3a8..9d8333dc2 100644 --- a/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.psm1 +++ b/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.psm1 @@ -26,7 +26,7 @@ $script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlServerSecureCon If Encryption should be Enabled (Present) or Disabled (Absent). .PARAMETER ServiceAccount - Name of the account running the SQL Server service. + Name of the account running the SQL Server service. If parameter is set to "LocalSystem", then a connection error is displayed. Use "SYSTEM" instead, in that case. #> function Get-TargetResource { diff --git a/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.schema.mof b/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.schema.mof index f05c80391..2be260bb6 100644 --- a/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.schema.mof +++ b/DSCResources/MSFT_SqlServerSecureConnection/MSFT_SqlServerSecureConnection.schema.mof @@ -5,7 +5,7 @@ class MSFT_SqlServerSecureConnection : OMI_BaseResource [Key, Description("Name of the SQL Server instance to be configured.")] String InstanceName; [Required, Description("Thumbprint of the certificate being used for encryption. If parameter Ensure is set to 'Absent', then the parameter Certificate can be set to an empty string.")] String Thumbprint; [Write, Description("If all connections to the SQL instance should be encrypted. If this parameter is not assigned a value, the default is, set to true, that all connections must be encrypted.")] boolean ForceEncryption; - [Required, Description("Name of the account running the SQL Server service.")] String ServiceAccount; + [Required, Description("Name of the account running the SQL Server service. If parameter is set to 'LocalSystem', then a connection error is displayed. Use 'SYSTEM' instead, in that case.")] String ServiceAccount; [Write, Description("If Encryption should be Enabled (Present) or Disabled (Absent)."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; }; diff --git a/DSCResources/MSFT_SqlSetup/en-US/MSFT_SqlSetup.strings.psd1 b/DSCResources/MSFT_SqlSetup/en-US/MSFT_SqlSetup.strings.psd1 index fbce73d37..4fcea76c2 100644 --- a/DSCResources/MSFT_SqlSetup/en-US/MSFT_SqlSetup.strings.psd1 +++ b/DSCResources/MSFT_SqlSetup/en-US/MSFT_SqlSetup.strings.psd1 @@ -42,7 +42,6 @@ ConvertFrom-StringData @' EvaluateClientToolsSdkFeature = Detecting Client Tools SDK feature ({0}). ClientToolsSdkFeatureFound = Client Tools SDK feature detected. ClientToolsSdkFeatureNotFound = Client Tools SDK feature not detected. - RobocopyIsCopying = Robocopy is copying media from source '{0}' to destination '{1}'. FeatureNotSupported = '{0}' is not a valid value for setting 'FEATURES'. Refer to SQL Help for more information. PathRequireClusterDriveFound = Found assigned parameter '{0}'. Adding path '{1}' to list of paths that required cluster drive. FailoverClusterDiskMappingError = Unable to map the specified paths to valid cluster storage. Drives mapped: {0}. @@ -56,7 +55,7 @@ ConvertFrom-StringData @' SetupFailed = Please see the 'Summary.txt' log file in the 'Setup Bootstrap\\Log' folder. Reboot = Rebooting target node. SuppressReboot = Suppressing reboot of target node. - TestFailedAfterSet = Test-TargetResource returned false after calling Set-TargetResource. + TestFailedAfterSet = Test-TargetResource function returned false when Set-TargetResource function verified the desired state. This indicates that the Set-TargetResource did not correctly set set the desired state, or that the function Test-TargetResource does not correctly evaluates the desired state. FeaturesFound = Found features already installed: {0} NoFeaturesFound = No features are installed. UnableToFindFeature = Unable to find feature '{0}' among the installed features: '{1}'. diff --git a/DSCResources/MSFT_SqlSetup/sv-SE/MSFT_SqlSetup.strings.psd1 b/DSCResources/MSFT_SqlSetup/sv-SE/MSFT_SqlSetup.strings.psd1 index ed61272c7..c688ef106 100644 --- a/DSCResources/MSFT_SqlSetup/sv-SE/MSFT_SqlSetup.strings.psd1 +++ b/DSCResources/MSFT_SqlSetup/sv-SE/MSFT_SqlSetup.strings.psd1 @@ -42,7 +42,6 @@ ConvertFrom-StringData @' EvaluateClientToolsSdkFeature = Letar efter Client Tools SDK funktionen ({0}). ClientToolsSdkFeatureFound = Client Tools SDK funktionen hittad. ClientToolsSdkFeatureNotFound = Client Tools SDK funktionen hittades inte. - RobocopyIsCopying = Robocopy kopierar media från källan '{0}' till destinationen '{1}'. FeatureNotSupported = '{0}' är inte ett giltigt värde för egenskapen 'FEATURES'. Titta i hjälpdokumentationen för SQL Server för mer information. PathRequireClusterDriveFound = Hittade tilldelad parameter '{0}'. Adderar sökväg '{1}' till listan av sökvägar som kräver en klustrad enhet. FailoverClusterDiskMappingError = Kunde inte koppla den specifika sökvägen till en giltig klusterlagring. Enheter kopplade: {0}. @@ -56,20 +55,11 @@ ConvertFrom-StringData @' SetupFailed = Vänligen titta i loggfilen 'Summary.txt' i sökvägen 'Setup Bootstrap\\Log'. Reboot = Startar om målnod. SuppressReboot = Förhindrar omstart av målnod. - TestFailedAfterSet = Test-TargetResource retunerade falskt efter anropet till Set-TargetResource. + TestFailedAfterSet = Funktionen Test-TargetResource returnerade falskt när funktionen Set-TargetResource verifierade önskad konfiguration. Detta indikerar att funktionen Set-TargetResource inte på ett korrekt sätt kunde sätta önskad konfiguration, eller att funktionen Test-TargetResource inte utvärderar önskad konfiguration på korrekt sätt. FeaturesFound = Funktioner funna: {0} UnableToFindFeature = Kunde inte hitta funktion '{0}' bland som installerade funktionerna: '{1}'. EvaluatingClusterParameters = Klustrad installation, kontrollerar parametrar. ClusterParameterIsNotInDesiredState = {0} '{1}' är inte i önskat läge för detta kluster. - RobocopyUsingUnbufferedIo = Robocopy använder sig av obuffrad I/O. - RobocopyNotUsingUnbufferedIo = Obuffrad I/O kan inte användas på grund av versionen av Robocopy inte är kompatibel. - RobocopyArguments = Robocopy startas med följande argument: {0} - RobocopyErrorCopying = Robocopy rapporterade fel när filer kopierades. Felkod: {0}. - RobocopyFailuresCopying = Robocopy rapporterade att fel uppstod när filer kopierades. Felkod: {0}. - RobocopySuccessful = Robocopy lyckades kopiera filer till destinationen. - RobocopyRemovedExtraFilesAtDestination = Robocopy fann extra filer på destinationen som inte finns i källan, dessa extra filer togs bort på destinationen. - RobocopySuccessfulAndRemovedExtraFilesAtDestination = Robocopy lyckades kopiera filer till destinationen. Robocopy fann extra filer på destinationen som inte finns i källan, dessa extra filer togs bort på destinationen. - RobocopyAllFilesPresent = Robocopy rapporterade att alla filer redan finns på destinationen. StartSetupProcess = Startade processen med id {0}, använder sig av sökvägen '{1}', och med en tidsgräns på {2} sekunder. EvaluateMasterDataServicesFeature = Letar efter Master Data Services (MDS) funktion ({0}). MasterDataServicesFeatureFound = Master Data Services (MDS) funktionen hittad. diff --git a/DSCResources/MSFT_SqlWaitForAG/MSFT_SqlWaitForAG.psm1 b/DSCResources/MSFT_SqlWaitForAG/MSFT_SqlWaitForAG.psm1 index 24b52a835..1ecdf88c1 100644 --- a/DSCResources/MSFT_SqlWaitForAG/MSFT_SqlWaitForAG.psm1 +++ b/DSCResources/MSFT_SqlWaitForAG/MSFT_SqlWaitForAG.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlWaitForAG' + <# .SYNOPSIS Returns the cluster role/group that is waiting to be created, @@ -43,13 +45,27 @@ function Get-TargetResource $RetryCount = 30 ) + Write-Verbose -Message ( + $script:localizedData.GetCurrentState -f $Name + ) + $clusterGroupFound = $false $clusterGroup = Get-ClusterGroup -Name $Name -ErrorAction SilentlyContinue if ($null -ne $clusterGroup) { + Write-Verbose -Message ( + $script:localizedData.FoundClusterGroup -f $Name + ) + $clusterGroupFound = $true } + else + { + Write-Verbose -Message ( + $script:localizedData.MissingClusterGroup -f $Name + ) + } return @{ Name = $Name @@ -93,7 +109,9 @@ function Set-TargetResource $RetryCount = 30 ) - New-VerboseMessage -Message "Checking for cluster group $Name. Will try for a total of $($RetryIntervalSec*$RetryCount) seconds." + Write-Verbose -Message ( + $script:localizedData.WaitingClusterGroup -f $Name, $RetryCount, ($RetryIntervalSec * $RetryCount) + ) $getTargetResourceParameters = @{ Name = $Name @@ -106,18 +124,29 @@ function Set-TargetResource $clusterGroupFound = (Get-TargetResource @getTargetResourceParameters).GroupExist if ($clusterGroupFound) { - New-VerboseMessage -Message "Found cluster group $Name. Will sleep for another $RetryIntervalSec seconds before continuing." + Write-Verbose -Message ( + '{0} {1}' -f ` + ($script:localizedData.FoundClusterGroup -f $Name, $RetryCount, ($RetryIntervalSec * $RetryCount)), + ($script:localizedData.SleepMessage -f $RetryIntervalSec) + ) + Start-Sleep -Seconds $RetryIntervalSec break } - New-VerboseMessage -Message "Cluster group $Name not found. Will retry again after $RetryIntervalSec sec" + Write-Verbose -Message ( + '{0} {1}' -f ` + ($script:localizedData.MissingClusterGroup -f $Name, $RetryCount, ($RetryIntervalSec * $RetryCount)), + ($script:localizedData.RetryMessage -f $RetryIntervalSec) + ) + Start-Sleep -Seconds $RetryIntervalSec } if (-not $clusterGroupFound) { - throw "Cluster group $Name not found after $RetryCount attempts with $RetryIntervalSec sec interval" + $errorMessage = $script:localizedData.FailedMessage -f $Name + New-InvalidOperationException -Message $errorMessage } } @@ -156,7 +185,9 @@ function Test-TargetResource $RetryCount = 30 ) - New-VerboseMessage -Message "Testing for cluster group $Name." + Write-Verbose -Message ( + $script:localizedData.TestingConfiguration -f $Name + ) $getTargetResourceParameters = @{ Name = $Name @@ -167,11 +198,15 @@ function Test-TargetResource $clusterGroupFound = (Get-TargetResource @getTargetResourceParameters).GroupExist if ($clusterGroupFound) { - New-VerboseMessage -Message "Found cluster group $Name" + Write-Verbose -Message ( + $script:localizedData.FoundClusterGroup -f $Name + ) } else { - New-VerboseMessage -Message "Cluster group $Name not found" + Write-Verbose -Message ( + $script:localizedData.MissingClusterGroup -f $Name + ) } return $clusterGroupFound diff --git a/DSCResources/MSFT_SqlWaitForAG/en-US/MSFT_SqlWaitForAG.strings.psd1 b/DSCResources/MSFT_SqlWaitForAG/en-US/MSFT_SqlWaitForAG.strings.psd1 new file mode 100644 index 000000000..88bbfbf71 --- /dev/null +++ b/DSCResources/MSFT_SqlWaitForAG/en-US/MSFT_SqlWaitForAG.strings.psd1 @@ -0,0 +1,10 @@ +ConvertFrom-StringData @' + GetCurrentState = Get the current state of the Always On Availability Group with the cluster group name '{0}'. + FoundClusterGroup = Found the cluster group '{0}'. + MissingClusterGroup = Did not find the cluster group '{0}'. + WaitingClusterGroup = Waiting for the Always On Availability Group with the cluster group name '{0}'. Will make {1} attempts during a total of {2} seconds. + SleepMessage = Will sleep for another {0} seconds before continuing. + RetryMessage = Will retry again after {0} seconds. + FailedMessage = Did not find the cluster group '{0}' within the timeout period. + TestingConfiguration = Determines the current state of the Always On Availability Group with the cluster group name '{0}'. +'@ diff --git a/DSCResources/MSFT_SqlWindowsFirewall/MSFT_SqlWindowsFirewall.psm1 b/DSCResources/MSFT_SqlWindowsFirewall/MSFT_SqlWindowsFirewall.psm1 index 513fe8e8d..a74de05b0 100644 --- a/DSCResources/MSFT_SqlWindowsFirewall/MSFT_SqlWindowsFirewall.psm1 +++ b/DSCResources/MSFT_SqlWindowsFirewall/MSFT_SqlWindowsFirewall.psm1 @@ -7,6 +7,8 @@ Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath ' $script:resourceHelperModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'DscResource.Common' Import-Module -Name (Join-Path -Path $script:resourceHelperModulePath -ChildPath 'DscResource.Common.psm1') +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_SqlWindowsFirewall' + <# .SYNOPSIS Returns the current state of the firewall rules. @@ -48,13 +50,23 @@ function Get-TargetResource $InstanceName = $InstanceName.ToUpper() + Write-Verbose -Message ( + $script:localizedData.EnumeratingFirewallRules -f $InstanceName + ) + $SourcePath = [Environment]::ExpandEnvironmentVariables($SourcePath) if ($SourceCredential) { + $userName = "$($SourceCredential.GetNetworkCredential().Domain)\$($SourceCredential.GetNetworkCredential().UserName)" + + Write-Verbose -Message ( + $script:localizedData.ConnectUsingCredential -f $SourcePath, $userName + ) + $newSmbMappingParameters = @{ RemotePath = $SourcePath - UserName = "$($SourceCredential.GetNetworkCredential().Domain)\$($SourceCredential.GetNetworkCredential().UserName)" + UserName = $userName Password = $($SourceCredential.GetNetworkCredential().Password) } @@ -63,10 +75,16 @@ function Get-TargetResource $pathToSetupExecutable = Join-Path -Path $SourcePath -ChildPath 'setup.exe' - New-VerboseMessage -Message "Using path: $pathToSetupExecutable" + Write-Verbose -Message ( + $script:localizedData.UsingPath -f $pathToSetupExecutable + ) $sqlVersion = Get-SqlMajorVersion -Path $pathToSetupExecutable + Write-Verbose -Message ( + $script:localizedData.MajorVersion -f $sqlVersion + ) + if ($SourceCredential) { Remove-SmbMapping -RemotePath $SourcePath -Force @@ -352,24 +370,40 @@ function Set-TargetResource $InstanceName = $InstanceName.ToUpper() + Write-Verbose -Message ( + $script:localizedData.ModifyFirewallRules -f $InstanceName + ) + $SourcePath = [Environment]::ExpandEnvironmentVariables($SourcePath) if ($SourceCredential) { + $userName = "$($SourceCredential.GetNetworkCredential().Domain)\$($SourceCredential.GetNetworkCredential().UserName)" + + Write-Verbose -Message ( + $script:localizedData.ConnectUsingCredential -f $SourcePath, $userName + ) + $newSmbMappingParameters = @{ RemotePath = $SourcePath - UserName = "$($SourceCredential.GetNetworkCredential().Domain)\$($SourceCredential.GetNetworkCredential().UserName)" + UserName = $userName Password = $($SourceCredential.GetNetworkCredential().Password) } $null = New-SmbMapping @newSmbMappingParameters } - $path = Join-Path -Path $SourcePath -ChildPath 'setup.exe' + $pathToSetupExecutable = Join-Path -Path $SourcePath -ChildPath 'setup.exe' + + Write-Verbose -Message ( + $script:localizedData.UsingPath -f $pathToSetupExecutable + ) - New-VerboseMessage -Message "Using path: $path" + $sqlVersion = Get-SqlMajorVersion -Path $pathToSetupExecutable - $sqlVersion = Get-SqlMajorVersion -Path $path + Write-Verbose -Message ( + $script:localizedData.MajorVersion -f $sqlVersion + ) if ($SourceCredential) { @@ -558,7 +592,8 @@ function Set-TargetResource if (-not (Test-TargetResource -SourcePath $SourcePath -Features $Features -InstanceName $InstanceName)) { - throw New-TerminatingError -ErrorType TestFailedAfterSet -ErrorCategory InvalidResult + $errorMessage = $script:localizedData.TestFailedAfterSet + New-InvalidResultException -Message $errorMessage } } @@ -609,9 +644,28 @@ function Test-TargetResource $SourceCredential ) + Write-Verbose -Message ( + $script:localizedData.EvaluatingFirewallRules -f $sqlVersion + ) + $getTargetResourceResult = Get-TargetResource -SourcePath $SourcePath -Features $Features -InstanceName $InstanceName - return ($getTargetResourceResult.Ensure -eq $Ensure) + $isInDesiredState = $getTargetResourceResult.Ensure -eq $Ensure + + if ($isInDesiredState) + { + Write-Verbose -Message ( + $script:localizedData.InDesiredState + ) + } + else + { + Write-Verbose -Message ( + $script:localizedData.NotInDesiredState + ) + } + + return $isInDesiredState } <# @@ -747,13 +801,13 @@ function Test-IsFirewallRuleInDesiredState $isRuleInDesiredState = $false - if ($firewallRule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction SilentlyContinue) + if ($firewallRule = Get-NetFirewallRule -DisplayName $DisplayName -ErrorAction 'SilentlyContinue') { if (($firewallRule.Enabled -eq $Enabled) -and ($firewallRule.Profile -eq $Profile) -and ($firewallRule.Direction -eq $Direction)) { if ($PSBoundParameters.ContainsKey('Program')) { - if ($firewallApplicationFilter = Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction SilentlyContinue) + if ($firewallApplicationFilter = Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction 'SilentlyContinue') { if ($firewallApplicationFilter.Program -eq $Program) { @@ -764,7 +818,7 @@ function Test-IsFirewallRuleInDesiredState if ($PSBoundParameters.ContainsKey('Service')) { - if ($firewallServiceFilter = Get-NetFirewallServiceFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction SilentlyContinue) + if ($firewallServiceFilter = Get-NetFirewallServiceFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction 'SilentlyContinue') { if ($firewallServiceFilter.Service -eq $Service) { @@ -775,7 +829,7 @@ function Test-IsFirewallRuleInDesiredState if ($PSBoundParameters.ContainsKey('Protocol') -and $PSBoundParameters.ContainsKey('LocalPort')) { - if ($firewallPortFilter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction SilentlyContinue) + if ($firewallPortFilter = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $firewallRule -ErrorAction 'SilentlyContinue') { if ($firewallPortFilter.Protocol -eq $Protocol -and $firewallPortFilter.LocalPort -eq $LocalPort) { diff --git a/DSCResources/MSFT_SqlWindowsFirewall/en-US/MSFT_SqlWindowsFirewall.strings.psd1 b/DSCResources/MSFT_SqlWindowsFirewall/en-US/MSFT_SqlWindowsFirewall.strings.psd1 new file mode 100644 index 000000000..1a7e6bd3b --- /dev/null +++ b/DSCResources/MSFT_SqlWindowsFirewall/en-US/MSFT_SqlWindowsFirewall.strings.psd1 @@ -0,0 +1,11 @@ +ConvertFrom-StringData @' + EnumeratingFirewallRules = Enumerating firewall rules for instance '{0}'. + ConnectUsingCredential = Connecting to the path '{0}' using the credential '{1}' through SMB. + UsingPath = Using the executable at '{0}' to determine the SQL Server major version. + MajorVersion = The SQL Server major version is '{0}'. + ModifyFirewallRules = Modifying firewall rules for instance '{0}'. + TestFailedAfterSet = Test-TargetResource function returned false when Set-TargetResource function verified the desired state. This indicates that the Set-TargetResource did not correctly set set the desired state, or that the function Test-TargetResource does not correctly evaluates the desired state. + EvaluatingFirewallRules = Determines if the firewall rules are in desired state for the instance '{0}'. + InDesiredState = The firewall rules are in desired state. + NotInDesiredState = The firewall rules are not in desired state. +'@ diff --git a/Examples/Resources/SqlServerSecureConnection/2-SecureConnectionNotForced.ps1 b/Examples/Resources/SqlServerSecureConnection/2-SecureConnectionNotForced.ps1 index 0e544b0cb..7d8382f97 100644 --- a/Examples/Resources/SqlServerSecureConnection/2-SecureConnectionNotForced.ps1 +++ b/Examples/Resources/SqlServerSecureConnection/2-SecureConnectionNotForced.ps1 @@ -1,6 +1,6 @@ <# .EXAMPLE - This example performs a standard Sql encryption setup. Forcing all connections to be encrypted. + This example performs a standard Sql encryption setup. All connections are not forced to be encrypted. #> Configuration Example { diff --git a/Examples/Resources/SqlServerSecureConnection/4-SecureConnectionUsingSYSTEMAccount.ps1 b/Examples/Resources/SqlServerSecureConnection/4-SecureConnectionUsingSYSTEMAccount.ps1 new file mode 100644 index 000000000..ab4f2c70f --- /dev/null +++ b/Examples/Resources/SqlServerSecureConnection/4-SecureConnectionUsingSYSTEMAccount.ps1 @@ -0,0 +1,21 @@ +<# +.EXAMPLE + This example performs a standard Sql encryption setup using the "SYSTEM" account. + Note that the "LocalSystem" account should not be used because it returns a connection error, + even though it inherits the "SYSTEM" account's privileges. +#> +Configuration Example +{ + Import-DscResource -ModuleName SqlServerDsc + + node localhost { + SqlServerSecureConnection SecureConnectionUsingSYSTEMAccount + { + InstanceName = 'MSSQLSERVER' + Thumbprint = 'fb0b82c94b80da26cf0b86f10ec0c50ae7864a2c' + ForceEncryption = $false + Ensure = 'Present' + ServiceAccount = 'SYSTEM' + } + } +} diff --git a/Modules/DscResource.Common/DscResource.Common.psm1 b/Modules/DscResource.Common/DscResource.Common.psm1 index 203a37586..4ed14410a 100644 --- a/Modules/DscResource.Common/DscResource.Common.psm1 +++ b/Modules/DscResource.Common/DscResource.Common.psm1 @@ -340,7 +340,7 @@ function Copy-ItemWithRobocopy ArgumentList = $robocopyArgumentList } - Write-Verbose -Message ($script:localizedData.RobocopyArguments -f $robocopyArgumentList) -Verbose + Write-Verbose -Message ($script:localizedData.RobocopyArguments -f $robocopyArgumentList) -Verbose $robocopyProcess = Start-Process @robocopyStartProcessParameters -Wait -NoNewWindow -PassThru switch ($($robocopyProcess.ExitCode)) @@ -359,22 +359,24 @@ function Copy-ItemWithRobocopy 1 { - Write-Verbose -Message $script:localizedData.RobocopySuccessful -Verbose + Write-Verbose -Message $script:localizedData.RobocopySuccessful -Verbose } 2 { - Write-Verbose -Message $script:localizedData.RobocopyRemovedExtraFilesAtDestination -Verbose + Write-Verbose -Message $script:localizedData.RobocopyRemovedExtraFilesAtDestination -Verbose } 3 { - Write-Verbose -Message $script:localizedData.RobocopySuccessfulAndRemovedExtraFilesAtDestination -Verbose + Write-Verbose -Message ( + '{0} {1}' -f $script:localizedData.RobocopySuccessful, $script:localizedData.RobocopyRemovedExtraFilesAtDestination + ) -Verbose } {$_ -eq 0 -or $null -eq $_ } { - Write-Verbose -Message $script:localizedData.RobocopyAllFilesPresent -Verbose + Write-Verbose -Message $script:localizedData.RobocopyAllFilesPresent -Verbose } } } @@ -1334,15 +1336,31 @@ function Restart-ReportingServicesService $WaitTime = 0 ) - $ServiceName = 'ReportServer' - - if (-not ($SQLInstanceName -eq 'MSSQLSERVER')) + if ($SQLInstanceName -eq 'SSRS') { - $ServiceName += '${0}' -f $SQLInstanceName + # Check if we're dealing with SSRS 2017 + $ServiceName = 'SQLServerReportingServices' + + Write-Verbose -Message ($script:localizedData.GetServiceInformation -f $ServiceName) -Verbose + $reportingServicesService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue } - Write-Verbose -Message ($script:localizedData.GetServiceInformation -f 'Reporting Services') -Verbose - $reportingServicesService = Get-Service -Name $ServiceName + if ($null -eq $reportingServicesService) + { + $ServiceName = 'ReportServer' + + <# + Pre-2017 SSRS support multiple instances, check if we're dealing + with a named instance. + #> + if (-not ($SQLInstanceName -eq 'MSSQLSERVER')) + { + $ServiceName += '${0}' -f $SQLInstanceName + } + + Write-Verbose -Message ($script:localizedData.GetServiceInformation -f $ServiceName) -Verbose + $reportingServicesService = Get-Service -Name $ServiceName + } <# Get all dependent services that are running. @@ -2013,6 +2031,7 @@ function Test-ActiveNode #> function Invoke-SqlScript { + [CmdletBinding()] param ( [Parameter(Mandatory = $true)] diff --git a/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 b/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 index c0b589dc1..70c63814c 100644 --- a/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 +++ b/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 @@ -8,6 +8,7 @@ ConvertFrom-StringData @' PropertyThatDoesNotMatch = {0} - {1} ValueOfTypeDoesNotMatch = {0} value for property {1} does not match. Current state is '{2}' and desired state is '{3}'. UnableToCompareProperty = Unable to compare property {0} as the type {1} is not handled by the Test-DscParameterState cmdlet. + RobocopyIsCopying = Robocopy is copying media from source '{0}' to destination '{1}'. RobocopyUsingUnbufferedIo = Robocopy is using unbuffered I/O. RobocopyNotUsingUnbufferedIo = Unbuffered I/O cannot be used due to incompatible version of Robocopy. RobocopyArguments = Robocopy is started with the following arguments: {0} @@ -15,7 +16,6 @@ ConvertFrom-StringData @' RobocopyFailuresCopying = Robocopy reported that failures occurred when copying files. Error code: {0}. RobocopySuccessful = Robocopy copied files successfully RobocopyRemovedExtraFilesAtDestination = Robocopy found files at the destination path that is not present at the source path, these extra files was remove at the destination path. - RobocopySuccessfulAndRemovedExtraFilesAtDestination = Robocopy copied files to destination successfully. Robocopy also found files at the destination path that is not present at the source path, these extra files was remove at the destination path. RobocopyAllFilesPresent = Robocopy reported that all files already present. StartSetupProcess = Started the process with id {0} using the path '{1}', and with a timeout value of {2} seconds. ConnectedToDatabaseEngineInstance = Connected to SQL instance '{0}'. @@ -65,11 +65,8 @@ ConvertFrom-StringData @' # Common NoKeyFound = No Localization key found for ErrorType: '{0}'. AbsentNotImplemented = Ensure = Absent is not implemented! - TestFailedAfterSet = Test-TargetResource returned false after calling set. RemoteConnectionFailed = Remote PowerShell connection to Server '{0}' failed. TODO = ToDo. Work not implemented at this time. - UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. - NotConnectedToInstance = Was unable to connect to the instance '{0}\\{1}' AlterAvailabilityGroupFailed = Failed to alter the availability group '{0}'. HadrNotEnabled = HADR is not enabled. AvailabilityGroupNotFound = Unable to locate the availability group '{0}' on the instance '{1}'. @@ -83,42 +80,12 @@ ConvertFrom-StringData @' LoginNotFound = Login '{0}' does not exist on SQL server '{1}\\{2}'." FailedLogin = Creating a login of type 'SqlLogin' requires LoginCredential - # Database Role - AddLoginDatabaseSetError = Failed adding the login {2} as a user of the database {3}, on the instance {0}\\{1}. - DropMemberDatabaseSetError = Failed removing the login {2} from the role {3} on the database {4}, on the instance {0}\\{1}. - AddMemberDatabaseSetError = Failed adding the login {2} to the role {3} on the database {4}, on the instance {0}\\{1}. - # AvailabilityGroupListener - AvailabilityGroupListenerNotFound = Trying to make a change to a listener that does not exist. AvailabilityGroupListenerErrorVerifyExist = Unexpected result when trying to verify existence of listener '{0}'. - AvailabilityGroupListenerIPChangeError = IP-address configuration mismatch. Expecting '{0}' found '{1}'. Resource does not support changing IP-address. Listener needs to be removed and then created again. - AvailabilityGroupListenerDHCPChangeError = IP-address configuration mismatch. Expecting '{0}' found '{1}'. Resource does not support changing between static IP and DHCP. Listener needs to be removed and then created again. - - # Endpoint - EndpointNotFound = Endpoint '{0}' does not exist - EndpointErrorVerifyExist = Unexpected result when trying to verify existence of endpoint '{0}'. - EndpointFoundButWrongType = Endpoint '{0}' does exist, but it is not of type 'DatabaseMirroring'. - - # Permission - PermissionGetError = Unexpected result when trying to get permissions for '{0}'. - ChangingPermissionFailed = Changing permission for principal '{0}' failed. # AlwaysOnService - AlterAlwaysOnServiceFailed = Failed to ensure Always On is {0} on the instance '{1}'. - UnexpectedAlwaysOnStatus = The status of property Server.IsHadrEnabled was neither $true or $false. Status is '{0}'. - # Login - PasswordValidationFailed = Creation of the login '{0}' failed due to the following error: {1} - LoginCreationFailedFailedOperation = Creation of the login '{0}' failed due to a failed operation. - LoginCreationFailedSqlNotSpecified = Creation of the SQL login '{0}' failed due to an unspecified error. - LoginCreationFailedWindowsNotSpecified = Creation of the Windows login '{0}' failed due to an unspecified error. - LoginTypeNotImplemented = The login type '{0}' is not implemented in this resource. - IncorrectLoginMode = The instance '{0}\{1}' is currently in '{2}' authentication mode. To create a SQL Login, it must be set to 'Mixed' authentication mode. - LoginCredentialNotFound = The credential for the SQL Login '{0}' was not found. - PasswordChangeFailed = Setting the password failed for the SQL Login '{0}'. - AlterLoginFailed = Altering the login '{0}' failed. - CreateLoginFailed = Creating the login '{0}' failed. - DropLoginFailed = Dropping the login '{0}' failed. + UnexpectedAlwaysOnStatus = The status of property Server.IsHadrEnabled was neither $true or $false. Status is '{0}'. # AlwaysOnAvailabilityGroup CreateAvailabilityGroupReplicaFailed = Creating the Availability Group Replica '{0}' failed on the instance '{1}'. @@ -131,27 +98,4 @@ ConvertFrom-StringData @' JoinAvailabilityGroupFailed = Failed to join the availability group replica '{0}'. RemoveAvailabilityGroupReplicaFailed = Failed to remove the availability group replica '{0}'. ReplicaNotFound = Unable to find the availability group replica '{0}' on the instance '{1}'. - - # Max degree of parallelism - MaxDopSetError = Unexpected result when trying to configure the max degree of parallelism server configuration option. - MaxDopParamMustBeNull = MaxDop parameter must be set to $null or not assigned if DynamicAlloc parameter is set to $true. - - # Server Memory - MaxMemoryParamMustBeNull = The parameter MaxMemory must be null when DynamicAlloc is set to true. - MaxMemoryParamMustNotBeNull = The parameter MaxMemory must not be null when DynamicAlloc is set to false. - AlterServerMemoryFailed = Failed to alter the server configuration memory for {0}\\{1}. - ErrorGetDynamicMaxMemory = Failed to calculate dynamically the maximum memory. - - # SQLServerDatabase - CreateDatabaseSetError = Failed to create the database named {2} on {0}\\{1}. - DropDatabaseSetError = Failed to drop the database named {2} on {0}\\{1}. - FailedToGetOwnerDatabase = Failed to get owner of the database named {0} on {1}\\{2}. - FailedToSetOwnerDatabase = Failed to set owner named {0} of the database named {1} on {2}\\{3}. - FailedToSetPermissionDatabase = Failed to set permission for login named {0} of the database named {1} on {2}\\{3}. - FailedToEnumDatabasePermissions = Failed to get permission for login named {0} of the database named {1} on {2}\\{3}. - UpdateDatabaseSetError = Failed to update database {1} on {0}\\{1} with specified changes. - InvalidCollationError = The specified collation '{3}' is not a valid collation for database {2} on {0}\\{1}. - - # SQLServerNetwork - UnableToUseBothDynamicAndStaticPort = Unable to set both TCP dynamic port and TCP static port. Only one can be set. '@ diff --git a/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 b/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 index 0d2ec4462..1b519bd7c 100644 --- a/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 +++ b/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 @@ -35,6 +35,15 @@ ConvertFrom-StringData @' ExecuteNonQueryFailed = Exekvering av icke-fråga misslyckades på databas '{0}'. AlterAvailabilityGroupReplicaFailed = Misslyckades att ändra Availability Group kopia '{0}'. GetEffectivePermissionForLogin = Hämtar effektiva behörigheter för inloggningen '{0}' på '{1}'. + RobocopyIsCopying = Robocopy kopierar media från källan '{0}' till destinationen '{1}'. + RobocopyUsingUnbufferedIo = Robocopy använder sig av obuffrad I/O. + RobocopyNotUsingUnbufferedIo = Obuffrad I/O kan inte användas på grund av versionen av Robocopy inte är kompatibel. + RobocopyArguments = Robocopy startas med följande argument: {0} + RobocopyErrorCopying = Robocopy rapporterade fel när filer kopierades. Felkod: {0}. + RobocopyFailuresCopying = Robocopy rapporterade att fel uppstod när filer kopierades. Felkod: {0}. + RobocopySuccessful = Robocopy lyckades kopiera filer till destinationen. + RobocopyRemovedExtraFilesAtDestination = Robocopy fann extra filer på destinationen som inte finns i källan, dessa extra filer togs bort på destinationen. + RobocopyAllFilesPresent = Robocopy rapporterade att alla filer redan finns på destinationen. # - NOTE! # - Below strings are used by helper functions New-TerminatingError and New-WarningMessage. @@ -45,11 +54,8 @@ ConvertFrom-StringData @' # Common NoKeyFound = No Localization key found for ErrorType: '{0}'. AbsentNotImplemented = Ensure = Absent is not implemented! - TestFailedAfterSet = Test-TargetResource returned false after calling set. RemoteConnectionFailed = Remote PowerShell connection to Server '{0}' failed. TODO = ToDo. Work not implemented at this time. - UnexpectedErrorFromGet = Got unexpected result from Get-TargetResource. No change is made. - NotConnectedToInstance = Was unable to connect to the instance '{0}\\{1}' AlterAvailabilityGroupFailed = Failed to alter the availability group '{0}'. HadrNotEnabled = HADR is not enabled. AvailabilityGroupNotFound = Unable to locate the availability group '{0}' on the instance '{1}'. @@ -63,46 +69,16 @@ ConvertFrom-StringData @' LoginNotFound = Login '{0}' does not exist on SQL server '{1}\\{2}'." FailedLogin = Creating a login of type 'SqlLogin' requires LoginCredential - # Database Role - AddLoginDatabaseSetError = Failed adding the login {2} as a user of the database {3}, on the instance {0}\\{1}. - DropMemberDatabaseSetError = Failed removing the login {2} from the role {3} on the database {4}, on the instance {0}\\{1}. - AddMemberDatabaseSetError = Failed adding the login {2} to the role {3} on the database {4}, on the instance {0}\\{1}. - # AvailabilityGroupListener - AvailabilityGroupListenerNotFound = Trying to make a change to a listener that does not exist. AvailabilityGroupListenerErrorVerifyExist = Unexpected result when trying to verify existence of listener '{0}'. - AvailabilityGroupListenerIPChangeError = IP-address configuration mismatch. Expecting '{0}' found '{1}'. Resource does not support changing IP-address. Listener needs to be removed and then created again. - AvailabilityGroupListenerDHCPChangeError = IP-address configuration mismatch. Expecting '{0}' found '{1}'. Resource does not support changing between static IP and DHCP. Listener needs to be removed and then created again. - - # Endpoint - EndpointNotFound = Endpoint '{0}' does not exist - EndpointErrorVerifyExist = Unexpected result when trying to verify existence of endpoint '{0}'. - EndpointFoundButWrongType = Endpoint '{0}' does exist, but it is not of type 'DatabaseMirroring'. - - # Permission - PermissionGetError = Unexpected result when trying to get permissions for '{0}'. - ChangingPermissionFailed = Changing permission for principal '{0}' failed. # Configuration ConfigurationOptionNotFound = Specified option '{0}' could not be found. ConfigurationRestartRequired = Configuration option '{0}' has been updated, but a manual restart of SQL Server is required for it to take effect. # AlwaysOnService - AlterAlwaysOnServiceFailed = Failed to ensure Always On is {0} on the instance '{1}'. - UnexpectedAlwaysOnStatus = The status of property Server.IsHadrEnabled was neither $true or $false. Status is '{0}'. - # Login - PasswordValidationFailed = Creation of the login '{0}' failed due to the following error: {1} - LoginCreationFailedFailedOperation = Creation of the login '{0}' failed due to a failed operation. - LoginCreationFailedSqlNotSpecified = Creation of the SQL login '{0}' failed due to an unspecified error. - LoginCreationFailedWindowsNotSpecified = Creation of the Windows login '{0}' failed due to an unspecified error. - LoginTypeNotImplemented = The login type '{0}' is not implemented in this resource. - IncorrectLoginMode = The instance '{0}\{1}' is currently in '{2}' authentication mode. To create a SQL Login, it must be set to 'Mixed' authentication mode. - LoginCredentialNotFound = The credential for the SQL Login '{0}' was not found. - PasswordChangeFailed = Setting the password failed for the SQL Login '{0}'. - AlterLoginFailed = Altering the login '{0}' failed. - CreateLoginFailed = Creating the login '{0}' failed. - DropLoginFailed = Dropping the login '{0}' failed. + UnexpectedAlwaysOnStatus = The status of property Server.IsHadrEnabled was neither $true or $false. Status is '{0}'. # AlwaysOnAvailabilityGroup ClusterPermissionsMissing = The cluster does not have permissions to manage the Availability Group on '{0}\\{1}'. Grant 'Connect SQL', 'Alter Any Availability Group', and 'View Server State' to either 'NT SERVICE\\ClusSvc' or 'NT AUTHORITY\\SYSTEM'. @@ -116,26 +92,4 @@ ConvertFrom-StringData @' JoinAvailabilityGroupFailed = Failed to join the availability group replica '{0}'. RemoveAvailabilityGroupReplicaFailed = Failed to remove the availability group replica '{0}'. ReplicaNotFound = Unable to find the availability group replica '{0}' on the instance '{1}'. - - # Max degree of parallelism - MaxDopSetError = Unexpected result when trying to configure the max degree of parallelism server configuration option. - MaxDopParamMustBeNull = MaxDop parameter must be set to $null or not assigned if DynamicAlloc parameter is set to $true. - - # Server Memory - MaxMemoryParamMustBeNull = The parameter MaxMemory must be null when DynamicAlloc is set to true. - MaxMemoryParamMustNotBeNull = The parameter MaxMemory must not be null when DynamicAlloc is set to false. - AlterServerMemoryFailed = Failed to alter the server configuration memory for {0}\\{1}. - ErrorGetDynamicMaxMemory = Failed to calculate dynamically the maximum memory. - - # SQLServerDatabase - CreateDatabaseSetError = Failed to create the database named {2} on {0}\\{1}. - DropDatabaseSetError = Failed to drop the database named {2} on {0}\\{1}. - FailedToGetOwnerDatabase = Failed to get owner of the database named {0} on {1}\\{2}. - FailedToSetOwnerDatabase = Failed to set owner named {0} of the database named {1} on {2}\\{3}. - FailedToSetPermissionDatabase = Failed to set permission for login named {0} of the database named {1} on {2}\\{3}. - FailedToEnumDatabasePermissions = Failed to get permission for login named {0} of the database named {1} on {2}\\{3}. - - # SQLServerNetwork - UnableToUseBothDynamicAndStaticPort = Unable to set both TCP dynamic port and TCP static port. Only one can be set. - '@ diff --git a/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 b/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 index 32a3b847e..daf9e0cd3 100644 --- a/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 +++ b/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 @@ -257,10 +257,67 @@ function New-InvalidResultException throw $errorRecordToThrow } +<# + .SYNOPSIS + Creates and throws an not implemented exception. + + .PARAMETER Message + The message explaining why this error is being thrown. + + .PARAMETER ErrorRecord + The error record containing the exception that is causing this terminating error. + ' + .NOTES + The error categories can be found here: + https://docs.microsoft.com/en-us/dotnet/api/system.management.automation.errorcategory +#> +function New-NotImplementedException +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Message, + + [Parameter()] + [ValidateNotNull()] + [System.Management.Automation.ErrorRecord] + $ErrorRecord + ) + + if ($null -eq $ErrorRecord) + { + $invalidOperationException = New-Object -TypeName 'NotImplementedException' ` + -ArgumentList @($Message) + } + else + { + $invalidOperationException = New-Object -TypeName 'NotImplementedException' ` + -ArgumentList @($Message, $ErrorRecord.Exception) + } + + $newObjectParameters = @{ + TypeName = 'System.Management.Automation.ErrorRecord' + ArgumentList = @( + $invalidOperationException.ToString(), + 'MachineStateIncorrect', + 'NotImplemented', + $null + ) + } + + $errorRecordToThrow = New-Object @newObjectParameters + + throw $errorRecordToThrow +} + Export-ModuleMember -Function @( 'New-InvalidArgumentException', 'New-InvalidOperationException', 'New-ObjectNotFoundException', - 'New-InvalidResultException' + 'New-InvalidResultException', + 'New-NotImplementedException' 'Get-LocalizedData' ) diff --git a/README.md b/README.md index 73c7a208e..f285c7164 100644 --- a/README.md +++ b/README.md @@ -775,6 +775,9 @@ Initializes and configures SQL Reporting Services server. * **`[Boolean]` UseSsl** _(Write)_: If connections to the Reporting Services must use SSL. If this parameter is not assigned a value, the default is that Reporting Services does not use SSL. +* **`[Boolean]` SuppressRestart** _(Write)_: Reporting Services need to be restarted + after initialization or settings change. If this parameter is set to $true, + Reporting Services will not be restarted, even after initialisation. #### Read-Only Properties from Get-TargetResource @@ -1610,6 +1613,10 @@ All issues are not listed here, see [here for all open issues](https://github.co Configures SQL connections to be encrypted. Read more about encrypted connections in this article [Enable Encrypted Connections](https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/enable-encrypted-connections-to-the-database-engine). +>Note: that the 'LocalSystem' service account will return a connection +error, even though the connection has been successful. +In that case, the 'SYSTEM' service account can be used. + #### Requirements * Target machine must be running Windows Server 2008 R2 or later. @@ -1630,7 +1637,9 @@ Read more about encrypted connections in this article [Enable Encrypted Connecti used for encryption. If parameter Ensure is set to 'Absent', then the parameter Certificate can be set to an empty string. * **`[String]` ServiceAccount** _(Required)_: Name of the account running the - SQL Server service. + SQL Server service. If parameter is set to "LocalSystem", then a + connection error is displayed. Use the "SYSTEM" account instead, in that + case. * **`[String]` Ensure** _(Write)_: If Encryption should be Enabled (Present) or Disabled (Absent). { *Present* | Absent }. Defaults to Present. * **`[Boolean]` ForceEncryption** _(Write)_: If all connections to the SQL @@ -1642,6 +1651,7 @@ Read more about encrypted connections in this article [Enable Encrypted Connecti * [Force Secure Connection](Examples/Resources/SqlServerSecureConnection/1-ForceSecureConnection.ps1). * [Secure Connection but not required](Examples/Resources/SqlServerSecureConnection/2-SecureConnectionNotForced.ps1). * [Secure Connection disabled](Examples/Resources/SqlServerSecureConnection/3-SecureConnectionAbsent.ps1). +* [Secure Connection Using "SYSTEM" Account](/Examples/Resources/SqlServerSecureConnection/4-SecureConnectionUsingSYSTEMAccount.ps1). #### Known issues diff --git a/SqlServerDsc.psd1 b/SqlServerDsc.psd1 index 7135da128..e485244de 100644 --- a/SqlServerDsc.psd1 +++ b/SqlServerDsc.psd1 @@ -1,6 +1,6 @@ @{ # Version number of this module. - moduleVersion = '12.4.0.0' + moduleVersion = '12.5.0.0' # ID used to uniquely identify this module GUID = '693ee082-ed36-45a7-b490-88b07c86b42f' @@ -49,81 +49,89 @@ # IconUri = '' # ReleaseNotes of this module - ReleaseNotes = '- Changes to SqlServerDsc - - Added new resources. - - SqlRSSetup - - Added helper module DscResource.Common from the repository - DscResource.Template. - - Moved all helper functions from SqlServerDscHelper.psm1 to DscResource.Common. - - Renamed Test-SqlDscParameterState to Test-DscParameterState. - - New-TerminatingError error text for a missing localized message now matches - the output even if the "missing localized message" localized message is - also missing. - - Added helper module DscResource.LocalizationHelper from the repository - DscResource.Template, this replaces the helper module CommonResourceHelper.psm1. - - Cleaned up unit tests, mostly around loading cmdlet stubs and loading - classes stubs, but also some tests that were using some odd variants. - - Fix all integration tests according to issue [PowerShell/DscResource.Template14](https://github.com/PowerShell/DscResource.Template/issues/14). -- Changes to SqlServerMemory - - Updated Cim Class to Win32_ComputerSystem (instead of Win32_PhysicalMemory) - because the correct memory size was not being detected correctly on Azure VMs - ([issue 914](https://github.com/PowerShell/SqlServerDsc/issues/914)). + ReleaseNotes = '- Changes to SqlServerSecureConnection + - Updated README and added example for SqlServerSecureConnection, + instructing users to use the "SYSTEM" service account instead of + "LocalSystem". +- Changes to SqlScript + - Correctly passes the `$VerbosePreference` to the helper function + `Invoke-SqlScript` so that `PRINT` statements is outputted correctly + when verbose output is requested, e.g + `Start-DscConfiguration -Verbose`. + - Added en-US localization ([issue 624](https://github.com/PowerShell/SqlServerDsc/issues/624)). + - Added additional unit tests for code coverage. +- Changes to SqlScriptQuery + - Correctly passes the `$VerbosePreference` to the helper function + `Invoke-SqlScript` so that `PRINT` statements is outputted correctly + when verbose output is requested, e.g + `Start-DscConfiguration -Verbose`. + - Added en-US localization. + - Added additional unit tests for code coverage. - Changes to SqlSetup - - Split integration tests into two jobs, one for running integration tests - for SQL Server 2016 and another for running integration test for - SQL Server 2017 ([issue 858](https://github.com/PowerShell/SqlServerDsc/issues/858)). - - Localized messages for Master Data Services no longer start and end with - single quote. - - When installing features a verbose message is written if a feature is found - to already be installed. It no longer quietly removes the feature from the - `/FEATURES` argument. - - Cleaned up a bit in the tests, removed excessive piping. - - Fixed minor typo in examples. - - A new optional parameter `FeatureFlag` parameter was added to control - breaking changes. Functionality added under a feature flag can be - toggled on or off, and could be changed later to be the default. - This way we can also make more of the new functionalities the default - in the same breaking change release ([issue 1105](https://github.com/PowerShell/SqlServerDsc/issues/1105)). - - Added a new way of detecting if the shared feature CONN (Client Tools - Connectivity, and SQL Client Connectivity SDK), BC (Client Tools - Backwards Compatibility), and SDK (Client Tools SDK) is installed or - not. The new functionality is used when the parameter `FeatureFlag` - is set to `"DetectionSharedFeatures"` ([issue 1105](https://github.com/PowerShell/SqlServerDsc/issues/1105)). - - Added a new helper function `Get-InstalledSharedFeatures` to move out - some of the code from the `Get-TargetResource` to make unit testing - easier and faster. - - Changed the logic of "Build the argument string to be passed to setup" to - not quote the value if root directory is specified - ([issue 1254](https://github.com/PowerShell/SqlServerDsc/issues/1254)). - - Moved some resource specific helper functions to the new helper module - DscResource.Common so they can be shared with the new resource SqlRSSetup. - - Improved verbose messages in Test-TargetResource function to more - clearly tell if features are already installed or not. - - Refactored unit tests for the functions Test-TargetResource and - Set-TargetResource to improve testing speed. - - Modified the Test-TargetResource and Set-TargetResource to not be - case-sensitive when comparing feature names. *This was handled - correctly in real-world scenarios, but failed when running the unit - tests (and testing casing).* -- Changes to SqlAGDatabase - - Fix MatchDatabaseOwner to check for CONTROL SERVER, IMPERSONATE LOGIN, or - CONTROL LOGIN permission in addition to IMPERSONATE ANY LOGIN. - - Update and fix MatchDatabaseOwner help text. -- Changes to SqlAG - - Updated documentation on the behaviour of defaults as they only apply when - creating a group. -- Changes to SqlAGReplica - - AvailabilityMode, BackupPriority, and FailoverMode defaults only apply when - creating a replica not when making changes to an existing replica. Explicit - parameters will still change existing replicas ([issue 1244](https://github.com/PowerShell/SqlServerDsc/issues/1244)). - - ReadOnlyRoutingList now gets updated without throwing an error on the first - run ([issue 518](https://github.com/PowerShell/SqlServerDsc/issues/518)). - - Test-Resource fixed to report whether ReadOnlyRoutingList desired state - has been reached correctly ([issue 1305](https://github.com/PowerShell/SqlServerDsc/issues/1305)). -- Changes to SqlDatabaseDefaultLocation - - No longer does the Test-TargetResource fail on the second test run - when the backup file path was changed, and the path was ending with - a backslash ([issue 1307](https://github.com/PowerShell/SqlServerDsc/issues/1307)). + - Concatenated Robocopy localization strings ([issue 694](https://github.com/PowerShell/SqlServerDsc/issues/694)). + - Made the error message more descriptive when the Set-TargetResource + function calls the Test-TargetResource function to verify the desired + state. +- Changes to SqlWaitForAG + - Added en-US localization ([issue 625](https://github.com/PowerShell/SqlServerDsc/issues/625)). +- Changes to SqlServerPermission + - Added en-US localization ([issue 619](https://github.com/PowerShell/SqlServerDsc/issues/619)). +- Changes to SqlServerMemory + - Added en-US localization ([issue 617](https://github.com/PowerShell/SqlServerDsc/issues/617)). + - No longer will the resource set the MinMemory value if it was provided + in a configuration that also set the `Ensure` parameter to "Absent" + ([issue 1329](https://github.com/PowerShell/SqlServerDsc/issues/1329)). + - Refactored unit tests to simplify them add add slightly more code + coverage. +- Changes to SqlServerMaxDop + - Added en-US localization ([issue 616](https://github.com/PowerShell/SqlServerDsc/issues/616)). +- Changes to SqlRS + - Reporting Services are restarted after changing settings, unless + `$SuppressRestart` parameter is set ([issue 1331](https://github.com/PowerShell/SqlServerDsc/issues/1331)). + `$SuppressRestart` will also prevent Reporting Services restart after initialization. + - Fixed one of the error handling to use localization, and made the + error message more descriptive when the Set-TargetResource function + calls the Test-TargetResource function to verify the desired + state. *This was done prior to adding full en-US localization.* + - Fixed ([issue 1258](https://github.com/PowerShell/SqlServerDsc/issues/1258)). + When initializing Reporting Services, there is no need to execute `InitializeReportServer` + CIM method, since executing `SetDatabaseConnection` CIM method initializes + Reporting Services. + - [issue 864](https://github.com/PowerShell/SqlServerDsc/issues/864) SqlRs + can now initialise SSRS 2017 instances +- Changes to SqlServerLogin + - Added en-US localization ([issue 615](https://github.com/PowerShell/SqlServerDsc/issues/615)). + - Added unit tests to improved code coverage. +- Changes to SqlWindowsFirewall + - Added en-US localization ([issue 614](https://github.com/PowerShell/SqlServerDsc/issues/614)). +- Changes to SqlServerEndpoint + - Added en-US localization ([issue 611](https://github.com/PowerShell/SqlServerDsc/issues/611)). +- Changes to SqlServerEndpointPermission + - Added en-US localization ([issue 612](https://github.com/PowerShell/SqlServerDsc/issues/612)). +- Changes to SqlServerEndpointState + - Added en-US localization ([issue 613](https://github.com/PowerShell/SqlServerDsc/issues/613)). +- Changes to SqlDatabaseRole + - Added en-US localization ([issue 610](https://github.com/PowerShell/SqlServerDsc/issues/610)). +- Changes to SqlDatabaseRecoveryModel + - Added en-US localization ([issue 609](https://github.com/PowerShell/SqlServerDsc/issues/609)). +- Changes to SqlDatabasePermission + - Added en-US localization ([issue 608](https://github.com/PowerShell/SqlServerDsc/issues/608)). +- Changes to SqlDatabaseOwner + - Added en-US localization ([issue 607](https://github.com/PowerShell/SqlServerDsc/issues/607)). +- Changes to SqlDatabase + - Added en-US localization ([issue 606](https://github.com/PowerShell/SqlServerDsc/issues/606)). +- Changes to SqlAGListener + - Added en-US localization ([issue 604](https://github.com/PowerShell/SqlServerDsc/issues/604)). +- Changes to SqlAlwaysOnService + - Added en-US localization ([issue 603](https://github.com/PowerShell/SqlServerDsc/issues/608)). +- Changes to SqlAlias + - Added en-US localization ([issue 602](https://github.com/PowerShell/SqlServerDsc/issues/602)). + - Removed ShouldProcess for the code, since it has no purpose in a DSC + resource ([issue 242](https://github.com/PowerShell/SqlServerDsc/issues/242)). +- Changes to SqlServerReplication + - Added en-US localization ([issue 620](https://github.com/PowerShell/SqlServerDsc/issues/620)). + - Refactored Get-TargetResource slightly so it provide better verbose + messages. ' @@ -150,5 +158,6 @@ + diff --git a/Tests/Integration/MSFT_SqlRS.Integration.Tests.ps1 b/Tests/Integration/MSFT_SqlRS.Integration.Tests.ps1 index 492fdb216..fa94d1ef8 100644 --- a/Tests/Integration/MSFT_SqlRS.Integration.Tests.ps1 +++ b/Tests/Integration/MSFT_SqlRS.Integration.Tests.ps1 @@ -4,7 +4,7 @@ param() Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') -if (Test-SkipContinuousIntegrationTask -Type 'Integration' -Category 'Integration_SQL2016') +if (Test-SkipContinuousIntegrationTask -Type 'Integration' -Category @('Integration_SQL2016','Integration_SQL2017')) { return } @@ -29,6 +29,22 @@ $TestEnvironment = Initialize-TestEnvironment ` -TestType Integration #endregion +<# + This is used in both the configuration file and in this script file + to run the correct tests depending of what version of SQL Server is + being tested in the current job. +#> +if (Test-ContinuousIntegrationTaskCategory -Category 'Integration_SQL2017') +{ + $script:sqlVersion = '140' +} +else +{ + $script:sqlVersion = '130' +} + +Write-Verbose -Message ('Running integration tests for SSRS version {0}' -f $script:sqlVersion) -Verbose + # Using try/finally to always cleanup. try { @@ -117,7 +133,15 @@ try } It 'Should be able to access the ReportServer site without any error' { - $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + if($script:sqlVersion -eq '140') + { + # SSRS 2017 does not support multiple instances + $reportServerUri = 'http://{0}/ReportServer' -f $env:COMPUTERNAME + } + else + { + $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + } try { @@ -139,7 +163,15 @@ try } It 'Should be able to access the Reports site without any error' { - $reportsUri = 'http://{0}/Reports_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + if($script:sqlVersion -eq '140') + { + # SSRS 2017 does not support multiple instances + $reportsUri = 'http://{0}/Reports' -f $env:COMPUTERNAME + } + else + { + $reportsUri = 'http://{0}/Reports_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + } try { @@ -213,7 +245,15 @@ try as this without testing for the correct error message on purpose. #> It 'Should not be able to access the ReportServer site and throw an error message' { - $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + if($script:sqlVersion -eq '140') + { + # SSRS 2017 does not support multiple instances + $reportServerUri = 'http://{0}/ReportServer' -f $env:COMPUTERNAME + } + else + { + $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + } { Invoke-WebRequest -Uri $reportServerUri -UseDefaultCredentials } | Should -Throw } @@ -265,7 +305,15 @@ try } It 'Should be able to access the ReportServer site without any error' { - $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + if($script:sqlVersion -eq '140') + { + # SSRS 2017 does not support multiple instances + $reportServerUri = 'http://{0}/ReportServer' -f $env:COMPUTERNAME + } + else + { + $reportServerUri = 'http://{0}/ReportServer_{1}' -f $env:COMPUTERNAME, $ConfigurationData.AllNodes.InstanceName + } try { diff --git a/Tests/Integration/MSFT_SqlRS.config.ps1 b/Tests/Integration/MSFT_SqlRS.config.ps1 index 702715389..0c2b1f45e 100644 --- a/Tests/Integration/MSFT_SqlRS.config.ps1 +++ b/Tests/Integration/MSFT_SqlRS.config.ps1 @@ -17,6 +17,19 @@ else $mockLastDrive = ((Get-Volume).DriveLetter | Sort-Object | Select-Object -Last 1) $mockIsoMediaDriveLetter = [char](([int][char]$mockLastDrive) + 1) + if($script:sqlVersion -eq '140') + { + # SQL2017 + $instanceName = 'SSRS' + $isoImageName = 'SQL2017.iso' + } + else + { + # SQL2016 + $instanceName = 'DSCRS2016' + $isoImageName = 'SQL2016.iso' + } + $ConfigurationData = @{ AllNodes = @( @{ @@ -27,7 +40,7 @@ else Service_UserName = "$env:COMPUTERNAME\svc-Reporting" Service_Password = 'yig-C^Equ3' - InstanceName = 'DSCRS2016' + InstanceName = $instanceName Features = 'RS' InstallSharedDir = 'C:\Program Files\Microsoft SQL Server' InstallSharedWOWDir = 'C:\Program Files (x86)\Microsoft SQL Server' @@ -35,7 +48,7 @@ else SuppressReboot = $true # Make sure we don't reboot during testing. ForceReboot = $false - ImagePath = "$env:TEMP\SQL2016.iso" + ImagePath = "$env:TEMP\$isoImageName" DriveLetter = $mockIsoMediaDriveLetter DatabaseServerName = $env:COMPUTERNAME @@ -90,32 +103,46 @@ Configuration MSFT_SqlRS_CreateDependencies_Config Ensure = 'Present' } - SqlSetup 'InstallReportingServicesInstance' + if($script:sqlVersion -eq '130') { - InstanceName = $Node.InstanceName - Features = $Node.Features - SourcePath = "$($Node.DriveLetter):\" - BrowserSvcStartupType = 'Automatic' - InstallSharedDir = $Node.InstallSharedDir - InstallSharedWOWDir = $Node.InstallSharedWOWDir - UpdateEnabled = $Node.UpdateEnabled - SuppressReboot = $Node.SuppressReboot - ForceReboot = $Node.ForceReboot - RSSvcAccount = New-Object ` - -TypeName System.Management.Automation.PSCredential ` - -ArgumentList @($Node.Service_UserName, (ConvertTo-SecureString -String $Node.Service_Password -AsPlainText -Force)) - - DependsOn = @( - '[WaitForVolume]WaitForMountOfIsoMedia' - '[User]CreateReportingServicesServiceAccount' - '[WindowsFeature]NetFramework45' - ) + SqlSetup 'InstallReportingServicesInstance' + { + InstanceName = $Node.InstanceName + Features = $Node.Features + SourcePath = "$($Node.DriveLetter):\" + BrowserSvcStartupType = 'Automatic' + InstallSharedDir = $Node.InstallSharedDir + InstallSharedWOWDir = $Node.InstallSharedWOWDir + UpdateEnabled = $Node.UpdateEnabled + SuppressReboot = $Node.SuppressReboot + ForceReboot = $Node.ForceReboot + RSSvcAccount = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @($Node.Service_UserName, (ConvertTo-SecureString -String $Node.Service_Password -AsPlainText -Force)) - PsDscRunAsCredential = New-Object ` - -TypeName System.Management.Automation.PSCredential ` - -ArgumentList @( - $Node.RunAs_UserName, (ConvertTo-SecureString -String $Node.RunAs_Password -AsPlainText -Force)) + DependsOn = @( + '[WaitForVolume]WaitForMountOfIsoMedia' + '[User]CreateReportingServicesServiceAccount' + '[WindowsFeature]NetFramework45' + ) + PsDscRunAsCredential = New-Object ` + -TypeName System.Management.Automation.PSCredential ` + -ArgumentList @( + $Node.RunAs_UserName, (ConvertTo-SecureString -String $Node.RunAs_Password -AsPlainText -Force)) + } + } + <# + MSFT_SqlRSSetup.Integration.Tests.ps1 will have installed SSRS 2017. + We just need to start SSRS. + #> + elseif($script:sqlVersion -eq '140') + { + Service 'StartReportingServicesInstance' + { + Name = 'SQLServerReportingServices' + State = 'Running' + } } } } @@ -222,10 +249,21 @@ Configuration MSFT_SqlRS_StopReportingServicesInstance_Config node $AllNodes.NodeName { - Service ('StopReportingServicesInstance{0}' -f $Node.InstanceName) + if($script:sqlVersion -eq '130') { - Name = ('ReportServer${0}' -f $Node.InstanceName) - State = 'Stopped' + Service ('StopReportingServicesInstance{0}' -f $Node.InstanceName) + { + Name = ('ReportServer${0}' -f $Node.InstanceName) + State = 'Stopped' + } + } + elseif($script:sqlVersion -eq '140') + { + Service 'StopReportingServicesInstance' + { + Name = 'SQLServerReportingServices' + State = 'Stopped' + } } } } diff --git a/Tests/Unit/DscResource.Common.Tests.ps1 b/Tests/Unit/DscResource.Common.Tests.ps1 index 6e175df60..7a9aeb079 100644 --- a/Tests/Unit/DscResource.Common.Tests.ps1 +++ b/Tests/Unit/DscResource.Common.Tests.ps1 @@ -2634,6 +2634,31 @@ InModuleScope 'DscResource.Common' { } } + Context 'When restarting an SQL Server 2017 Report Services' { + BeforeAll { + $mockServiceName = 'SQLServerReportingServices' + $mockDependedServiceName = 'DependentService' + + $mockDynamicServiceName = $mockServiceName + $mockDynamicDependedServiceName = $mockDependedServiceName + $mockDynamicServiceDisplayName = 'Reporting Services' + + Mock -CommandName Stop-Service -Verifiable + Mock -CommandName Start-Service -Verifiable + Mock -CommandName Get-Service -MockWith $mockGetService + } + + It 'Should restart the service and dependent service' { + { Restart-ReportingServicesService -SQLInstanceName 'SSRS' } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-Service -ParameterFilter { + $Name -eq $mockServiceName + } -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Stop-Service -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Start-Service -Scope It -Exactly -Times 2 + } + } + Context 'When restarting a Report Services named instance' { BeforeAll { $mockServiceName = 'ReportServer$TEST' diff --git a/Tests/Unit/DscResource.LocalizationHelper.Tests.ps1 b/Tests/Unit/DscResource.LocalizationHelper.Tests.ps1 index 2d054fab8..be615670d 100644 --- a/Tests/Unit/DscResource.LocalizationHelper.Tests.ps1 +++ b/Tests/Unit/DscResource.LocalizationHelper.Tests.ps1 @@ -188,6 +188,30 @@ InModuleScope 'DscResource.LocalizationHelper' { Assert-VerifiableMock } + Describe 'DscResource.LocalizationHelper\New-NotImplementedException' { + Context 'When calling with Message parameter only' { + It 'Should throw the correct error' { + $mockErrorMessage = 'Mocked error' + + { New-NotImplementedException -Message $mockErrorMessage } | Should -Throw $mockErrorMessage + } + } + + Context 'When calling with both the Message and ErrorRecord parameter' { + It 'Should throw the correct error' { + $mockErrorMessage = 'Mocked error' + $mockExceptionErrorMessage = 'Mocked exception error message' + + $mockException = New-Object -TypeName System.Exception -ArgumentList $mockExceptionErrorMessage + $mockErrorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord -ArgumentList $mockException, $null, 'InvalidResult', $null + + { New-NotImplementedException -Message $mockErrorMessage -ErrorRecord $mockErrorRecord } | Should -Throw ('System.NotImplementedException: {0} ---> System.Exception: {1}' -f $mockErrorMessage, $mockExceptionErrorMessage) + } + } + + Assert-VerifiableMock + } + Describe 'DscResource.LocalizationHelper\New-InvalidArgumentException' { Context 'When calling with both the Message and ArgumentName parameter' { It 'Should throw the correct error' { diff --git a/Tests/Unit/MSFT_SqlAGListener.Tests.ps1 b/Tests/Unit/MSFT_SqlAGListener.Tests.ps1 index 8033eae08..160da4867 100644 --- a/Tests/Unit/MSFT_SqlAGListener.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlAGListener.Tests.ps1 @@ -236,7 +236,7 @@ try $mockDynamicAvailabilityGroup = $mockUnknownAvailabilityGroup It 'Should throw the correct error' { - { Get-TargetResource @testParameters } | Should -Throw 'Trying to make a change to a listener that does not exist. InnerException: Unable to locate the availability group ''AG01'' on the instance ''MSSQLSERVER''.' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupListenerNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } } @@ -521,7 +521,7 @@ try return $null } - { Test-TargetResource @testParameters } | Should -Throw 'Got unexpected result from Get-TargetResource. No change is made.' + { Test-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet } } @@ -685,7 +685,7 @@ try } } - { Set-TargetResource @testParameters } | Should -Throw 'Unable to locate the availability group ''AG01'' on the instance ''MSSQLSERVER''.' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } It 'Should throw the correct error when availability group is not found and Ensure is set to ''Absent''' { @@ -697,7 +697,7 @@ try } } - { Set-TargetResource @testParameters } | Should -Throw 'Unable to locate the availability group ''AG01'' on the instance ''MSSQLSERVER''.' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } $mockDynamicAvailabilityGroup = $mockKnownAvailabilityGroup @@ -706,7 +706,7 @@ try It 'Should throw the correct error when listener is not found and Ensure is set to ''Absent''' { $testParameters['Ensure'] = 'Absent' - { Set-TargetResource @testParameters } | Should -Throw 'Trying to make a change to a listener that does not exist.' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupListenerNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } It 'Should throw the correct error when listener is not found and Ensure is set to ''Present''' { @@ -726,7 +726,7 @@ try } } - { Set-TargetResource @testParameters } | Should -Throw 'Trying to make a change to a listener that does not exist.' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupListenerNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } $mockDynamicAvailabilityGroup = $mockUnknownAvailabilityGroup @@ -749,7 +749,7 @@ try } } - { Set-TargetResource @testParameters } | Should -Throw 'Unable to locate the availability group ''AG01'' on the instance ''MSSQLSERVER''.' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AvailabilityGroupNotFound -f $testParameters.AvailabilityGroup, $testParameters.InstanceName) } } @@ -810,7 +810,7 @@ try return $null } - { Set-TargetResource @testParameters } | Should -Throw 'Got unexpected result from Get-TargetResource. No change is made.' + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet } } diff --git a/Tests/Unit/MSFT_SqlAlias.Tests.ps1 b/Tests/Unit/MSFT_SqlAlias.Tests.ps1 index dd85d22f7..50c6360e8 100644 --- a/Tests/Unit/MSFT_SqlAlias.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlAlias.Tests.ps1 @@ -1090,6 +1090,28 @@ try Add-Member -MemberType NoteProperty -Name OSArchitecture -Value '64-bit' -PassThru -Force } -ParameterFilter { $ClassName -eq 'win32_OperatingSystem' } -Verifiable + Context 'When the system is in the desired state (Absent)' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + Ensure = 'Absent' + } + } + + $testParameters = @{ + Ensure = 'Absent' + Name = $name + ServerName = $serverNameTcp + } + } + + It "Should return true from the test method" { + Test-TargetResource @testParameters | Should -Be $true + + Assert-MockCalled Get-TargetResource -Exactly -Times 1 -Scope It + } + } + Context 'When the system is in the desired state (when using TCP)' { $testParameters = @{ Name = $name diff --git a/Tests/Unit/MSFT_SqlAlwaysOnService.Tests.ps1 b/Tests/Unit/MSFT_SqlAlwaysOnService.Tests.ps1 index eff282a4d..373cdeba7 100644 --- a/Tests/Unit/MSFT_SqlAlwaysOnService.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlAlwaysOnService.Tests.ps1 @@ -135,8 +135,6 @@ try Mock -CommandName Disable-SqlAlwaysOn -ModuleName $script:dscResourceName Mock -CommandName Enable-SqlAlwaysOn -ModuleName $script:dscResourceName Mock -CommandName Import-SQLPSModule -ModuleName $script:dscResourceName - Mock -CommandName New-TerminatingError { $ErrorType } -ModuleName $script:dscResourceName - Mock -CommandName New-VerboseMessage -ModuleName $script:dscResourceName Mock -CommandName Restart-SqlService -ModuleName $script:dscResourceName -Verifiable Context 'When HADR is not in the desired state' { @@ -203,12 +201,11 @@ try } } -ModuleName $script:dscResourceName -Verifiable - { Set-TargetResource @enableHadr } | Should -Throw 'AlterAlwaysOnServiceFailed' + { Set-TargetResource @enableHadr } | Should -Throw ($script:localizedData.AlterAlwaysOnServiceFailed -f 'enabled', $enableHadr.ServerName, $enableHadr.InstanceName) Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Connect-SQL -Scope It -Times 1 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Disable-SqlAlwaysOn -Scope It -Times 0 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Enable-SqlAlwaysOn -Scope It -Times 1 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Restart-SqlService -Scope It -Times 1 - Assert-MockCalled -ModuleName $script:dscResourceName -CommandName New-TerminatingError -Scope It -Times 1 } It 'Should throw the correct error message when Ensure is set to Absent, but IsHadrEnabled is $true' { @@ -218,12 +215,11 @@ try } } -ModuleName $script:dscResourceName -Verifiable - { Set-TargetResource @disableHadr } | Should -Throw 'AlterAlwaysOnServiceFailed' + { Set-TargetResource @disableHadr } | Should -Throw ($script:localizedData.AlterAlwaysOnServiceFailed -f 'disabled', $disableHadr.ServerName, $disableHadr.InstanceName) Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Connect-SQL -Scope It -Times 1 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Disable-SqlAlwaysOn -Scope It -Times 1 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Enable-SqlAlwaysOn -Scope It -Times 0 Assert-MockCalled -ModuleName $script:dscResourceName -CommandName Restart-SqlService -Scope It -Times 1 - Assert-MockCalled -ModuleName $script:dscResourceName -CommandName New-TerminatingError -Scope It -Times 1 } } } diff --git a/Tests/Unit/MSFT_SqlDatabase.Tests.ps1 b/Tests/Unit/MSFT_SqlDatabase.Tests.ps1 index feac8d33a..54293a4c6 100644 --- a/Tests/Unit/MSFT_SqlDatabase.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlDatabase.Tests.ps1 @@ -379,10 +379,26 @@ try Ensure = 'Present' } - $throwInvalidOperation = ('InnerException: Exception calling "Create" ' + ` - 'with "0" argument(s): "Mock Create Method was called with invalid operation."') + $errorMessage = $script:localizedData.FailedToCreateDatabase -f $testParameters.Name - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage + + Assert-MockCalled New-Object -Exactly -Times 1 -ParameterFilter { + $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Database' + } -Scope It + } + + It 'Should throw the correct error when Alter() method was called with invalid operation' { + $testParameters = $mockDefaultParameters + $testParameters += @{ + Name = $mockSqlDatabaseName + Ensure = 'Present' + Collation = 'SQL_Latin1_General_Pref_CP850_CI_AS' + } + + $errorMessage = $script:localizedData.FailedToUpdateDatabase -f $testParameters.Name + + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should throw the correct error when invalid collation is specified' { @@ -393,19 +409,11 @@ try Collation = 'InvalidCollation' } - $throwInvalidOperation = ("The specified collation '{3}' is not a valid collation for database {2} on {0}\{1}." -f $mockServerName, $mockInstanceName, $testParameters.Name, $testParameters.Collation) + $errorMessage = $script:localizedData.InvalidCollation -f $testParameters.Collation, $testParameters.InstanceName - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 2 -Scope Context - } + { Set-TargetResource @testParameters } | Should -Throw $errorMessage - It 'Should call the mock function New-Object with TypeName equal to Microsoft.SqlServer.Management.Smo.Database' { - Assert-MockCalled New-Object -Exactly -Times 1 -ParameterFilter { - $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Database' - } -Scope Context + Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } } @@ -421,10 +429,10 @@ try } It 'Should throw the correct error when Drop() method was called with invalid operation' { - $throwInvalidOperation = ('InnerException: Exception calling "Drop" ' + ` - 'with "0" argument(s): "Mock Drop Method was called with invalid operation."') - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + $errorMessage = $script:localizedData.FailedToDropDatabase -f $testParameters.Name + + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { diff --git a/Tests/Unit/MSFT_SqlDatabaseOwner.Tests.ps1 b/Tests/Unit/MSFT_SqlDatabaseOwner.Tests.ps1 index b847d4311..5392278b1 100644 --- a/Tests/Unit/MSFT_SqlDatabaseOwner.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlDatabaseOwner.Tests.ps1 @@ -120,10 +120,9 @@ try Name = $mockSqlServerLogin } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -157,6 +156,27 @@ try } } + Context 'When the Connect-Sql fails with an error' { + BeforeEach { + Mock -CommandName Connect-Sql -MockWith { + throw 'mocked error' + } + } + + It 'Should throw the correct error when the method SetOwner() set the wrong login' { + $testParameters = $mockDefaultParameters + $testParameters += @{ + Database = $mockSqlDatabaseName + Name = $mockSqlServerLogin + } + + $errorMessage = $script:localizedData.FailedToGetOwnerDatabase -f $testParameters.Database + + { Get-TargetResource @testParameters } | Should -Throw $errorMessage + } + } + + Assert-VerifiableMock } @@ -217,10 +237,10 @@ try Name = $mockSqlServerLogin } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database + + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -236,10 +256,9 @@ try Name = 'John' } - $throwInvalidOperation = ("Login 'John' does not exist on " + ` - "SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.LoginNotFound -f $testParameters.Name - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -274,13 +293,9 @@ try Name = $mockSqlServerLogin } - $throwInvalidOperation = ('Failed to set owner named Zebes\SamusAran of the database ' + ` - 'named AdventureWorks on localhost\MSSQLSERVER. InnerException: ' + ` - 'Exception calling "SetOwner" with "1" argument(s): "Called mocked ' + ` - 'SetOwner() method without setting the right login. ' + ` - "Expected 'Zebes\SamusAran'. But was 'Elysia\Chozo'.") + $errorMessage = $script:localizedData.FailedToSetOwnerDatabase -f $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -298,12 +313,9 @@ try Name = $mockSqlServerLogin } - $throwInvalidOperation = ('Failed to set owner named Zebes\SamusAran of the database ' + ` - 'named AdventureWorks on localhost\MSSQLSERVER. InnerException: ' + ` - 'Exception calling "SetOwner" with "1" argument(s): "Mock ' + ` - 'of method SetOwner() was called with invalid operation.') + $errorMessage = $script:localizedData.FailedToSetOwnerDatabase -f $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { diff --git a/Tests/Unit/MSFT_SqlDatabasePermission.Tests.ps1 b/Tests/Unit/MSFT_SqlDatabasePermission.Tests.ps1 index aba28b934..d4edcaef3 100644 --- a/Tests/Unit/MSFT_SqlDatabasePermission.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlDatabasePermission.Tests.ps1 @@ -257,10 +257,9 @@ try Permissions = @( 'Connect', 'Update' ) } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -276,10 +275,9 @@ try Permissions = @( 'Connect', 'Update' ) } - $throwInvalidOperation = ("Login 'unknownLoginName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.LoginNotFound -f $testParameters.Name - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -296,10 +294,9 @@ try Permissions = @( 'Connect', 'Update' ) } - $throwInvalidOperation = ('Failed to get permission for login named Zebes\SamusAran of ' + ` - 'the database named AdventureWorks on localhost\MSSQLSERVER.') + $errorMessage = $script:localizedData.FailedToEnumDatabasePermissions -f $testParameters.Name, $testParameters.Database - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -428,10 +425,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database - { Test-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Test-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -448,10 +444,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ("Login 'unknownLoginName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.LoginNotFound -f $testParameters.Name - { Test-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Test-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -469,10 +464,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ('Failed to get permission for login named Zebes\SamusAran of ' + ` - 'the database named AdventureWorks on localhost\MSSQLSERVER.') + $errorMessage = $script:localizedData.FailedToEnumDatabasePermissions -f $testParameters.Name, $testParameters.Database - { Test-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Test-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -573,10 +567,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -593,10 +586,10 @@ try Ensure = 'Present' } - $throwInvalidOperation = ("Login 'unknownLoginName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + $errorMessage = $script:localizedData.LoginNotFound -f $testParameters.Name + + { Set-TargetResource @testParameters } | Should -Throw $errorMessage Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -614,11 +607,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ('Failed adding the login Elysia\Chozo ' + ` - 'as a user of the database AdventureWorks, ' + ` - 'on the instance localhost\MSSQLSERVER.') + $errorMessage = $script:localizedData.FailedToAddUser -f $testParameters.Name, $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage $script:mockMethodCreateLoginRan | Should -Be $true @@ -629,9 +620,7 @@ try Context 'When the system is not in the desired state' { Context 'When the mock methods fail (testing the test)' { BeforeAll { - $throwInvalidOperation = ('Failed to set permission for login named ' + ` - 'Zebes\SamusAran of the database named ' + ` - 'AdventureWorks on localhost\MSSQLSERVER.') + $throwInvalidOperation = $script:localizedData.FailedToSetPermissionDatabase -f 'Zebes\SamusAran', 'AdventureWorks' $mockExpectedSqlServerLogin = $mockSqlServerLoginUnknown } diff --git a/Tests/Unit/MSFT_SqlDatabaseRecoveryModel.Tests.ps1 b/Tests/Unit/MSFT_SqlDatabaseRecoveryModel.Tests.ps1 index 5b6c2b664..00cb72363 100644 --- a/Tests/Unit/MSFT_SqlDatabaseRecoveryModel.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlDatabaseRecoveryModel.Tests.ps1 @@ -109,10 +109,9 @@ try RecoveryModel = 'Full' } - $throwInvalidOperation = ("Database 'UnknownDatabase' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Name - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -224,10 +223,9 @@ try RecoveryModel = 'Full' } - $throwInvalidOperation = ("Database 'UnknownDatabase' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Name - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { diff --git a/Tests/Unit/MSFT_SqlDatabaseRole.Tests.ps1 b/Tests/Unit/MSFT_SqlDatabaseRole.Tests.ps1 index 56c38c34f..4ff6e1c94 100644 --- a/Tests/Unit/MSFT_SqlDatabaseRole.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlDatabaseRole.Tests.ps1 @@ -94,7 +94,9 @@ try $mockSqlServerLoginOne = @(( New-Object -TypeName Object | Add-Member -MemberType ScriptMethod -Name IsMember -Value { - param( + param + ( + [Parameter()] [System.String] $mockSqlDatabaseRole ) @@ -122,7 +124,9 @@ try New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name Name -Value $mockSqlDatabaseRole -PassThru | Add-Member -MemberType ScriptMethod -Name AddMember -Value { - param( + param + ( + [Parameter()] [System.String] $mockSqlServerLogin ) @@ -137,7 +141,9 @@ try } } -PassThru | Add-Member -MemberType ScriptMethod -Name DropMember -Value { - param( + param + ( + [Parameter()] [System.String] $mockSqlServerLogin ) @@ -156,7 +162,9 @@ try New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name Name -Value $mockSqlDatabaseRoleSecond -PassThru | Add-Member -MemberType ScriptMethod -Name AddMember -Value { - param( + param + ( + [Parameter()] [System.String] $mockSqlServerLogin ) @@ -171,7 +179,9 @@ try } } -PassThru | Add-Member -MemberType ScriptMethod -Name DropMember -Value { - param( + param + ( + [Parameter()] [System.String] $mockSqlServerLogin ) @@ -234,7 +244,7 @@ try } #endregion - Describe "MSFT_SqlDatabaseRole\Get-TargetResource" -Tag 'Get' { + Describe 'MSFT_SqlDatabaseRole\Get-TargetResource' -Tag 'Get' { BeforeEach { Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable } @@ -248,10 +258,9 @@ try Role = $mockSqlDatabaseRole } - $throwInvalidOperation = ("Database 'unknownDatabaseName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.DatabaseNotFound -f $testParameters.Database - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -268,10 +277,9 @@ try Role = 'unknownRoleName' } - $throwInvalidOperation = ("Role 'unknownRoleName' does not exist on database " + ` - "'AdventureWorks' on SQL server 'localhost\MSSQLSERVER'.") + $errorMessage = $script:localizedData.RoleNotFound -f $testParameters.Role, $testParameters.Database - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Get-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -305,10 +313,10 @@ try Role = $mockSqlDatabaseRole } - $throwInvalidOperation = ("Login 'unknownLoginName' does not exist " + ` - "on SQL server 'localhost\MSSQLSERVER'.") - { Get-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + $errorMessage = $script:localizedData.LoginNotFound -f $testParameters.Name + + { Get-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -604,11 +612,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ('Failed adding the login John as a user of the database AdventureWorks, on ' + ` - 'the instance localhost\MSSQLSERVER. InnerException: Exception calling "Create" ' + ` - 'with "0" argument(s): "Mock Create Method was called with invalid operation."') + $errorMessage = $script:localizedData.FailedToAddUser -f $testParameters.Name, $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -659,12 +665,9 @@ try Ensure = 'Present' } - $throwInvalidOperation = ('Failed adding the login CONTOSO\KingJulian to the role MySecondRole on ' + ` - 'the database AdventureWorks, on the instance localhost\MSSQLSERVER. ' + ` - 'InnerException: Exception calling "AddMember" with "1" argument(s): ' + ` - '"Mock AddMember Method was called with invalid operation."') + $errorMessage = $script:localizedData.FailedToAddUserToRole -f $testParameters.Name, $testParameters.Role, $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { @@ -714,12 +717,9 @@ try Ensure = 'Absent' } - $throwInvalidOperation = ('Failed removing the login CONTOSO\SQLAdmin from the role MyRole on ' + ` - 'the database AdventureWorks, on the instance localhost\MSSQLSERVER. ' + ` - 'InnerException: Exception calling "DropMember" with "1" argument(s): ' + ` - '"Mock DropMember Method was called with invalid operation."') + $errorMessage = $script:localizedData.FailedToDropUserFromRole -f $testParameters.Name, $testParameters.Role, $testParameters.Database - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + { Set-TargetResource @testParameters } | Should -Throw $errorMessage } It 'Should call the mock function Connect-SQL' { diff --git a/Tests/Unit/MSFT_SqlRS.Tests.ps1 b/Tests/Unit/MSFT_SqlRS.Tests.ps1 index c451117ed..067ad4db7 100644 --- a/Tests/Unit/MSFT_SqlRS.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlRS.Tests.ps1 @@ -99,13 +99,6 @@ try } } - $mockGetItemProperty = { - return @{ - InstanceName = $mockInstanceName - Version = $mockDynamic_SqlBuildVersion - } - } - $mockGetCimInstance_ConfigurationSetting_NamedInstance = { return @( ( @@ -157,12 +150,9 @@ try Describe "SqlRS\Get-TargetResource" -Tag 'Get' { BeforeAll { - $mockDynamic_SqlBuildVersion = '13.0.4001.0' - - Mock -CommandName Get-ItemProperty -MockWith $mockGetItemProperty -Verifiable Mock -CommandName Invoke-RsCimMethod -MockWith $mockInvokeRsCimMethod_ListReservedUrls -ParameterFilter { $MethodName -eq 'ListReservedUrls' - } -Verifiable + } <# This is mocked here so that no calls are made to it directly, @@ -179,19 +169,20 @@ try Context 'When the system is in the desired state' { BeforeAll { + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + ReportsApplicationName = 'ReportServerWebApp' + SqlVersion = 13 + } + } + $mockDynamicReportServerApplicationName = $mockReportServerApplicationName $mockDynamicReportsApplicationName = $mockReportsApplicationName $mockDynamicReportsApplicationUrlString = $mockReportsApplicationUrl $mockDynamicReportServerApplicationUrlString = $mockReportServerApplicationUrl } - BeforeEach { - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_ConfigurationSetting_NamedInstance ` - -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` - -Verifiable - } - $mockDynamicIsInitialized = $true It 'Should return the same values as passed as parameters' { $resultGetTargetResource = Get-TargetResource @defaultParameters @@ -239,10 +230,13 @@ try Context 'When the system is not in the desired state' { BeforeEach { - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_ConfigurationSetting_DefaultInstance ` - -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` - -Verifiable + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] + ReportsApplicationName = 'ReportServerWebApp' + SqlVersion = 13 + } + } $testParameters = $defaultParameters.Clone() $testParameters['InstanceName'] = $mockDefaultInstanceName @@ -290,28 +284,29 @@ try $resultGetTargetResource.IsInitialized | Should -Be $false } } + } - Context 'When there is no Reporting Services instance' { - BeforeEach { - Mock -CommandName Get-ItemProperty + Context 'When there is no Reporting Services instance' { + BeforeAll { + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = $null + } } + } - It 'Should throw the correct error message' { - { Get-TargetResource @defaultParameters } | Should -Throw 'SQL Reporting Services instance ''INSTANCE'' does not exist!' - } + It 'Should throw the correct error message' { + { Get-TargetResource @defaultParameters } | Should -Throw 'SQL Reporting Services instance ''INSTANCE'' does not exist!' } } - - Assert-VerifiableMock } Describe "SqlRS\Set-TargetResource" -Tag 'Set' { BeforeAll { - Mock -CommandName Import-SQLPSModule -Verifiable - Mock -CommandName Invoke-Sqlcmd -Verifiable - Mock -CommandName Get-ItemProperty -MockWith $mockGetItemProperty -Verifiable - Mock -CommandName Restart-ReportingServicesService -Verifiable - Mock -CommandName Invoke-RsCimMethod -Verifiable + Mock -CommandName Import-SQLPSModule + Mock -CommandName Invoke-Sqlcmd + Mock -CommandName Restart-ReportingServicesService + Mock -CommandName Invoke-RsCimMethod Mock -CommandName Invoke-RsCimMethod -MockWith $mockInvokeRsCimMethod_GenerateDatabaseCreationScript -ParameterFilter { $MethodName -eq 'GenerateDatabaseCreationScript' } @@ -332,274 +327,386 @@ try $mockDynamicReportServerApplicationUrlString = $mockReportServerApplicationUrl } - Context 'When the system is not in the desired state' { - Context 'When configuring a named instance that are not initialized' { - BeforeAll { - $mockDynamic_SqlBuildVersion = '13.0.4001.0' - $mockDynamicIsInitialized = $false - Mock -CommandName Test-TargetResource -MockWith { - return $true - } + $sqlVersions = @( + @{ + VersionName = "SQL Server Reporting Services 2016" + Version = 13 + } + @{ + VersionName = "SQL Server Reporting Services 2017" + Version = 14 + } + ) + foreach($sqlVersion in $sqlVersions) + { + Context "When the system is not in the desired state ($($sqlVersion.VersionName))" { + Context "When configuring a named instance that are not initialized ($($sqlVersion.VersionName))" { + BeforeAll { + $mockDynamicIsInitialized = $false + + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + ReportsApplicationName = 'ReportServerWebApp' + SqlVersion = $sqlVersion.Version + } + } - $defaultParameters = @{ - InstanceName = $mockNamedInstanceName - DatabaseServerName = $mockReportingServicesDatabaseServerName - DatabaseInstanceName = $mockReportingServicesDatabaseNamedInstanceName - UseSsl = $true + Mock -CommandName Test-TargetResource -MockWith { + return $true + } + + $defaultParameters = @{ + InstanceName = $mockNamedInstanceName + DatabaseServerName = $mockReportingServicesDatabaseServerName + DatabaseInstanceName = $mockReportingServicesDatabaseNamedInstanceName + UseSsl = $true + } } - } - BeforeEach { - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_ConfigurationSetting_NamedInstance ` - -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` - -Verifiable + BeforeEach { + Mock -CommandName Get-CimInstance ` + -MockWith $mockGetCimInstance_Language ` + -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter + } - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_Language ` - -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter ` - -Verifiable - } + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @defaultParameters } | Should -Not -Throw - It 'Should configure Reporting Service without throwing an error' { - { Set-TargetResource @defaultParameters } | Should -Not -Throw + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetSecureConnectionLevel' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetSecureConnectionLevel' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' - } -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'InitializeReportServer' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'InitializeReportServer' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetDatabaseConnection' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetDatabaseConnection' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseRightsScript' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseRightsScript' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseCreationScript' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseCreationScript' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 1 -Scope It + } - Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 1 -Scope It - } + Context 'When there is no Reporting Services instance after Set-TargetResource has been called' { + BeforeEach { + Mock -CommandName Get-ItemProperty + Mock -CommandName Test-TargetResource + } - Context 'When there is no Reporting Services instance after Set-TargetResource has been called' { - BeforeEach { - Mock -CommandName Get-ItemProperty -Verifiable - Mock -CommandName Test-TargetResource -Verifiable + It 'Should throw the correct error message' { + { Set-TargetResource @defaultParameters } | Should -Throw $script:localizedData.TestFailedAfterSet + } } - It 'Should throw the correct error message' { - { Set-TargetResource @defaultParameters } | Should -Throw 'Test-TargetResource returned false after calling set.' + Context 'When it is not possible to evaluate OSLanguage' { + BeforeEach { + Mock -CommandName Get-CimInstance -MockWith { + return $null + } -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter } + + It 'Should throw the correct error message' { + { Set-TargetResource @defaultParameters } | Should -Throw 'Unable to find WMI object Win32_OperatingSystem.' + } } } - Context 'When it is not possible to evaluate OSLanguage' { - BeforeEach { - Mock -CommandName Get-CimInstance -MockWith { - return $null - } -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter -Verifiable } + Context "When configuring a named instance that are already initialized ($($sqlVersion.VersionName))" { + BeforeAll { + $mockDynamicIsInitialized = $true - It 'Should throw the correct error message' { - { Set-TargetResource @defaultParameters } | Should -Throw 'Unable to find WMI object Win32_OperatingSystem.' - } - } - } + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + ReportsApplicationName = 'ReportServerWebApp' + SqlVersion = $sqlVersion.Version + } + } - Context 'When configuring a named instance that are already initialized' { - BeforeAll { - $mockDynamic_SqlBuildVersion = '13.0.4001.0' - $mockDynamicIsInitialized = $true + Mock -CommandName Get-TargetResource -MockWith { + return @{ + ReportServerReservedUrl = $mockReportServerApplicationUrl + ReportsReservedUrl = $mockReportsApplicationUrl + } + } - Mock -CommandName Get-TargetResource -MockWith { - return @{ - ReportServerReservedUrl = $mockReportServerApplicationUrl - ReportsReservedUrl = $mockReportsApplicationUrl + Mock -CommandName Test-TargetResource -MockWith { + return $true + } + + $testParameters = @{ + InstanceName = $mockNamedInstanceName + DatabaseServerName = $mockReportingServicesDatabaseServerName + DatabaseInstanceName = $mockReportingServicesDatabaseNamedInstanceName + ReportServerVirtualDirectory = 'ReportServer_NewName' + ReportsVirtualDirectory = 'Reports_NewName' + ReportServerReservedUrl = 'https://+:4443' + ReportsReservedUrl = 'https://+:4443' + UseSsl = $true } } - Mock -CommandName Test-TargetResource -MockWith { - return $true + BeforeEach { + Mock -CommandName Get-CimInstance ` + -MockWith $mockGetCimInstance_Language ` + -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter } - $testParameters = @{ - InstanceName = $mockNamedInstanceName - DatabaseServerName = $mockReportingServicesDatabaseServerName - DatabaseInstanceName = $mockReportingServicesDatabaseNamedInstanceName - ReportServerVirtualDirectory = 'ReportServer_NewName' - ReportsVirtualDirectory = 'Reports_NewName' - ReportServerReservedUrl = 'https://+:4443' - ReportsReservedUrl = 'https://+:4443' - UseSsl = $true + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @testParameters } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetSecureConnectionLevel' + } -Exactly -Times 1 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 2 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 2 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'InitializeReportServer' + } -Exactly -Times 0 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetDatabaseConnection' + } -Exactly -Times 0 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseRightsScript' + } -Exactly -Times 0 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseCreationScript' + } -Exactly -Times 0 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 2 -Scope It + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 2 -Scope It + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 1 -Scope It } } - BeforeEach { - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_ConfigurationSetting_NamedInstance ` - -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` - -Verifiable + Context "When configuring a named instance that are already initialized ($($sqlVersion.VersionName)), suppress restart" { + BeforeAll { + $mockDynamicIsInitialized = $true - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_Language ` - -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter ` - -Verifiable - } + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_NamedInstance)[0] + ReportsApplicationName = 'ReportServerWebApp' + SqlVersion = $sqlVersion.Version + } + } - It 'Should configure Reporting Service without throwing an error' { - { Set-TargetResource @testParameters } | Should -Not -Throw + Mock -CommandName Get-TargetResource -MockWith { + return @{ + ReportServerReservedUrl = $mockReportServerApplicationUrl + ReportsReservedUrl = $mockReportsApplicationUrl + } + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetSecureConnectionLevel' - } -Exactly -Times 1 -Scope It + Mock -CommandName Test-TargetResource -MockWith { + return $true + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + $testParameters = @{ + InstanceName = $mockNamedInstanceName + DatabaseServerName = $mockReportingServicesDatabaseServerName + DatabaseInstanceName = $mockReportingServicesDatabaseNamedInstanceName + ReportServerVirtualDirectory = 'ReportServer_NewName' + ReportsVirtualDirectory = 'Reports_NewName' + ReportServerReservedUrl = 'https://+:4443' + ReportsReservedUrl = 'https://+:4443' + UseSsl = $true + SuppressRestart = $true + } + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + BeforeEach { + Mock -CommandName Get-CimInstance ` + -MockWith $mockGetCimInstance_Language ` + -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'InitializeReportServer' - } -Exactly -Times 0 -Scope It + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @testParameters } | Should -Not -Throw - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetDatabaseConnection' - } -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetSecureConnectionLevel' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseRightsScript' - } -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseCreationScript' - } -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'InitializeReportServer' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetDatabaseConnection' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseRightsScript' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName - } -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseCreationScript' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 0 -Scope It - } - } + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Context 'When configuring a default instance that are not initialized' { - BeforeAll { - $mockDynamic_SqlBuildVersion = '12.0.4100.1' - $mockDynamicIsInitialized = $false + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 1 -Scope It - Mock -CommandName Test-TargetResource -MockWith { - return $true - } -Verifiable + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 2 -Scope It - $defaultParameters = @{ - InstanceName = $mockDefaultInstanceName - DatabaseServerName = $mockReportingServicesDatabaseServerName - DatabaseInstanceName = $mockReportingServicesDatabaseDefaultInstanceName + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationName + } -Exactly -Times 2 -Scope It + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 0 -Scope It + Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 0 -Scope It } } - BeforeEach { - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_ConfigurationSetting_DefaultInstance ` - -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` - -Verifiable + Context "When configuring a default instance that are not initialized ($($sqlVersion.VersionName))" { + BeforeAll { + $mockDynamicIsInitialized = $false - Mock -CommandName Get-CimInstance ` - -MockWith $mockGetCimInstance_Language ` - -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter ` - -Verifiable - } + Mock -CommandName Test-TargetResource -MockWith { + return $true + } - It 'Should configure Reporting Service without throwing an error' { - { Set-TargetResource @defaultParameters } | Should -Not -Throw + $defaultParameters = @{ + InstanceName = $mockDefaultInstanceName + DatabaseServerName = $mockReportingServicesDatabaseServerName + DatabaseInstanceName = $mockReportingServicesDatabaseDefaultInstanceName + } + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'RemoveURL' - } -Exactly -Times 0 -Scope It + BeforeEach { + # This mocks the SQL Server Reporting Services 2014 and older + Mock -CommandName Get-ReportingServicesData -MockWith { + return @{ + Configuration = (& $mockGetCimInstance_ConfigurationSetting_DefaultInstance)[0] + ReportsApplicationName = 'ReportManager' + SqlVersion = $sqlVersion.Version + } + } - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'InitializeReportServer' - } -Exactly -Times 1 -Scope It + Mock -CommandName Get-CimInstance ` + -MockWith $mockGetCimInstance_Language ` + -ParameterFilter $mockGetCimInstance_OperatingSystem_ParameterFilter + } + + It 'Should configure Reporting Service without throwing an error' { + { Set-TargetResource @defaultParameters } | Should -Not -Throw + + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'RemoveURL' + } -Exactly -Times 0 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetDatabaseConnection' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'InitializeReportServer' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseRightsScript' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetDatabaseConnection' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'GenerateDatabaseCreationScript' - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseRightsScript' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'GenerateDatabaseCreationScript' + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'SetVirtualDirectory' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { - $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy - } -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportServerApplicationName + } -Exactly -Times 1 -Scope It - Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 2 -Scope It - Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-RsCimMethod -ParameterFilter { + $MethodName -eq 'ReserveUrl' -and $Arguments.Application -eq $mockReportsApplicationNameLegacy + } -Exactly -Times 1 -Scope It + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Invoke-Sqlcmd -Exactly -Times 2 -Scope It + Assert-MockCalled -CommandName Restart-ReportingServicesService -Exactly -Times 1 -Scope It + } } } } - - Assert-VerifiableMock } Describe "SqlRS\Test-TargetResource" -Tag 'Test' { @@ -610,7 +717,7 @@ try return @{ IsInitialized = $false } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -633,7 +740,7 @@ try ReportServerVirtualDirectory = $mockVirtualDirectoryReportServerName ReportsVirtualDirectory = $mockVirtualDirectoryReportsName } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -658,7 +765,7 @@ try ReportServerVirtualDirectory = $mockVirtualDirectoryReportServerName ReportsVirtualDirectory = $mockVirtualDirectoryReportsName } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -682,7 +789,7 @@ try IsInitialized = $true ReportServerReservedUrl = $mockReportServerApplicationUrl } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -705,7 +812,7 @@ try IsInitialized = $true ReportsReservedUrl = $mockReportServerApplicationUrl } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -730,7 +837,7 @@ try IsInitialized = $true UseSsl = $false } - } -Verifiable + } $testParameters = @{ InstanceName = $mockNamedInstanceName @@ -753,7 +860,7 @@ try return @{ IsInitialized = $true } - } -Verifiable + } $defaultParameters = @{ InstanceName = $mockNamedInstanceName @@ -767,8 +874,6 @@ try $resultTestTargetResource | Should -Be $true } } - - Assert-VerifiableMock } Describe "SqlRS\Invoke-RsCimMethod" -Tag 'Helper' { @@ -785,7 +890,7 @@ try return @{ HRESULT = 0 } - } -Verifiable + } } Context 'When calling Invoke-CimMethod without arguments' { @@ -832,7 +937,7 @@ try HRESULT = 1 Error = 'Something went wrong' } - } -Verifiable + } } It 'Should call Invoke-CimMethod and throw the correct error' { @@ -855,7 +960,7 @@ try return New-Object -TypeName Object | Add-Member -MemberType NoteProperty -Name 'HRESULT' -Value 1 -PassThru | Add-Member -MemberType NoteProperty -Name 'ExtendedErrors' -Value @('Something went wrong', 'Another thing went wrong') -PassThru -Force - } -Verifiable + } } It 'Should call Invoke-CimMethod and throw the correct error' { @@ -872,8 +977,170 @@ try } } } + } + + Describe 'SqlRS\Get-ReportingServicesData' -Tag 'Helper' { + BeforeAll { + $mockInstanceId = 'MSRS13.{0}' -f $mockNamedInstanceName + $mockGetItemProperty_InstanceNames = { + return @{ + $mockNamedInstanceName = $mockInstanceId + } + } - Assert-VerifiableMock + $mockGetItemProperty_InstanceNames_ParameterFilter = { + $Path -eq 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\RS' + } + + $mockSql2014Version = '12.0.6024.0' + $mockGetItemProperty_Sql2014 = { + return @{ + Version = $mockSql2014Version + } + } + + $mockSql2016Version = '13.0.4001.0' + $mockGetItemProperty_Sql2016 = { + return @{ + Version = $mockSql2016Version + } + } + + $mockSql2017Version = '14.0.6514.11481' + $mockGetItemProperty_Sql2017 = { + return @{ + CurrentVersion = $mockSql2017Version + } + } + + $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter = { + $Path -eq ('HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{0}\Setup' -f $mockInstanceId) + } + + $mockGetItemProperty_Sql2017_ParameterFilter = { + $Path -eq ('HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\{0}\MSSQLServer\CurrentVersion' -f $mockInstanceId) + } + + $mockDynamicIsInitialized = $false + $mockDynamicSecureConnectionLevel = 0 + } + + Context 'When there is a Reporting Services instance' { + BeforeEach { + Mock -CommandName Get-ItemProperty ` + -MockWith $mockGetItemProperty_InstanceNames ` + -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter + + Mock -CommandName Get-CimInstance ` + -MockWith $mockGetCimInstance_ConfigurationSetting_NamedInstance ` + -ParameterFilter $mockGetCimInstance_ConfigurationSetting_ParameterFilter ` + } + + Context 'When the instance is SQL Server Reporting Services 2014 or older' { + BeforeEach { + Mock -CommandName Test-Path -MockWith { + return $false + } + + Mock -CommandName Get-ItemProperty ` + -MockWith $mockGetItemProperty_Sql2014 ` + -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter + } + + It 'Should return the correct information' { + $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName $mockNamedInstanceName + $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] + $getReportingServicesDataResult.Configuration.InstanceName | Should -Be $mockNamedInstanceName + $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" + $getReportingServicesDataResult.Configuration.IsInitialized | Should -Be $false + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be $mockVirtualDirectoryReportServerName + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be $mockVirtualDirectoryReportManagerName + $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 + $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportManager' + $getReportingServicesDataResult.SqlVersion | Should -Be $mockSql2014Version.Split('.')[0] + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` + -Exactly -Times 2 -Scope 'It' + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter ` + -Exactly -Times 1 -Scope 'It' + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' + } + } + + Context 'When the instance is SQL Server Reporting Services 2016' { + BeforeEach { + Mock -CommandName Test-Path -MockWith { + return $false + } + + Mock -CommandName Get-ItemProperty ` + -MockWith $mockGetItemProperty_Sql2016 ` + -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter + } + + It 'Should return the correct information' { + $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName $mockNamedInstanceName + $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] + $getReportingServicesDataResult.Configuration.InstanceName | Should -Be $mockNamedInstanceName + $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" + $getReportingServicesDataResult.Configuration.IsInitialized | Should -Be $false + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be $mockVirtualDirectoryReportServerName + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be $mockVirtualDirectoryReportManagerName + $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 + $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportServerWebApp' + $getReportingServicesDataResult.SqlVersion | Should -Be $mockSql2016Version.Split('.')[0] + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` + -Exactly -Times 2 -Scope 'It' + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_Sql2014AndSql2016_ParameterFilter ` + -Exactly -Times 1 -Scope 'It' + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' + } + } + + Context 'When the instance is SQL Server Reporting Services 2017' { + BeforeEach { + Mock -CommandName Test-Path -MockWith { + return $true + } + + Mock -CommandName Get-ItemProperty ` + -MockWith $mockGetItemProperty_Sql2017 ` + -ParameterFilter $mockGetItemProperty_Sql2017_ParameterFilter + } + + It 'Should return the correct information' { + $getReportingServicesDataResult = Get-ReportingServicesData -InstanceName $mockNamedInstanceName + $getReportingServicesDataResult.Configuration | Should -BeOfType [Microsoft.Management.Infrastructure.CimInstance] + $getReportingServicesDataResult.Configuration.InstanceName | Should -Be $mockNamedInstanceName + $getReportingServicesDataResult.Configuration.DatabaseServerName | Should -Be "$mockReportingServicesDatabaseServerName\$mockReportingServicesDatabaseNamedInstanceName" + $getReportingServicesDataResult.Configuration.IsInitialized | Should -Be $false + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportServer | Should -Be $mockVirtualDirectoryReportServerName + $getReportingServicesDataResult.Configuration.VirtualDirectoryReportManager | Should -Be $mockVirtualDirectoryReportManagerName + $getReportingServicesDataResult.Configuration.SecureConnectionLevel | Should -Be 0 + $getReportingServicesDataResult.ReportsApplicationName | Should -Be 'ReportServerWebApp' + $getReportingServicesDataResult.SqlVersion | Should -Be $mockSql2017Version.Split('.')[0] + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_InstanceNames_ParameterFilter ` + -Exactly -Times 2 -Scope 'It' + + Assert-MockCalled -CommandName Get-ItemProperty ` + -ParameterFilter $mockGetItemProperty_Sql2017_ParameterFilter ` + -Exactly -Times 1 -Scope 'It' + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope 'It' + } + } + } } } } diff --git a/Tests/Unit/MSFT_SqlScript.Tests.ps1 b/Tests/Unit/MSFT_SqlScript.Tests.ps1 index cb560a952..a961049ad 100644 --- a/Tests/Unit/MSFT_SqlScript.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlScript.Tests.ps1 @@ -41,12 +41,14 @@ $TestEnvironment = Initialize-TestEnvironment ` #endregion HEADER -function Invoke-TestSetup { +function Invoke-TestSetup +{ # Loading mocked classes Add-Type -Path (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs') -ChildPath 'SqlPowerShellSqlExecutionException.cs') } -function Invoke-TestCleanup { +function Invoke-TestCleanup +{ Restore-TestEnvironment -TestEnvironment $TestEnvironment } @@ -156,44 +158,59 @@ try } Describe 'MSFT_SqlScript\Test-TargetResource' { - Context 'When Test-TargetResource runs script without issue' { - Mock -CommandName Invoke-SqlScript + Context 'When the system is in the desired state' { + Context 'When Test-TargetResource runs script without issue' { + Mock -CommandName Invoke-SqlScript - It 'Should return true' { - $result = Test-TargetResource @testParameters - $result | Should -Be $true + It 'Should return true' { + $result = Test-TargetResource @testParameters + $result | Should -Be $true + } } - } - Context 'When Test-TargetResource runs script without issue with timeout' { - Mock -CommandName Invoke-SqlScript + Context 'When Test-TargetResource runs script without issue with timeout' { + Mock -CommandName Invoke-SqlScript - It 'Should return true' { - $result = Test-TargetResource @testParametersTimeout - $result | Should -Be $true + It 'Should return true' { + $result = Test-TargetResource @testParametersTimeout + $result | Should -Be $true + } } } - Context 'When Test-TargetResource throws the exception SqlPowerShellSqlExecutionException when running the script in the TestFilePath parameter' { - Mock -CommandName Invoke-SqlScript -MockWith { - throw New-Object -TypeName Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException - } + Context 'When the system is not in the desired state' { + Context 'When Invoke-SqlScript returns an SQL error code from the script that was ran' { + Mock -CommandName Invoke-SqlScript -MockWith { + return 1 + } - It 'Should return false' { - $result = Test-TargetResource @testParameters - $result | Should -Be $false + It 'Should return false' { + $result = Test-TargetResource @testParametersTimeout + $result | Should -Be $false + } } - } - Context 'When Test-TargetResource throws an unexpected error when running the script in the TestFilePath parameter' { - $errorMessage = "Failed to run SQL Script" + Context 'When Test-TargetResource throws the exception SqlPowerShellSqlExecutionException when running the script in the TestFilePath parameter' { + Mock -CommandName Invoke-SqlScript -MockWith { + throw New-Object -TypeName Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException + } - Mock -CommandName Invoke-SqlScript -MockWith { - throw $errorMessage + It 'Should return false' { + $result = Test-TargetResource @testParameters + $result | Should -Be $false + } } - It 'Should throw the correct error from Invoke-Sqlcmd' { - { Test-TargetResource @testParameters } | Should -Throw $errorMessage + Context 'When Test-TargetResource throws an unexpected error when running the script in the TestFilePath parameter' { + $errorMessage = "Failed to run SQL Script" + + Mock -CommandName Invoke-SqlScript -MockWith { + throw $errorMessage + } + + It 'Should throw the correct error from Invoke-Sqlcmd' { + { Test-TargetResource @testParameters } | Should -Throw $errorMessage + } } } } diff --git a/Tests/Unit/MSFT_SqlScriptQuery.Tests.ps1 b/Tests/Unit/MSFT_SqlScriptQuery.Tests.ps1 index 9eeb4d83f..8c3fd3d7b 100644 --- a/Tests/Unit/MSFT_SqlScriptQuery.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlScriptQuery.Tests.ps1 @@ -41,7 +41,8 @@ $TestEnvironment = Initialize-TestEnvironment ` #endregion HEADER -function Invoke-TestSetup { +function Invoke-TestSetup +{ # Loading mocked classes Add-Type -Path (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs') -ChildPath 'SqlPowerShellSqlExecutionException.cs') @@ -49,7 +50,8 @@ function Invoke-TestSetup { Import-Module -Name (Join-Path -Path (Join-Path -Path $PSScriptRoot -ChildPath 'Stubs') -ChildPath 'SQLPSStub.psm1') -Force -Global } -function Invoke-TestCleanup { +function Invoke-TestCleanup +{ Restore-TestEnvironment -TestEnvironment $TestEnvironment } @@ -159,44 +161,58 @@ try } Describe 'MSFT_SqlScriptQuery\Test-TargetResource' { - Context 'Test-TargetResource runs script without issue' { - Mock -CommandName Invoke-SqlScript + Context 'When the system is in the desired state' { + Context 'Test-TargetResource runs script without issue' { + Mock -CommandName Invoke-SqlScript - It 'Should return true' { - $result = Test-TargetResource @testParameters - $result | Should -Be $true + It 'Should return true' { + $result = Test-TargetResource @testParameters + $result | Should -Be $true + } } - } - Context 'Test-TargetResource runs script without issue with timeout' { - Mock -CommandName Invoke-SqlScript + Context 'Test-TargetResource runs script without issue with timeout' { + Mock -CommandName Invoke-SqlScript - It 'Should return true' { - $result = Test-TargetResource @testParametersTimeout - $result | Should -Be $true + It 'Should return true' { + $result = Test-TargetResource @testParametersTimeout + $result | Should -Be $true + } } } - Context 'Test-TargetResource throws the exception SqlPowerShellSqlExecutionException when running the script in the TestFilePath parameter' { - Mock -CommandName Invoke-SqlScript -MockWith { - throw New-Object -TypeName Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException + Context 'When the system is not in the desired state' { + Context 'When Invoke-SqlScript returns an SQL error code from the query that was ran' { + Mock -CommandName Invoke-SqlScript -MockWith { + return 1 + } + It 'Should return false' { + $result = Test-TargetResource @testParametersTimeout + $result | Should -Be $false + } } - It 'Should return false' { - $result = Test-TargetResource @testParameters - $result | Should -Be $false + Context 'Test-TargetResource throws the exception SqlPowerShellSqlExecutionException when running the script in the TestFilePath parameter' { + Mock -CommandName Invoke-SqlScript -MockWith { + throw New-Object -TypeName Microsoft.SqlServer.Management.PowerShell.SqlPowerShellSqlExecutionException + } + + It 'Should return false' { + $result = Test-TargetResource @testParameters + $result | Should -Be $false + } } - } - Context 'Test-TargetResource throws an unexpected error when running the script in the TestFilePath parameter' { - $errorMessage = "Failed to run SQL Script" + Context 'Test-TargetResource throws an unexpected error when running the script in the TestFilePath parameter' { + $errorMessage = "Failed to run SQL Script" - Mock -CommandName Invoke-SqlScript -MockWith { - throw $errorMessage - } + Mock -CommandName Invoke-SqlScript -MockWith { + throw $errorMessage + } - It 'Should throw the correct error from Invoke-Sqlcmd' { - { Test-TargetResource @testParameters } | Should -Throw $errorMessage + It 'Should throw the correct error from Invoke-Sqlcmd' { + { Test-TargetResource @testParameters } | Should -Throw $errorMessage + } } } } diff --git a/Tests/Unit/MSFT_SqlServerEndpoint.Tests.ps1 b/Tests/Unit/MSFT_SqlServerEndpoint.Tests.ps1 index 86843d44b..3cbec6c3e 100644 --- a/Tests/Unit/MSFT_SqlServerEndpoint.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerEndpoint.Tests.ps1 @@ -227,7 +227,7 @@ try Context 'When endpoint exist but with wrong endpoint type' { It 'Should throw the correct error' { - { Get-TargetResource @testParameters } | Should -Throw 'Endpoint ''DefaultEndpointMirror'' does exist, but it is not of type ''DatabaseMirroring''.' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointFoundButWrongType -f $testParameters.EndpointName) } } @@ -241,7 +241,7 @@ try return $null } - { Get-TargetResource @testParameters } | Should -Throw 'Was unable to connect to the instance ''localhost\INSTANCE1''' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.NotConnectedToInstance -f $testParameters.ServerName, $testParameters.InstanceName) } } @@ -583,7 +583,7 @@ try } } -Verifiable - { Set-TargetResource @testParameters } | Should -Throw 'Endpoint ''DefaultEndpointMirror'' does not exist' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointNotFound -f $testParameters.EndpointName) } } @@ -600,7 +600,7 @@ try $testParameters.Add('Ensure', 'Absent') - { Set-TargetResource @testParameters } | Should -Throw 'Endpoint ''DefaultEndpointMirror'' does not exist' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointNotFound -f $testParameters.EndpointName) } } @@ -611,7 +611,7 @@ try return $null } - { Set-TargetResource @testParameters } | Should -Throw 'Was unable to connect to the instance ''localhost\INSTANCE1''' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.NotConnectedToInstance -f $testParameters.ServerName, $testParameters.InstanceName) } } } diff --git a/Tests/Unit/MSFT_SqlServerEndpointPermission.Tests.ps1 b/Tests/Unit/MSFT_SqlServerEndpointPermission.Tests.ps1 index 3202edffb..e07e4ac21 100644 --- a/Tests/Unit/MSFT_SqlServerEndpointPermission.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerEndpointPermission.Tests.ps1 @@ -147,7 +147,7 @@ try Context 'When endpoint is missing' { It 'Should throw the correct error message' { - { Get-TargetResource @testParameters } | Should -Throw 'Got unexpected result from Get-TargetResource. No change is made. InnerException: Endpoint ''DefaultEndpointMirror'' does not exist' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.UnexpectedErrorFromGet -f $testParameters.Name) Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -296,7 +296,7 @@ try } } -Verifiable - { Set-TargetResource @testParameters } | Should -Throw 'Endpoint ''DefaultEndpointMirror'' does not exist' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointNotFound -f $testParameters.Name) Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } diff --git a/Tests/Unit/MSFT_SqlServerEndpointState.Tests.ps1 b/Tests/Unit/MSFT_SqlServerEndpointState.Tests.ps1 index 7f90c553e..cb006d4e9 100644 --- a/Tests/Unit/MSFT_SqlServerEndpointState.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerEndpointState.Tests.ps1 @@ -143,7 +143,7 @@ try Context 'When endpoint is missing' { It 'Should throw the correct error message' { - { Get-TargetResource @testParameters } | Should -Throw 'Unexpected result when trying to verify existence of endpoint ''DefaultEndpointMirror''. InnerException: Endpoint ''DefaultEndpointMirror'' does not exist' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.EndpointErrorVerifyExist -f $testParameters.Name) Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope It } @@ -267,7 +267,7 @@ try return $null } -Verifiable - { Test-TargetResource @testParameters } | Should -Throw 'Got unexpected result from Get-TargetResource. No change is made.' + { Test-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet Assert-MockCalled Connect-SQL -Exactly -Times 0 -Scope It } @@ -342,7 +342,7 @@ try return $null } -Verifiable - { Set-TargetResource @testParameters } | Should -Throw 'Got unexpected result from Get-TargetResource. No change is made.' + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.UnexpectedErrorFromGet Assert-MockCalled Connect-SQL -Exactly -Times 0 -Scope It } diff --git a/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 b/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 index 218f6ea5e..b5c531830 100644 --- a/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 @@ -487,7 +487,7 @@ try $result | Should -Be $false } - It 'Should throw exception when unkown error occurred and account is disabled' { + It 'Should throw exception when unknown error occurred and account is disabled' { $mockTestTargetResourceParameters = $getTargetResource_KnownSqlLogin.Clone() $mockTestTargetResourceParameters.Add('Ensure', 'Present') $mockTestTargetResourceParameters.Add('Disabled', $true) @@ -512,10 +512,11 @@ try } # Call the test target - { Test-TargetResource @mockTestTargetResourceParameters } | Should -Throw + $errorMessage = $script:localizedData.PasswordValidationError + { Test-TargetResource @mockTestTargetResourceParameters } | Should -Throw $errorMessage Assert-MockCalled -CommandName Get-TargetResource -Scope It -Times 1 -Exactly - Assert-MockCAlled -CommandName Connect-SQL -Scope It -Times 1 -Exactly + Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly } } @@ -692,6 +693,23 @@ try Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly } + + It 'Should be return $false when a login has the wrong login type' { + $mockTestTargetResourceParameters = $instanceParameters.Clone() + $mockTestTargetResourceParameters.Add( 'Ensure', 'Present' ) + <# + Use WindowsLogin format here to be able to test the + specific property LoginType. + #> + $mockTestTargetResourceParameters.Add( 'Name', 'Windows\UserDisabled' ) + $mockTestTargetResourceParameters.Add( 'LoginType', 'SqlLogin' ) + $mockTestTargetResourceParameters.Add( 'Disabled', $true ) + + $result = Test-TargetResource @mockTestTargetResourceParameters + $result | Should -Be $false + + Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly + } } } @@ -945,7 +963,8 @@ try $setTargetResource_CertificateAbsent_EnsurePresent = $setTargetResource_CertificateAbsent.Clone() $setTargetResource_CertificateAbsent_EnsurePresent.Add( 'Ensure', 'Present' ) - { Set-TargetResource @setTargetResource_CertificateAbsent_EnsurePresent } | Should -Throw 'LoginTypeNotImplemented' + $errorMessage = $script:localizedData.LoginTypeNotImplemented -f $setTargetResource_CertificateAbsent_EnsurePresent.LoginType + { Set-TargetResource @setTargetResource_CertificateAbsent_EnsurePresent } | Should -Throw $errorMessage Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly Assert-MockCalled -CommandName Update-SQLServerLogin -Scope It -Times 0 -Exactly @@ -960,7 +979,8 @@ try $setTargetResource_SqlLoginAbsent_EnsurePresent_NoCred = $setTargetResource_SqlLoginAbsent.Clone() $setTargetResource_SqlLoginAbsent_EnsurePresent_NoCred.Add( 'Ensure', 'Present' ) - { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent_NoCred } | Should -Throw 'LoginCredentialNotFound' + $errorMessage = $script:localizedData.LoginCredentialNotFound -f $setTargetResource_SqlLoginAbsent_EnsurePresent_NoCred.Name + { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent_NoCred } | Should -Throw $errorMessage Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly Assert-MockCalled -CommandName Update-SQLServerLogin -Scope It -Times 0 -Exactly @@ -1058,7 +1078,12 @@ try $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'Ensure', 'Present' ) $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'LoginCredential', $mockSqlLoginCredential ) - { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Throw 'IncorrectLoginMode' + $errorMessage = $script:localizedData.IncorrectLoginMode -f + $setTargetResource_SqlLoginAbsent_EnsurePresent.ServerName, + $setTargetResource_SqlLoginAbsent_EnsurePresent.InstanceName, + $mockLoginMode + + { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Throw $errorMessage Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly Assert-MockCalled -CommandName Update-SQLServerLogin -Scope It -Times 0 -Exactly @@ -1077,7 +1102,7 @@ try $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'Ensure', 'Present' ) $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'LoginCredential', $mockSqlLoginCredential ) - { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Not -Throw 'IncorrectLoginMode' + { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Not -Throw Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly Assert-MockCalled -CommandName Update-SQLServerLogin -Scope It -Times 0 -Exactly @@ -1095,7 +1120,7 @@ try $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'Ensure', 'Present' ) $setTargetResource_SqlLoginAbsent_EnsurePresent.Add( 'LoginCredential', $mockSqlLoginCredential ) - { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Not -Throw 'IncorrectLoginMode' + { Set-TargetResource @setTargetResource_SqlLoginAbsent_EnsurePresent } | Should -Not -Throw Assert-MockCalled -CommandName Connect-SQL -Scope It -Times 1 -Exactly Assert-MockCalled -CommandName Update-SQLServerLogin -Scope It -Times 0 -Exactly @@ -1121,7 +1146,9 @@ try $login.LoginType = 'WindowsUser' $login.MockLoginType = 'SqlLogin' - { Update-SQLServerLogin -Login $login } | Should -Throw 'AlterLoginFailed' + $errorMessage = $script:localizedData.AlterLoginFailed -f $login.Name + + { Update-SQLServerLogin -Login $login } | Should -Throw $errorMessage } } } @@ -1157,7 +1184,9 @@ try $login.LoginType = 'WindowsUser' $login.MockLoginType = 'SqlLogin' - { New-SQLServerLogin -Login $login } | Should -Throw 'LoginCreationFailedWindowsNotSpecified' + $errorMessage = $script:localizedData.CreateLoginFailed -f $login.Name + + { New-SQLServerLogin -Login $login } | Should -Throw $errorMessage } It 'Should throw the correct error when password validation fails when creating a SQL Login' { @@ -1170,7 +1199,9 @@ try LoginCreateOptions = 'None' } - { New-SQLServerLogin @createLoginParameters } | Should -Throw 'PasswordValidationFailed' + $errorMessage = $script:localizedData.CreateLoginFailedOnPassword -f $login.Name + + { New-SQLServerLogin @createLoginParameters } | Should -Throw $errorMessage } It 'Should throw the correct error when creating a SQL Login fails' { @@ -1183,7 +1214,9 @@ try LoginCreateOptions = 'None' } - { New-SQLServerLogin @createLoginParameters } | Should -Throw 'LoginCreationFailedFailedOperation' + $errorMessage = $script:localizedData.CreateLoginFailed -f $login.Name + + { New-SQLServerLogin @createLoginParameters } | Should -Throw $errorMessage } It 'Should throw the correct error when creating a SQL Login fails with an unhandled exception' { @@ -1196,7 +1229,9 @@ try LoginCreateOptions = 'None' } - { New-SQLServerLogin @createLoginParameters } | Should -Throw 'LoginCreationFailedSqlNotSpecified' + $errorMessage = $script:localizedData.CreateLoginFailed -f $login.Name + + { New-SQLServerLogin @createLoginParameters } | Should -Throw $errorMessage } } } @@ -1217,7 +1252,9 @@ try $login.LoginType = 'WindowsUser' $login.MockLoginType = 'SqlLogin' - { Remove-SQLServerLogin -Login $login } | Should -Throw 'DropLoginFailed' + $errorMessage = $script:localizedData.DropLoginFailed -f $login.Name + + { Remove-SQLServerLogin -Login $login } | Should -Throw $errorMessage } } } @@ -1241,7 +1278,9 @@ try SecureString = ConvertTo-SecureString -String 'pw' -AsPlainText -Force } - { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw 'PasswordValidationFailed' + $errorMessage = $script:localizedData.SetPasswordValidationFailed -f $setPasswordParameters.Login.Name + + { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw $errorMessage } It 'Should throw the correct error when changing the password fails' { @@ -1250,7 +1289,9 @@ try SecureString = ConvertTo-SecureString -String 'reused' -AsPlainText -Force } - { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw 'PasswordChangeFailed' + $errorMessage = $script:localizedData.SetPasswordFailed -f $setPasswordParameters.Login.Name + + { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw $errorMessage } It 'Should throw the correct error when changing the password fails' { @@ -1259,7 +1300,9 @@ try SecureString = ConvertTo-SecureString -String 'other' -AsPlainText -Force } - { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw 'PasswordChangeFailed' + $errorMessage = $script:localizedData.SetPasswordFailed -f $setPasswordParameters.Login.Name + + { Set-SQLServerLoginPassword @setPasswordParameters } | Should -Throw $errorMessage } } } diff --git a/Tests/Unit/MSFT_SqlServerMaxDop.Tests.ps1 b/Tests/Unit/MSFT_SqlServerMaxDop.Tests.ps1 index bdc09f063..fa416db03 100644 --- a/Tests/Unit/MSFT_SqlServerMaxDop.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerMaxDop.Tests.ps1 @@ -372,7 +372,7 @@ try } It 'Should throw the correct error' { - { Test-TargetResource @testParameters } | Should -Throw 'MaxDop parameter must be set to $null or not assigned if DynamicAlloc parameter is set to $true.' + { Test-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxDopParamMustBeNull } It 'Should call the mock function Connect-SQL' { @@ -418,7 +418,7 @@ try } It 'Should throw the correct error' { - { Set-TargetResource @testParameters } | Should -Throw 'MaxDop parameter must be set to $null or not assigned if DynamicAlloc parameter is set to $true.' + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxDopParamMustBeNull } It 'Should call the mock function Connect-SQL' { @@ -501,12 +501,8 @@ try Ensure = 'Present' } - It 'Shoud throw the correct error when Alter() method was called with invalid operation' { - $throwInvalidOperation = ('Unexpected result when trying to configure the max degree of parallelism ' + ` - 'server configuration option. InnerException: Exception calling "Alter" ' + ` - 'with "0" argument(s): "Mock Alter Method was called with invalid operation."') - - { Set-TargetResource @testParameters } | Should -Throw $throwInvalidOperation + It 'Should throw the correct error when Alter() method was called with invalid operation' { + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxDopSetError } It 'Should call the mock function Connect-SQL' { diff --git a/Tests/Unit/MSFT_SqlServerMemory.Tests.ps1 b/Tests/Unit/MSFT_SqlServerMemory.Tests.ps1 index 7b88588a3..22c58acb3 100644 --- a/Tests/Unit/MSFT_SqlServerMemory.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerMemory.Tests.ps1 @@ -137,11 +137,11 @@ try } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } It 'Should call the mock function Test-ActiveNode' { - Assert-MockCalled Test-ActiveNode -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Test-ActiveNode -Exactly -Times 1 -Scope Context } } @@ -149,37 +149,24 @@ try } Describe "MSFT_SqlServerMemory\Test-TargetResource" -Tag 'Test' { - Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - throw 'Mocked function Get-CimInstance was called with the wrong set of parameter filters.' - } - - Mock -CommandName Get-CimInstance -MockWith { - - New-Object -TypeName PSObject -Property @{ - TotalPhysicalMemory = 17179869184 - } - - } -ParameterFilter { $ClassName -eq 'Win32_ComputerSystem' } -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - $mockGetCimInstanceProc = [PSCustomObject]@{ - NumberOfCores = 2 - } - - $mockGetCimInstanceProc - } -ParameterFilter { $ClassName -eq 'Win32_Processor' } -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - $mockGetCimInstanceOS = [PSCustomObject]@{ - OSArchitecture = '64-bit' + BeforeEach { + Mock -CommandName Get-SqlDscDynamicMaxMemory -MockWith { + return 8192 # MB + } + + Mock -CommandName Get-TargetResource -MockWith { + return @{ + InstanceName = $mockInstanceName + ServerName = $mockServerName + MinMemory = $mockMinServerMemory + MaxMemory = $mockMaxServerMemory + IsActiveNode = $mockTestActiveNode + } } + } - $mockGetCimInstanceOS - } -ParameterFilter { $ClassName -eq 'Win32_OperatingSystem' } -Verifiable - - Mock -CommandName Test-ActiveNode -MockWith { return $mockTestActiveNode } -Verifiable + $mockMinServerMemory = 0 + $mockMaxServerMemory = 16384 Context 'When the system is not in the desired state and DynamicAlloc is set to false' { $testParameters = $mockDefaultParameters @@ -194,14 +181,6 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $false } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context - } } Context 'When the system is not in the desired state and DynamicAlloc is set to false' { @@ -216,22 +195,14 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $false } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context - } } Context 'When the system is in the desired state and DynamicAlloc is set to false' { $testParameters = $mockDefaultParameters $testParameters += @{ Ensure = 'Present' - MinMemory = 0 - MaxMemory = 10300 + MinMemory = $mockMinServerMemory + MaxMemory = $mockMaxServerMemory DynamicAlloc = $false } @@ -239,14 +210,6 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $true } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context - } } Context 'When the MaxMemory parameter is not null and DynamicAlloc is set to true' { @@ -258,15 +221,7 @@ try } It 'Should throw the correct error' { - { Test-TargetResource @testParameters } | Should -Throw 'The parameter MaxMemory must be null when DynamicAlloc is set to true.' - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + { Test-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxMemoryParamMustBeNull } } @@ -278,15 +233,7 @@ try } It 'Should throw the correct error' { - {Test-TargetResource @testParameters } | Should -Throw 'The parameter MaxMemory must not be null when DynamicAlloc is set to false.' - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + {Test-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxMemoryParamMustNotBeNull } } @@ -301,28 +248,6 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $false } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context - } } Context 'When the system is not in the desired state, DynamicAlloc is set to true and ProcessOnlyOnActiveNode is set to true' { @@ -345,35 +270,11 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $true } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context - } - - It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context - } - - It 'Should not call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context - } } $mockMinServerMemory = 0 $mockMaxServerMemory = 12083 - Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable - Context 'When the system is in the desired state and DynamicAlloc is set to true' { $testParameters = $mockDefaultParameters $testParameters += @{ @@ -381,39 +282,15 @@ try DynamicAlloc = $true } - It 'Should return the state as true when desired MinMemory and MaxMemory are present' { + It 'Should return the state as false when desired MinMemory and MaxMemory are wrong values' { $result = Test-TargetResource @testParameters - $result | Should -Be $true - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context + $result | Should -Be $false } } $mockMinServerMemory = 1024 $mockMaxServerMemory = 8192 - Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable - Context 'When the system is not in the desired state and Ensure is set to Absent' { $testParameters = $mockDefaultParameters $testParameters += @{ @@ -424,21 +301,11 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $false } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context - } } $mockMinServerMemory = 0 $mockMaxServerMemory = 2147483647 - Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable - Context 'When the system is in the desired state and Ensure is set to Absent' { $testParameters = $mockDefaultParameters $testParameters += @{ @@ -449,14 +316,6 @@ try $result = Test-TargetResource @testParameters $result | Should -Be $true } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context - } } # This is regression test for issue #576 @@ -480,35 +339,10 @@ try $mockMaxServerMemory = 2147483647 Mock -CommandName Connect-SQL -MockWith $mockConnectSQL -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - throw 'Mocked function Get-CimInstance was called with the wrong set of parameter filters.' + Mock -CommandName Get-SqlDscDynamicMaxMemory -MockWith { + return 16384 # MB } - Mock -CommandName Get-CimInstance -MockWith { - - New-Object -TypeName PSObject -Property @{ - TotalPhysicalMemory = 17179869184 - } - - } -ParameterFilter { $ClassName -eq 'Win32_ComputerSystem' } -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - $mockGetCimInstanceProc = [PSCustomObject]@{ - NumberOfCores = 6 - } - - $mockGetCimInstanceProc - } -ParameterFilter { $ClassName -eq 'Win32_Processor' } -Verifiable - - Mock -CommandName Get-CimInstance -MockWith { - $mockGetCimInstanceOS = [PSCustomObject]@{ - OSArchitecture = 'IA64-bit' - } - - $mockGetCimInstanceOS - } -ParameterFilter { $ClassName -eq 'Win32_OperatingSystem' } -Verifiable - Context 'When the MaxMemory parameter is not null and DynamicAlloc is set to true' { $testParameters = $mockDefaultParameters $testParameters += @{ @@ -518,15 +352,15 @@ try } It 'Should throw the correct error' { - { Set-TargetResource @testParameters } | Should -Throw 'The parameter MaxMemory must be null when DynamicAlloc is set to true.' + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxMemoryParamMustBeNull } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + It 'Should not call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 0 -Scope Context } } @@ -538,15 +372,15 @@ try } It 'Should throw the correct error' { - { Set-TargetResource @testParameters } | Should -Throw 'The parameter MaxMemory must not be null when DynamicAlloc is set to false.' + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.MaxMemoryParamMustNotBeNull } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + It 'Should not call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 0 -Scope Context } } @@ -562,11 +396,11 @@ try } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + It 'Should not call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 0 -Scope Context } } @@ -591,11 +425,11 @@ try } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + It 'Should not call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 0 -Scope Context } } @@ -612,67 +446,11 @@ try } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context - } - } - - Mock -CommandName Get-CimInstance -MockWith { - $mockGetCimInstanceOS = [PSCustomObject]@{ - OSArchitecture = '32-bit' - } - - $mockGetCimInstanceOS - } -ParameterFilter { $ClassName -eq 'Win32_OperatingSystem' } -Verifiable - - Context 'When the system (OS 32-bit) is not in the desired state and Ensure is set to Present, and DynamicAlloc is set to true' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - DynamicAlloc = $true - Ensure = 'Present' - } - - It 'Should set the MaxMemory to the correct values when Ensure parameter is set to Present and DynamicAlloc is set to true' { - { Set-TargetResource @testParameters } | Should -Not -Throw - } - - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context - } - - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context + It 'Should call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 1 -Scope Context } } @@ -714,59 +492,244 @@ try } It 'Should throw the correct error' { - { Set-TargetResource @testParameters } | Should -Throw ("Failed to alter the server configuration memory for $($env:COMPUTERNAME)" + "\" + ` - "$mockInstanceName. InnerException: Exception calling ""Alter"" with ""0"" argument(s): " + ` - """Mock Alter Method was called with invalid operation.""") + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.AlterServerMemoryFailed -f $env:COMPUTERNAME, $mockInstanceName) } It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Assert-MockCalled -CommandName Connect-SQL -Exactly -Times 1 -Scope Context } - It 'Should not call the mock function Get-CimInstance' { - Assert-MockCalled Get-CimInstance -Exactly -Times 0 -Scope Context + It 'Should not call the mock function Get-SqlDscDynamicMaxMemory' { + Assert-MockCalled -CommandName Get-SqlDscDynamicMaxMemory -Exactly -Times 0 -Scope Context } } - Mock -CommandName Get-CimInstance -MockWith { - throw - } -ParameterFilter { $ClassName -eq 'Win32_OperatingSystem' } -Verifiable + Assert-VerifiableMock + } - Context 'When the Get-SqlDscDynamicMaxMemory fails to calculate the MaxMemory' { - $testParameters = $mockDefaultParameters - $testParameters += @{ - DynamicAlloc = $true - Ensure = 'Present' + Describe 'MSFT_SqlServerMemory\Get-SqlDscDynamicMaxMemory' -Tag 'Helper' { + Context 'When the physical memory should be calculated' { + BeforeEach { + Mock -CommandName Get-CimInstance -MockWith { + return New-Object -TypeName PSObject -Property @{ + TotalPhysicalMemory = $mockTotalPhysicalMemory + } + } -ParameterFilter { $ClassName -eq 'Win32_ComputerSystem' } + + Mock -CommandName Get-CimInstance -MockWith { + return [PSCustomObject]@{ + NumberOfCores = $mockNumberOfCores + } + } -ParameterFilter { $ClassName -eq 'Win32_Processor' } + + Mock -CommandName Get-CimInstance -MockWith { + return [PSCustomObject]@{ + OSArchitecture = $mockOSArchitecture + } + } -ParameterFilter { $ClassName -eq 'Win32_OperatingSystem' } } - It 'Should throw the correct error' { - { Set-TargetResource @testParameters } | Should -Throw 'Failed to calculate dynamically the maximum memory.' + Context 'When number of cores is 2' { + $mockNumberOfCores = 2 + + Context 'When OS Architecture is 64-bit' { + $mockOSArchitecture = '64-bit' + + context 'When physical memory is less than 20480MB' { + $mockTotalPhysicalMemory = 20426260480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 14560 + } + } + + context 'When physical memory is equal to 20480MB' { + $mockTotalPhysicalMemory = 21474836480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 16896 + } + } + + context 'When physical memory is more than 20480MB' { + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 25646 + } + } + + + } + + Context 'When OS Architecture is 32-bit' { + $mockOSArchitecture = '32-bit' + + context 'When physical memory is less than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 20426260480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 14560 + } + } + + context 'When physical memory is equal to 20480MB' { + $mockTotalPhysicalMemory = 21474836480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 16896 + } + } + + context 'When physical memory is more than 20480MB' { + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 25646 + } + } + } + + Context 'When OS Architecture is IA64-bit' { + $mockOSArchitecture = 'IA64-bit' + + context 'When physical memory is less than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 20426260480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 14560 + } + } + + context 'When physical memory is equal to 20480MB' { + $mockTotalPhysicalMemory = 21474836480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 16896 + } + } + + context 'When physical memory is more than 20480MB' { + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 25646 + } + } + } } - It 'Should call the mock function Connect-SQL' { - Assert-MockCalled Connect-SQL -Exactly -Times 1 -Scope Context + Context 'When number of cores is 4' { + $mockNumberOfCores = 4 + Context 'When OS Architecture is 64-bit' { + $mockOSArchitecture = '64-bit' + + context 'When physical memory is more than 20480MB' { + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 25134 + } + } + } + + Context 'When OS Architecture is 32-bit' { + $mockOSArchitecture = '32-bit' + + context 'When physical memory is more than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 25390 + } + } + } + + Context 'When OS Architecture is IA64-bit' { + $mockOSArchitecture = 'IA64-bit' + + context 'When physical memory is more than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 24622 + } + } + } } - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_ComputerSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_ComputerSystem' - } -Scope Context + Context 'When number of cores is 6' { + $mockNumberOfCores = 6 + Context 'When OS Architecture is 64-bit' { + $mockOSArchitecture = '64-bit' + + context 'When physical memory is more than 20480MB' { + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 24078 + } + } + } + + Context 'When OS Architecture is 32-bit' { + $mockOSArchitecture = '32-bit' + + context 'When physical memory is more than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 24350 + } + } + } + + Context 'When OS Architecture is IA64-bit' { + $mockOSArchitecture = 'IA64-bit' + + context 'When physical memory is more than 20480MB' { + # Dynamically set the mock return value. + $mockTotalPhysicalMemory = 31960596480 + + It 'Should return the correct max memory (in megabytes) value' { + $result = Get-SqlDscDynamicMaxMemory + $result | Should -Be 23534 + } + } + } } + } - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_Processor' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_Processor' - } -Scope Context + Context 'When the physical memory fails to be calculated' { + BeforeAll { + Mock -CommandName Get-CimInstance -MockWith { + throw 'mocked unkown error' + } } - It 'Should call the mock function Get-CimInstance with ClassName equal to Win32_OperatingSystem' { - Assert-MockCalled Get-CimInstance -Exactly -Times 1 -ParameterFilter { - $ClassName -eq 'Win32_OperatingSystem' - } -Scope Context + It 'Should throw the correct error' { + { Get-SqlDscDynamicMaxMemory } | Should -Throw $script:localizedData.ErrorGetDynamicMaxMemory } } - - Assert-VerifiableMock } } } diff --git a/Tests/Unit/MSFT_SqlServerPermission.Tests.ps1 b/Tests/Unit/MSFT_SqlServerPermission.Tests.ps1 index 92007b2c8..a27e484ec 100644 --- a/Tests/Unit/MSFT_SqlServerPermission.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerPermission.Tests.ps1 @@ -148,7 +148,7 @@ try throw 'Mocked error.' } - { Get-TargetResource @testParameters } | Should -Throw 'Unexpected result when trying to get permissions for ''COMPANY\SqlServiceAcct''. InnerException: Mocked error.' + { Get-TargetResource @testParameters } | Should -Throw ($script:localizedData.PermissionGetError -f $mockPrincipal) } } } @@ -336,7 +336,7 @@ try return $mockObjectSmoServer } -Verifiable - { Set-TargetResource @testParameters } | Should -Throw 'Changing permission for principal ''COMPANY\SqlServiceAcct'' failed. InnerException: Exception calling "Grant" with "2" argument(s): "Expected to get granteeName == ''COMPANY\OtherAccount''. But got ''COMPANY\SqlServiceAcct''' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.ChangingPermissionFailed -f $mockPrincipal) } } } diff --git a/Tests/Unit/MSFT_SqlServerReplication.Tests.ps1 b/Tests/Unit/MSFT_SqlServerReplication.Tests.ps1 index cc7080d2f..2237aa797 100644 --- a/Tests/Unit/MSFT_SqlServerReplication.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerReplication.Tests.ps1 @@ -49,7 +49,7 @@ try -MockWith { return [pscustomobject]@{ MSSQLSERVER = 'MSSQL12.MSSQLSERVER'} } ` -ParameterFilter { $Path -eq 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\Instance Names\SQL' } - It 'Should return corrent major version for default instance' { + It 'Should return correct major version for default instance' { Mock -CommandName Get-ItemProperty ` -MockWith { return [pscustomobject]@{ Version = '12.1.4100.1' } } ` @@ -64,7 +64,7 @@ try -MockWith { return [pscustomobject]@{ Version = '' } }` -ParameterFilter { $Path -eq 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL12.MSSQLSERVER\Setup' } - { Get-SqlServerMajorVersion -InstanceName 'MSSQLSERVER' } | Should -Throw "instance: MSSQLSERVER!" + { Get-SqlServerMajorVersion -InstanceName 'MSSQLSERVER' } | Should -Throw ($script:localizedData.FailedToDetectSqlVersion -f 'MSSQLSERVER') } } @@ -85,87 +85,89 @@ try $credentials = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList @('AdminLink', $secpasswd) Describe 'The system is not in the desired state given Local distribution mode' { - - $testParameters = @{ - InstanceName = 'MSSQLSERVER' - AdminLinkCredentials = $credentials - DistributorMode = 'Local' - WorkingDirectory = 'C:\temp' - Ensure = 'Present' - } - - Mock -CommandName Get-SqlServerMajorVersion -MockWith { return '99' } - Mock -CommandName Get-SqlLocalServerName -MockWith { return 'SERVERNAME' } - Mock -CommandName New-ServerConnection -MockWith { - return [pscustomobject]@{ - ServerInstance = $SqlServerName - } - } - Mock -CommandName New-ReplicationServer -MockWith { - return [pscustomobject]@{ - IsDistributor = $false - IsPublisher = $false - DistributionDatabase = '' - DistributionServer = 'SERVERNAME' - WorkingDirectory = '' - } - } - Mock -CommandName New-DistributionDatabase -MockWith { return [pscustomobject]@{} } - Mock -CommandName Install-LocalDistributor -MockWith { } - Mock -CommandName Install-RemoteDistributor -MockWith { } - Mock -CommandName Register-DistributorPublisher -MockWith { } - Mock -CommandName Uninstall-Distributor -MockWith {} - - Context 'Get methot' { - $result = Get-TargetResource @testParameters - It 'Get method calls Get-SqlServerMajorVersion with InstanceName = MSSQLSERVER' { - Assert-MockCalled -CommandName Get-SqlServerMajorVersion -Times 1 ` - -ParameterFilter { $InstanceName -eq 'MSSQLSERVER' } - } - It 'Get method calls Get-SqlLocalServerName with $InstanceName = MSSQLSERVER' { - Assert-MockCalled -CommandName Get-SqlLocalServerName -Times 1 ` - -ParameterFilter { $InstanceName -eq 'MSSQLSERVER' } - } - It 'Get method calls New-ServerConnection with $SqlServerName = SERVERNAME' { - Assert-MockCalled -CommandName New-ServerConnection -Times 1 ` - -ParameterFilter { $SqlServerName -eq 'SERVERNAME' } - } - It 'Get method calls New-ReplicationServer with $ServerConnection.ServerInstance = SERVERNAME' { - Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` - -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } - } - It 'Get method doesnt call New-DistributionDatabase' { - Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 - } - It 'Get method doesnt call Install-LocalDistributor' { - Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 - } - It 'Get method doesnt call Install-RemoteDistributor' { - Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 - } - It 'Ger method doesnt call Register-DistributorPublisher' { - Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 - } - It 'Ger method doesnt call Uninstall-Distributor' { - Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 - } - It 'Get method returns Ensure = Absent' { - $result.Ensure | Should -Be 'Absent' - } - It "Get method returns InstanceName = $($testParameters.InstanceName)" { - $result.InstanceName | Should -Be $testParameters.InstanceName - } - It "Get method returns DistributorMode = $($testParameters.DistributorMode)" { - $result.DistributorMode | Should -Be $testParameters.DistributorMode - } - It 'Get method returns DistributionDBName = distribution' { - $result.DistributionDBName | Should -Be 'distribution' - } - It 'Get method returns RemoteDistributor is empty' { - $result.RemoteDistributor | Should -Be '' - } - It 'Get method returns WorkingDirectory = C:\temp' { - $result.WorkingDirectory | Should -Be 'C:\temp' + BeforeAll { + $testParameters = @{ + InstanceName = 'MSSQLSERVER' + AdminLinkCredentials = $credentials + DistributorMode = 'Local' + WorkingDirectory = 'C:\Temp' + } + + Mock -CommandName Get-SqlServerMajorVersion -MockWith { return '99' } + Mock -CommandName Get-SqlLocalServerName -MockWith { return 'SERVERNAME' } + Mock -CommandName New-ServerConnection -MockWith { + return [pscustomobject]@{ + ServerInstance = $SqlServerName + } + } + Mock -CommandName New-ReplicationServer -MockWith { + return [pscustomobject]@{ + IsDistributor = $false + IsPublisher = $false + DistributionDatabase = '' + DistributionServer = 'SERVERNAME' + WorkingDirectory = '' + } + } + Mock -CommandName New-DistributionDatabase -MockWith { return [pscustomobject]@{} } + Mock -CommandName Install-LocalDistributor -MockWith { } + Mock -CommandName Install-RemoteDistributor -MockWith { } + Mock -CommandName Register-DistributorPublisher -MockWith { } + Mock -CommandName Uninstall-Distributor -MockWith {} + } + + Context 'The system is not in the desired state' { + Context 'Get method' { + $result = Get-TargetResource @testParameters + It 'Get method calls Get-SqlServerMajorVersion with InstanceName = MSSQLSERVER' { + Assert-MockCalled -CommandName Get-SqlServerMajorVersion -Times 1 ` + -ParameterFilter { $InstanceName -eq 'MSSQLSERVER' } + } + It 'Get method calls Get-SqlLocalServerName with $InstanceName = MSSQLSERVER' { + Assert-MockCalled -CommandName Get-SqlLocalServerName -Times 1 ` + -ParameterFilter { $InstanceName -eq 'MSSQLSERVER' } + } + It 'Get method calls New-ServerConnection with $SqlServerName = SERVERNAME' { + Assert-MockCalled -CommandName New-ServerConnection -Times 1 ` + -ParameterFilter { $SqlServerName -eq 'SERVERNAME' } + } + It 'Get method calls New-ReplicationServer with $ServerConnection.ServerInstance = SERVERNAME' { + Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` + -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } + } + It 'Get method does not call New-DistributionDatabase' { + Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 + } + It 'Get method does not call Install-LocalDistributor' { + Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 + } + It 'Get method does not call Install-RemoteDistributor' { + Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 + } + It 'Ger method does not call Register-DistributorPublisher' { + Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 + } + It 'Ger method does not call Uninstall-Distributor' { + Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 + } + It 'Get method returns Ensure = Absent' { + $result.Ensure | Should -Be 'Absent' + } + It "Get method returns InstanceName = $($testParameters.InstanceName)" { + $result.InstanceName | Should -Be $testParameters.InstanceName + } + It 'Get method returns DistributorMode as $null' { + $result.DistributorMode | Should -BeNullOrEmpty + } + It 'Get method returns DistributionDBName as $null' { + $result.DistributionDBName | Should -BeNullOrEmpty + } + It 'Get method returns RemoteDistributor as $null' { + $result.RemoteDistributor | Should -BeNullOrEmpty + } + It 'Get method returns WorkingDirectory as $null' { + $result.WorkingDirectory | Should -BeNullOrEmpty + } } } @@ -205,10 +207,10 @@ try Assert-MockCalled -CommandName Register-DistributorPublisher -Times 1 ` -ParameterFilter { $PublisherName -eq 'SERVERNAME' } } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Uninstall-Distributor' { + It 'Set method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } } @@ -247,56 +249,58 @@ try Mock -CommandName Register-DistributorPublisher -MockWith { } Mock -CommandName Uninstall-Distributor -MockWith {} - Context 'Get methot' { - $result = Get-TargetResource @testParameters - It 'Get method calls Get-SqlServerMajorVersion with $InstanceName = INSTANCENAME' { - Assert-MockCalled -CommandName Get-SqlServerMajorVersion -Times 1 ` - -ParameterFilter { $InstanceName -eq 'INSTANCENAME' } - } - It 'Get method calls Get-SqlLocalServerName with $InstanceName = INSTANCENAME' { - Assert-MockCalled -CommandName Get-SqlLocalServerName -Times 1 ` - -ParameterFilter { $InstanceName -eq 'INSTANCENAME' } - } - It 'Get method calls New-ServerConnection with $SqlServerName = SERVERNAME\INSTANCENAME' { - Assert-MockCalled -CommandName New-ServerConnection -Times 1 ` - -ParameterFilter { $SqlServerName -eq 'SERVERNAME\INSTANCENAME' } - } - It 'Get method calls New-ReplicationServer with $ServerConnection.ServerInstance = SERVERNAME\INSTANCENAME' { - Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` - -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME\INSTANCENAME' } - } - It 'Get method doesnt call New-DistributionDatabase' { - Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 - } - It 'Get method doesnt call Install-LocalDistributor' { - Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 - } - It 'Get method doesnt call Install-RemoteDistributor' { - Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 - } - It 'Ger method doesnt call Register-DistributorPublisher' { - Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 - } - It 'Ger method doesnt call Uninstall-Distributor' { - Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 - } - It 'Get method returns Ensure = Absent' { - $result.Ensure | Should -Be 'Absent' - } - It "Get method returns InstanceName = $($testParameters.InstanceName)" { - $result.InstanceName | Should -Be $testParameters.InstanceName - } - It "Get method returns DistributorMode = $($testParameters.DistributorMode)" { - $result.DistributorMode | Should -Be $testParameters.DistributorMode - } - It 'Get method returns DistributionDBName = distribution' { - $result.DistributionDBName | Should -Be 'distribution' - } - It "Get method returns RemoteDistributor = $($testParameters.RemoteDistributor)" { - $result.RemoteDistributor | Should -Be $testParameters.RemoteDistributor - } - It 'Get method returns WorkingDirectory = C:\temp' { - $result.WorkingDirectory | Should -Be 'C:\temp' + Context 'The system is not in the desired state' { + Context 'Get method' { + $result = Get-TargetResource @testParameters + It 'Get method calls Get-SqlServerMajorVersion with $InstanceName = INSTANCENAME' { + Assert-MockCalled -CommandName Get-SqlServerMajorVersion -Times 1 ` + -ParameterFilter { $InstanceName -eq 'INSTANCENAME' } + } + It 'Get method calls Get-SqlLocalServerName with $InstanceName = INSTANCENAME' { + Assert-MockCalled -CommandName Get-SqlLocalServerName -Times 1 ` + -ParameterFilter { $InstanceName -eq 'INSTANCENAME' } + } + It 'Get method calls New-ServerConnection with $SqlServerName = SERVERNAME\INSTANCENAME' { + Assert-MockCalled -CommandName New-ServerConnection -Times 1 ` + -ParameterFilter { $SqlServerName -eq 'SERVERNAME\INSTANCENAME' } + } + It 'Get method calls New-ReplicationServer with $ServerConnection.ServerInstance = SERVERNAME\INSTANCENAME' { + Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` + -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME\INSTANCENAME' } + } + It 'Get method does not call New-DistributionDatabase' { + Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 + } + It 'Get method does not call Install-LocalDistributor' { + Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 + } + It 'Get method does not call Install-RemoteDistributor' { + Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 + } + It 'Ger method does not call Register-DistributorPublisher' { + Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 + } + It 'Ger method does not call Uninstall-Distributor' { + Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 + } + It 'Get method returns Ensure = Absent' { + $result.Ensure | Should -Be 'Absent' + } + It "Get method returns InstanceName = $($testParameters.InstanceName)" { + $result.InstanceName | Should -Be $testParameters.InstanceName + } + It 'Get method returns DistributorMode as $null' { + $result.DistributorMode | Should -BeNullOrEmpty + } + It 'Get method returns DistributionDBName as $null' { + $result.DistributionDBName | Should -BeNullOrEmpty + } + It 'Get method returns RemoteDistributor as $null' { + $result.RemoteDistributor | Should -BeNullOrEmpty + } + It 'Get method returns WorkingDirectory as $null' { + $result.WorkingDirectory | Should -BeNullOrEmpty + } } } @@ -339,13 +343,23 @@ try Assert-MockCalled -CommandName Install-RemoteDistributor -Times 1 ` -ParameterFilter { $RemoteDistributor -eq $testParameters.RemoteDistributor } } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Uninstall-Distributor' { + It 'Set method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } } + + Context 'When calling the Set method with the ''Remote'' distributor mode, but does not provide the parameter RemoteDistributor' { + BeforeAll { + $testParameters.Remove('RemoteDistributor') + } + + It 'Should throw the correct errror' { + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.NoRemoteDistributor + } + } } Describe 'The system is in sync given Local distribution mode' { @@ -398,19 +412,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } } - It 'Get method doesnt call New-DistributionDatabase' { + It 'Get method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Get method doesnt call Install-LocalDistributor' { + It 'Get method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Get method doesnt call Install-RemoteDistributor' { + It 'Get method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Ger method doesnt call Register-DistributorPublisher' { + It 'Ger method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Ger method doesnt call Uninstall-Distributor' { + It 'Ger method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } It 'Get method returns Ensure = Present' { @@ -457,19 +471,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } } - It 'Set method doesnt call New-DistributionDatabase with $DistributionDBName = distribution' { + It 'Set method does not call New-DistributionDatabase with $DistributionDBName = distribution' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Register-DistributorPublisher' { + It 'Set method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Set method doesnt call Uninstall-Distributor' { + It 'Set method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } } @@ -526,19 +540,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME\INSTANCENAME' } } - It 'Get method doesnt call New-DistributionDatabase' { + It 'Get method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Get method doesnt call Install-LocalDistributor' { + It 'Get method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Get method doesnt call Install-RemoteDistributor' { + It 'Get method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Ger method doesnt call Register-DistributorPublisher' { + It 'Ger method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Ger method doesnt call Uninstall-Distributor' { + It 'Ger method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } It 'Get method returns Ensure = Present' { @@ -585,19 +599,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME\INSTANCENAME' } } - It 'Set method doesnt call New-DistributionDatabase' { + It 'Set method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Register-DistributorPublisher' { + It 'Set method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Set method doesnt call Uninstall-Distributor' { + It 'Set method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } } @@ -653,19 +667,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } } - It 'Get method doesnt call New-DistributionDatabase' { + It 'Get method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Get method doesnt call Install-LocalDistributor' { + It 'Get method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Get method doesnt call Install-RemoteDistributor' { + It 'Get method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Ger method doesnt call Register-DistributorPublisher' { + It 'Ger method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Ger method doesnt call Uninstall-Distributor' { + It 'Ger method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } It 'Get method returns Ensure = Present' { @@ -717,16 +731,16 @@ try Assert-MockCalled -CommandName Uninstall-Distributor -Times 1 ` -ParameterFilter { $ReplicationServer.DistributionServer -eq 'SERVERNAME' } } - It 'Set method doesnt call New-DistributionDatabase' { + It 'Set method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Register-DistributorPublisher' { + It 'Set method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } } @@ -783,19 +797,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME\INSTANCENAME' } } - It 'Get method doesnt call New-DistributionDatabase' { + It 'Get method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Get method doesnt call Install-LocalDistributor' { + It 'Get method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Get method doesnt call Install-RemoteDistributor' { + It 'Get method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Ger method doesnt call Register-DistributorPublisher' { + It 'Ger method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Ger method doesnt call Uninstall-Distributor' { + It 'Ger method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } It 'Get method returns Ensure = Present' { @@ -846,16 +860,16 @@ try Assert-MockCalled -CommandName Uninstall-Distributor -Times 1 ` -ParameterFilter { $ReplicationServer.DistributionServer -eq 'REMOTESERVER' } } - It 'Set method doesnt call New-DistributionDatabase' { + It 'Set method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Register-DistributorPublisher' { + It 'Set method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } } @@ -911,19 +925,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } } - It 'Get method doesnt call New-DistributionDatabase' { + It 'Get method does not call New-DistributionDatabase' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Get method doesnt call Install-LocalDistributor' { + It 'Get method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Get method doesnt call Install-RemoteDistributor' { + It 'Get method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Ger method doesnt call Register-DistributorPublisher' { + It 'Ger method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Ger method doesnt call Uninstall-Distributor' { + It 'Ger method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } It 'Get method returns Ensure = Absent' { @@ -932,17 +946,17 @@ try It "Get method returns InstanceName = $($testParameters.InstanceName)" { $result.InstanceName | Should -Be $testParameters.InstanceName } - It "Get method returns DistributorMode = $($testParameters.DistributorMode)" { - $result.DistributorMode | Should -Be $testParameters.DistributorMode + It 'Get method returns DistributorMode as $null' { + $result.DistributorMode | Should -BeNullOrEmpty } - It 'Get method returns DistributionDBName = distribution' { - $result.DistributionDBName | Should -Be 'distribution' + It 'Get method returns DistributionDBName as $null' { + $result.DistributionDBName | Should -BeNullOrEmpty } - It 'Get method returns RemoteDistributor is empty' { - $result.RemoteDistributor | Should -Be '' + It 'Get method returns RemoteDistributor as $null' { + $result.RemoteDistributor | Should -BeNullOrEmpty } - It "Get method returns WorkingDirectory = $($testParameters.WorkingDirectory)" { - $result.WorkingDirectory | Should -Be $testParameters.WorkingDirectory + It 'Get method returns WorkingDirectory as $null' { + $result.WorkingDirectory | Should -BeNullOrEmpty } } @@ -970,19 +984,19 @@ try Assert-MockCalled -CommandName New-ReplicationServer -Times 1 ` -ParameterFilter { $ServerConnection.ServerInstance -eq 'SERVERNAME' } } - It 'Set method doesnt call New-DistributionDatabase with $DistributionDBName = distribution' { + It 'Set method does not call New-DistributionDatabase with $DistributionDBName = distribution' { Assert-MockCalled -CommandName New-DistributionDatabase -Times 0 } - It 'Set method doesnt call Install-LocalDistributor' { + It 'Set method does not call Install-LocalDistributor' { Assert-MockCalled -CommandName Install-LocalDistributor -Times 0 } - It 'Set method doesnt call Install-RemoteDistributor' { + It 'Set method does not call Install-RemoteDistributor' { Assert-MockCalled -CommandName Install-RemoteDistributor -Times 0 } - It 'Set method doesnt call Register-DistributorPublisher' { + It 'Set method does not call Register-DistributorPublisher' { Assert-MockCalled -CommandName Register-DistributorPublisher -Times 0 } - It 'Set method doesnt call Uninstall-Distributor' { + It 'Set method does not call Uninstall-Distributor' { Assert-MockCalled -CommandName Uninstall-Distributor -Times 0 } } diff --git a/Tests/Unit/MSFT_SqlWaitForAG.Tests.ps1 b/Tests/Unit/MSFT_SqlWaitForAG.Tests.ps1 index 3179c4e21..790aeecfe 100644 --- a/Tests/Unit/MSFT_SqlWaitForAG.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlWaitForAG.Tests.ps1 @@ -240,7 +240,7 @@ try It 'Should throw the correct error message' { $testParameters.Name = $mockOtherClusterGroupName - { Set-TargetResource @testParameters } | Should -Throw 'Cluster group UnknownAG not found after 2 attempts with 1 sec interval' + { Set-TargetResource @testParameters } | Should -Throw ($script:localizedData.FailedMessage -f $mockOtherClusterGroupName) Assert-MockCalled -CommandName Get-ClusterGroup ` -ParameterFilter $mockGetClusterGroup_ParameterFilter_KnownGroup ` diff --git a/Tests/Unit/MSFT_SqlWindowsFirewall.Tests.ps1 b/Tests/Unit/MSFT_SqlWindowsFirewall.Tests.ps1 index 22f6f3048..0254b0f7d 100644 --- a/Tests/Unit/MSFT_SqlWindowsFirewall.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlWindowsFirewall.Tests.ps1 @@ -1047,7 +1047,7 @@ try } It 'Should throw the correct error when Set-TargetResource verifies result with Test-TargetResource' { - { Set-TargetResource @testParameters } | Should -Throw TestFailedAfterSet + { Set-TargetResource @testParameters } | Should -Throw $script:localizedData.TestFailedAfterSet Assert-MockCalled -CommandName New-SmbMapping -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName Remove-SmbMapping -Exactly -Times 1 -Scope It