diff --git a/CHANGELOG.md b/CHANGELOG.md index b7fc73675..fa06a610b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,19 @@ ## Unreleased +- Changes to SqlServerDsc + - Updated helper function Restart-SqlService to have to new optional parameters + `SkipClusterCheck` and `SkipWaitForOnline`. This was to support more aspects + of the resource SqlServerNetwork. - Changes to SqlAlwaysOnService - Integration tests was updated to handle new IPv6 addresses on the AppVeyor build worker ([issue #1155](https://github.com/PowerShell/SqlServerDsc/issues/1155)). +- Changes to SqlServerNetwork + - Refactor SqlServerNetwork to not load assembly from GAC ([issue #1151](https://github.com/PowerShell/SqlServerDsc/issues/1151)). + - The resource now supports restarting the SQL Server service when both + enabling and disabling the protocol. + - Added integration tests for this resource + ([issue #751](https://github.com/PowerShell/SqlServerDsc/issues/751)). ## 11.3.0.0 diff --git a/DSCResources/MSFT_SqlServerNetwork/MSFT_SqlServerNetwork.psm1 b/DSCResources/MSFT_SqlServerNetwork/MSFT_SqlServerNetwork.psm1 index 0ce468776..98da5b0e6 100644 --- a/DSCResources/MSFT_SqlServerNetwork/MSFT_SqlServerNetwork.psm1 +++ b/DSCResources/MSFT_SqlServerNetwork/MSFT_SqlServerNetwork.psm1 @@ -33,31 +33,24 @@ function Get-TargetResource $ProtocolName ) - try - { - $applicationDomainObject = Register-SqlWmiManagement -SQLInstanceName $InstanceName - - $managedComputerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer + Import-SQLPSModule - Write-Verbose -Message ($script:localizedData.GetNetworkProtocol -f $ProtocolName, $InstanceName) - $tcp = $managedComputerObject.ServerInstances[$InstanceName].ServerProtocols[$ProtocolName] + $managedComputerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer - Write-Verbose -Message $script:localizedData.ReadingNetworkProperties - $returnValue = @{ - InstanceName = $InstanceName - ProtocolName = $ProtocolName - IsEnabled = $tcp.IsEnabled - TcpDynamicPort = ($tcp.IPAddresses['IPAll'].IPAddressProperties['TcpDynamicPorts'].Value -ge 0) - TcpPort = $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpPort'].Value - } + Write-Verbose -Message ($script:localizedData.GetNetworkProtocol -f $ProtocolName, $InstanceName) + $tcp = $managedComputerObject.ServerInstances[$InstanceName].ServerProtocols[$ProtocolName] - $returnValue.Keys | ForEach-Object { - Write-Verbose -Message "$_ = $($returnValue[$_])" - } + Write-Verbose -Message $script:localizedData.ReadingNetworkProperties + $returnValue = @{ + InstanceName = $InstanceName + ProtocolName = $ProtocolName + IsEnabled = $tcp.IsEnabled + TcpDynamicPort = ($tcp.IPAddresses['IPAll'].IPAddressProperties['TcpDynamicPorts'].Value -ge 0) + TcpPort = $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpPort'].Value } - finally - { - Unregister-SqlAssemblies -ApplicationDomain $applicationDomainObject + + $returnValue.Keys | ForEach-Object { + Write-Verbose -Message "$_ = $($returnValue[$_])" } return $returnValue @@ -145,90 +138,104 @@ function Set-TargetResource $getTargetResourceResult = Get-TargetResource -InstanceName $InstanceName -ProtocolName $ProtocolName - try - { - $applicationDomainObject = Register-SqlWmiManagement -SQLInstanceName $InstanceName - - $desiredState = @{ - InstanceName = $InstanceName - ProtocolName = $ProtocolName - IsEnabled = $IsEnabled - TcpDynamicPort = $TcpDynamicPort - TcpPort = $TcpPort - } + $desiredState = @{ + InstanceName = $InstanceName + ProtocolName = $ProtocolName + IsEnabled = $IsEnabled + TcpDynamicPort = $TcpDynamicPort + TcpPort = $TcpPort + } - $isRestartNeeded = $false + $isRestartNeeded = $false - $managedComputerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer + # Get-TargetResource makes the necessary calls so the type ManagedComputer is available. + $managedComputerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer - Write-Verbose -Message ($script:localizedData.GetNetworkProtocol -f $ProtocolName, $InstanceName) - $tcp = $managedComputerObject.ServerInstances[$InstanceName].ServerProtocols[$ProtocolName] + Write-Verbose -Message ($script:localizedData.GetNetworkProtocol -f $ProtocolName, $InstanceName) + $tcp = $managedComputerObject.ServerInstances[$InstanceName].ServerProtocols[$ProtocolName] - Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'IsEnabled') - if ($desiredState.IsEnabled -ine $getTargetResourceResult.IsEnabled) - { - Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'IsEnabled', $getTargetResourceResult.IsEnabled, $desiredState.IsEnabled) - $tcp.IsEnabled = $desiredState.IsEnabled - $tcp.Alter() + Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'IsEnabled') + if ($desiredState.IsEnabled -ine $getTargetResourceResult.IsEnabled) + { + Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'IsEnabled', $getTargetResourceResult.IsEnabled, $desiredState.IsEnabled) + $tcp.IsEnabled = $desiredState.IsEnabled + $tcp.Alter() + + $isRestartNeeded = $true + } - $isRestartNeeded = $true + Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'TcpDynamicPort') + if ($desiredState.TcpDynamicPort -ne $getTargetResourceResult.TcpDynamicPort) + { + # Translates the current and desired state to a string for display + $dynamicPortDisplayValueTable = @{ + $true = 'enabled' + $false = 'disabled' } - Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'TcpDynamicPort') - if ($desiredState.TcpDynamicPort -ne $getTargetResourceResult.TcpDynamicPort) - { - # Translates the current and desired state to a string for display - $dynamicPortDisplayValueTable = @{ - $true = 'enabled' - $false = 'disabled' - } + # Translates the desired state to a valid value + $desiredDynamicPortValue = @{ + $true = '0' + $false = '' + } - # Translates the desired state to a valid value - $desiredDynamicPortValue = @{ - $true = '0' - $false = '' - } + $fromTcpDynamicPortDisplayValue = $dynamicPortDisplayValueTable[$getTargetResourceResult.TcpDynamicPort] + $toTcpDynamicPortDisplayValue = $dynamicPortDisplayValueTable[$desiredState.TcpDynamicPort] - $fromTcpDynamicPortDisplayValue = $dynamicPortDisplayValueTable[$getTargetResourceResult.TcpDynamicPort] - $toTcpDynamicPortDisplayValue = $dynamicPortDisplayValueTable[$desiredState.TcpDynamicPort] + Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'TcpDynamicPorts', $fromTcpDynamicPortDisplayValue, $toTcpDynamicPortDisplayValue) + $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpDynamicPorts'].Value = $desiredDynamicPortValue[$desiredState.TcpDynamicPort] + $tcp.Alter() - Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'TcpDynamicPorts', $fromTcpDynamicPortDisplayValue, $toTcpDynamicPortDisplayValue) - $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpDynamicPorts'].Value = $desiredDynamicPortValue[$desiredState.TcpDynamicPort] - $tcp.Alter() + $isRestartNeeded = $true + } - $isRestartNeeded = $true + Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'TcpPort') + if ($desiredState.TcpPort -ine $getTargetResourceResult.TcpPort) + { + $fromTcpPort = $getTargetResourceResult.TcpPort + if ($fromTcpPort -eq '') + { + $fromTcpPort = 'none' } - Write-Verbose -Message ($script:localizedData.CheckingProperty -f 'TcpPort') - if ($desiredState.TcpPort -ine $getTargetResourceResult.TcpPort) + $toTcpPort = $desiredState.TcpPort + if ($toTcpPort -eq '') { - $fromTcpPort = $getTargetResourceResult.TcpPort - if ($fromTcpPort -eq '') - { - $fromTcpPort = 'none' - } + $toTcpPort = 'none' + } - $toTcpPort = $desiredState.TcpPort - if ($toTcpPort -eq '') - { - $toTcpPort = 'none' - } + Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'TcpPort', $fromTcpPort, $toTcpPort) + $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpPort'].Value = $desiredState.TcpPort + $tcp.Alter() - Write-Verbose -Message ($script:localizedData.UpdatingProperty -f 'TcpPort', $fromTcpPort, $toTcpPort) - $tcp.IPAddresses['IPAll'].IPAddressProperties['TcpPort'].Value = $desiredState.TcpPort - $tcp.Alter() + $isRestartNeeded = $true + } - $isRestartNeeded = $true + if ($RestartService -and $isRestartNeeded) + { + $restartSqlServiceParameters = @{ + SQLServer = $ServerName + SQLInstanceName = $InstanceName + Timeout = $RestartTimeout } - if ($RestartService -and $isRestartNeeded) + if ($getTargetResourceResult.IsEnabled -eq $false -and $IsEnabled -eq $true) { - Restart-SqlService -SQLServer $ServerName -SQLInstanceName $InstanceName -Timeout $RestartTimeout + <# + If the protocol was disabled and now being enabled, is not possible + to connect to the instance to evaluate if it is a clustered instance. + This is being tracked in issue #1174. + #> + $restartSqlServiceParameters['SkipClusterCheck'] = $true } - } - finally - { - Unregister-SqlAssemblies -ApplicationDomain $applicationDomainObject + + if ($PSBoundParameters.ContainsKey('IsEnabled') -and $IsEnabled -eq $false) + { + # If the protocol is disabled it is not possible to connect to the instance. + $restartSqlServiceParameters['SkipWaitForOnline'] = $true + } + + Restart-SqlService @restartSqlServiceParameters } } diff --git a/SqlServerDscHelper.psm1 b/SqlServerDscHelper.psm1 index e79e5ca10..dab9543d8 100644 --- a/SqlServerDscHelper.psm1 +++ b/SqlServerDscHelper.psm1 @@ -179,151 +179,6 @@ function Connect-SQLAnalysis return $analysisServicesObject } -<# - .SYNOPSIS - Creates a new application domain and loads the assemblies Microsoft.SqlServer.Smo - for the correct SQL Server major version. - - An isolated application domain is used to load version specific assemblies, this needed - if there is multiple versions of SQL server in the same configuration. So that a newer - version of SQL is not using an older version of the assembly, or vice verse. - - This should be unloaded using the helper function Unregister-SqlAssemblies or - using [System.AppDomain]::Unload($applicationDomainObject). - - .PARAMETER SQLInstanceName - String containing the SQL Server Database Engine instance name to get the major SQL version from. - - .PARAMETER ApplicationDomain - An optional System.AppDomain object to load the assembly into. - - .OUTPUTS - System.AppDomain. Returns the application domain object with SQL SMO loaded. -#> -function Register-SqlSmo -{ - [CmdletBinding()] - [OutputType([System.AppDomain])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $SQLInstanceName, - - [Parameter()] - [ValidateNotNullOrEmpty()] - [System.AppDomain] - $ApplicationDomain - ) - - $sqlMajorVersion = Get-SqlInstanceMajorVersion -SQLInstanceName $SQLInstanceName - - Write-Verbose -Message ($script:localizedData.SqlMajorVersion -f $sqlMajorVersion) -Verbose - - if ( -not $ApplicationDomain ) - { - $applicationDomainName = $MyInvocation.MyCommand.ModuleName - Write-Verbose -Message ($script:localizedData.CreatingApplicationDomain -f $applicationDomainName) -Verbose - $applicationDomainObject = [System.AppDomain]::CreateDomain($applicationDomainName) - } - else - { - Write-Verbose -Message ($script:localizedData.ReusingApplicationDomain -f $ApplicationDomain.FriendlyName) -Verbose - $applicationDomainObject = $ApplicationDomain - } - - $sqlSmoAssemblyName = "Microsoft.SqlServer.Smo, Version=$sqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" - Write-Verbose -Message ($script:localizedData.LoadingAssembly -f $sqlSmoAssemblyName) -Verbose - $applicationDomainObject.Load($sqlSmoAssemblyName) | Out-Null - - return $applicationDomainObject -} - -<# - .SYNOPSIS - Creates a new application domain and loads the assemblies Microsoft.SqlServer.Smo and - Microsoft.SqlServer.SqlWmiManagement for the correct SQL Server major version. - - An isolated application domain is used to load version specific assemblies, this needed - if there is multiple versions of SQL server in the same configuration. So that a newer - version of SQL is not using an older version of the assembly, or vice verse. - - This should be unloaded using the helper function Unregister-SqlAssemblies or - using [System.AppDomain]::Unload($applicationDomainObject) preferably in a finally block. - - .PARAMETER SQLInstanceName - String containing the SQL Server Database Engine instance name to get the major SQL version from. - - .PARAMETER ApplicationDomain - An optional System.AppDomain object to load the assembly into. - - .OUTPUTS - System.AppDomain. Returns the application domain object with SQL WMI Management loaded. -#> -function Register-SqlWmiManagement -{ - [CmdletBinding()] - [OutputType([System.AppDomain])] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNullOrEmpty()] - [System.String] - $SQLInstanceName, - - [Parameter()] - [ValidateNotNull()] - [System.AppDomain] - $ApplicationDomain - ) - - $sqlMajorVersion = Get-SqlInstanceMajorVersion -SQLInstanceName $SQLInstanceName - Write-Verbose -Message ($script:localizedData.SqlMajorVersion -f $sqlMajorVersion) -Verbose - - <# - Must register Microsoft.SqlServer.Smo first because that is a - dependency of Microsoft.SqlServer.SqlWmiManagement. - #> - if (-not $ApplicationDomain) - { - $applicationDomainObject = Register-SqlSmo -SQLInstanceName $SQLInstanceName - } - # Returns zero (0) objects if the assembly is not found - elseif (-not ($ApplicationDomain.GetAssemblies().FullName -match 'Microsoft.SqlServer.Smo')) - { - $applicationDomainObject = Register-SqlSmo -SQLInstanceName $SQLInstanceName -ApplicationDomain $ApplicationDomain - } - - $sqlSqlWmiManagementAssemblyName = "Microsoft.SqlServer.SqlWmiManagement, Version=$sqlMajorVersion.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91" - Write-Verbose -Message ($script:localizedData.LoadingAssembly -f $sqlSqlWmiManagementAssemblyName) -Verbose - $applicationDomainObject.Load($sqlSqlWmiManagementAssemblyName) | Out-Null - - return $applicationDomainObject -} - -<# - .SYNOPSIS - Unloads all assemblies in an application domain. It unloads the application domain. - - .PARAMETER ApplicationDomain - System.AppDomain object containing the SQL assemblies to unload. -#> -function Unregister-SqlAssemblies -{ - [CmdletBinding()] - param - ( - [Parameter(Mandatory = $true)] - [ValidateNotNull()] - [System.AppDomain] - $ApplicationDomain - ) - - Write-Verbose -Message ($script:localizedData.UnloadingApplicationDomain -f $ApplicationDomain.FriendlyName) -Verbose - [System.AppDomain]::Unload($ApplicationDomain) -} - <# .SYNOPSIS Returns the major SQL version for the specific instance. @@ -777,25 +632,42 @@ function Import-SQLPSModule <# .SYNOPSIS - Restarts a SQL Server instance and associated services + Restarts a SQL Server instance and associated services .PARAMETER SQLServer - Hostname of the SQL Server to be configured + Hostname of the SQL Server to be configured .PARAMETER SQLInstanceName - Name of the SQL instance to be configured. Default is 'MSSQLSERVER' + Name of the SQL instance to be configured. Default is 'MSSQLSERVER' .PARAMETER Timeout - Timeout value for restarting the SQL services. The default value is 120 seconds. + Timeout value for restarting the SQL services. The default value is 120 seconds. + + .PARAMETER SkipClusterCheck + If cluster check should be skipped. If this is present no connection + is made to the instance to check if the instance is on a cluster. + + This need to be used for some resource, for example for the SqlServerNetwork + resource when it's used to enable a disable protocol. + + .PARAMETER SkipWaitForOnline + If this is present no connection is made to the instance to check if the + instance is online. + + This need to be used for some resource, for example for the SqlServerNetwork + resource when it's used to disable protocol. + + .EXAMPLE + Restart-SqlService -SQLServer localhost .EXAMPLE - Restart-SqlService -SQLServer localhost + Restart-SqlService -SQLServer localhost -SQLInstanceName 'NamedInstance' .EXAMPLE - Restart-SqlService -SQLServer localhost -SQLInstanceName 'NamedInstance' + Restart-SqlService -SQLServer localhost -SQLInstanceName 'NamedInstance' -SkipClusterCheck -SkipWaitForOnline .EXAMPLE - Restart-SqlService -SQLServer CLU01 -Timeout 300 + Restart-SqlService -SQLServer CLU01 -Timeout 300 #> function Restart-SqlService { @@ -812,45 +684,76 @@ function Restart-SqlService [Parameter()] [System.UInt32] - $Timeout = 120 - ) + $Timeout = 120, - ## Connect to the instance - $serverObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName + [Parameter()] + [Switch] + $SkipClusterCheck, + + [Parameter()] + [Switch] + $SkipWaitForOnline + ) - if ($serverObject.IsClustered) + if (-not $SkipClusterCheck.IsPresent) { - # Get the cluster resources - Write-Verbose -Message ($script:localizedData.GetSqlServerClusterResources) -Verbose - $sqlService = Get-CimInstance -Namespace root/MSCluster -ClassName MSCluster_Resource -Filter "Type = 'SQL Server'" | - Where-Object -FilterScript { $_.PrivateProperties.InstanceName -eq $serverObject.ServiceName } + ## Connect to the instance + $serverObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName - Write-Verbose -Message ($script:localizedData.GetSqlAgentClusterResource) -Verbose - $agentService = $sqlService | Get-CimAssociatedInstance -ResultClassName MSCluster_Resource | - Where-Object -FilterScript { ($_.Type -eq 'SQL Server Agent') -and ($_.State -eq 2) } + if ($serverObject.IsClustered) + { + # Get the cluster resources + Write-Verbose -Message ($script:localizedData.GetSqlServerClusterResources) -Verbose + $sqlService = Get-CimInstance -Namespace root/MSCluster -ClassName MSCluster_Resource -Filter "Type = 'SQL Server'" | + Where-Object -FilterScript { $_.PrivateProperties.InstanceName -eq $serverObject.ServiceName } + + Write-Verbose -Message ($script:localizedData.GetSqlAgentClusterResource) -Verbose + $agentService = $sqlService | Get-CimAssociatedInstance -ResultClassName MSCluster_Resource | + Where-Object -FilterScript { ($_.Type -eq 'SQL Server Agent') -and ($_.State -eq 2) } - # Build a listing of resources being acted upon - $resourceNames = @($sqlService.Name, ($agentService | Select-Object -ExpandProperty Name)) -join "," + # Build a listing of resources being acted upon + $resourceNames = @($sqlService.Name, ($agentService | Select-Object -ExpandProperty Name)) -join "," - # Stop the SQL Server and dependent resources - Write-Verbose -Message ($script:localizedData.BringClusterResourcesOffline -f $resourceNames) -Verbose - $sqlService | Invoke-CimMethod -MethodName TakeOffline -Arguments @{ Timeout = $Timeout } + # Stop the SQL Server and dependent resources + Write-Verbose -Message ($script:localizedData.BringClusterResourcesOffline -f $resourceNames) -Verbose + $sqlService | Invoke-CimMethod -MethodName TakeOffline -Arguments @{ Timeout = $Timeout } - # Start the SQL server resource - Write-Verbose -Message ($script:localizedData.BringSqlServerClusterResourcesOnline) -Verbose - $sqlService | Invoke-CimMethod -MethodName BringOnline -Arguments @{ Timeout = $Timeout } + # Start the SQL server resource + Write-Verbose -Message ($script:localizedData.BringSqlServerClusterResourcesOnline) -Verbose + $sqlService | Invoke-CimMethod -MethodName BringOnline -Arguments @{ Timeout = $Timeout } - # Start the SQL Agent resource - if ($agentService) + # Start the SQL Agent resource + if ($agentService) + { + Write-Verbose -Message ($script:localizedData.BringSqlServerAgentClusterResourcesOnline) -Verbose + $agentService | Invoke-CimMethod -MethodName BringOnline -Arguments @{ Timeout = $Timeout } + } + } + else { - Write-Verbose -Message ($script:localizedData.BringSqlServerAgentClusterResourcesOnline) -Verbose - $agentService | Invoke-CimMethod -MethodName BringOnline -Arguments @{ Timeout = $Timeout } + # Not a cluster, restart the Windows service. + $restartWindowsService = $true } } else { + # Should not check if a cluster, assume that a Windows service should be restarted. + $restartWindowsService = $true + } + + if ($restartWindowsService) + { + if ($SQLInstanceName -eq 'MSSQLSERVER') + { + $serviceName = 'MSSQLSERVER' + } + else + { + $serviceName = 'MSSQL${0}' -f $SQLInstanceName + } + Write-Verbose -Message ($script:localizedData.GetServiceInformation -f 'SQL Server') -Verbose - $sqlService = Get-Service -DisplayName "SQL Server ($($serverObject.ServiceName))" + $sqlService = Get-Service -Name $serviceName <# Get all dependent services that are running. @@ -871,30 +774,33 @@ function Restart-SqlService Write-Verbose -Message ($script:localizedData.WaitingInstanceTimeout -f $SQLServer, $SQLInstanceName, $Timeout) -Verbose - $connectTimer = [System.Diagnostics.StopWatch]::StartNew() - - do + if (-not $SkipWaitForOnline.IsPresent) { - # This call, if it fails, will take between ~9-10 seconds to return. - $testConnectionServerObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -ErrorAction SilentlyContinue - if ($testConnectionServerObject -and $testConnectionServerObject.Status -ne 'Online') - { - # Waiting 2 seconds to not hammer the SQL Server instance. - Start-Sleep -Seconds 2 - } - else + $connectTimer = [System.Diagnostics.StopWatch]::StartNew() + + do { - break - } - } until ($connectTimer.Elapsed.Seconds -ge $Timeout) + # This call, if it fails, will take between ~9-10 seconds to return. + $testConnectionServerObject = Connect-SQL -SQLServer $SQLServer -SQLInstanceName $SQLInstanceName -ErrorAction SilentlyContinue + if ($testConnectionServerObject -and $testConnectionServerObject.Status -ne 'Online') + { + # Waiting 2 seconds to not hammer the SQL Server instance. + Start-Sleep -Seconds 2 + } + else + { + break + } + } until ($connectTimer.Elapsed.Seconds -ge $Timeout) - $connectTimer.Stop() + $connectTimer.Stop() - # Was the timeout period reach before able to connect to the SQL Server instance? - if (-not $testConnectionServerObject -or $testConnectionServerObject.Status -ne 'Online') - { - $errorMessage = $script:localizedData.FailedToConnectToInstanceTimeout -f $SQLServer, $SQLInstanceName, $Timeout - New-InvalidOperationException -Message $errorMessage + # Was the timeout period reach before able to connect to the SQL Server instance? + if (-not $testConnectionServerObject -or $testConnectionServerObject.Status -ne 'Online') + { + $errorMessage = $script:localizedData.FailedToConnectToInstanceTimeout -f $SQLServer, $SQLInstanceName, $Timeout + New-InvalidOperationException -Message $errorMessage + } } } diff --git a/Tests/Integration/MSFT_SqlServerNetwork.Integration.Tests.ps1 b/Tests/Integration/MSFT_SqlServerNetwork.Integration.Tests.ps1 new file mode 100644 index 000000000..26bab827b --- /dev/null +++ b/Tests/Integration/MSFT_SqlServerNetwork.Integration.Tests.ps1 @@ -0,0 +1,151 @@ +# This is used to make sure the integration test run in the correct order. +[Microsoft.DscResourceKit.IntegrationTest(OrderNumber = 2)] +param() + +$script:DSCModuleName = 'SqlServerDsc' +$script:DSCResourceFriendlyName = 'SqlServerNetwork' +$script:DSCResourceName = "MSFT_$($script:DSCResourceFriendlyName)" + +if (-not $env:APPVEYOR -eq $true) +{ + Write-Warning -Message ('Integration test for {0} will be skipped unless $env:APPVEYOR equals $true' -f $script:DSCResourceName) + return +} + +#region HEADER +# Integration Test Template Version: 1.1.2 +[System.String] $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests')) +} + +Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:DSCModuleName ` + -DSCResourceName $script:DSCResourceName ` + -TestType Integration + +#endregion + +$mockSqlInstallAccountPassword = ConvertTo-SecureString -String 'P@ssw0rd1' -AsPlainText -Force +$mockSqlInstallAccountUserName = "$env:COMPUTERNAME\SqlInstall" +$mockSqlInstallCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $mockSqlInstallAccountUserName, $mockSqlInstallAccountPassword + +try +{ + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:DSCResourceName).config.ps1" + . $configFile + + $mockProtocolName = $ConfigurationData.AllNodes.ProtocolName + $mockEnabled = $ConfigurationData.AllNodes.Enabled + $mockDisabled = $ConfigurationData.AllNodes.Disabled + $mockTcpDynamicPort = $ConfigurationData.AllNodes.TcpDynamicPort + + Describe "$($script:DSCResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:DSCResourceFriendlyName)]Integration_Test" + } + + $configurationName = "$($script:DSCResourceName)_SetDisabled_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + SqlInstallCredential = $mockSqlInstallCredential + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName + } | Where-Object -FilterScript { + $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.IsEnabled | Should -Be $mockDisabled + $resourceCurrentState.ProtocolName | Should -Be $mockProtocolName + $resourceCurrentState.TcpDynamicPort | Should -Be $mockTcpDynamicPort + } + } + + $configurationName = "$($script:DSCResourceName)_SetEnabled_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + SqlInstallCredential = $mockSqlInstallCredential + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName + } | Where-Object -FilterScript { + $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.IsEnabled | Should -Be $mockEnabled + $resourceCurrentState.ProtocolName | Should -Be $mockProtocolName + $resourceCurrentState.TcpDynamicPort | Should -Be $mockTcpDynamicPort + } + } + } +} +finally +{ + #region FOOTER + + Restore-TestEnvironment -TestEnvironment $TestEnvironment + + #endregion +} diff --git a/Tests/Integration/MSFT_SqlServerNetwork.config.ps1 b/Tests/Integration/MSFT_SqlServerNetwork.config.ps1 new file mode 100644 index 000000000..3a06ed784 --- /dev/null +++ b/Tests/Integration/MSFT_SqlServerNetwork.config.ps1 @@ -0,0 +1,70 @@ +$ConfigurationData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + ServerName = $env:COMPUTERNAME + InstanceName = 'DSCSQL2016' + + PSDscAllowPlainTextPassword = $true + + ProtocolName = 'Tcp' + Enabled = $true + Disabled = $false + TcpDynamicPort = $true + RestartService = $true + } + ) +} + +Configuration MSFT_SqlServerNetwork_SetDisabled_Config +{ + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlInstallCredential + ) + + Import-DscResource -ModuleName 'SqlServerDsc' + + node localhost { + SqlServerNetwork 'Integration_Test' + { + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + ProtocolName = $Node.ProtocolName + IsEnabled = $Node.Disabled + TcpDynamicPort = $Node.TcpDynamicPort + + PsDscRunAsCredential = $SqlInstallCredential + } + } +} + +Configuration MSFT_SqlServerNetwork_SetEnabled_Config +{ + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.Management.Automation.PSCredential] + $SqlInstallCredential + ) + + Import-DscResource -ModuleName 'SqlServerDsc' + + node localhost { + SqlServerNetwork 'Integration_Test' + { + ServerName = $Node.ServerName + InstanceName = $Node.InstanceName + ProtocolName = $Node.ProtocolName + IsEnabled = $Node.Enabled + TcpDynamicPort = $Node.TcpDynamicPort + + PsDscRunAsCredential = $SqlInstallCredential + } + } +} + diff --git a/Tests/Unit/MSFT_SqlServerNetwork.Tests.ps1 b/Tests/Unit/MSFT_SqlServerNetwork.Tests.ps1 index 21efdc997..65f459662 100644 --- a/Tests/Unit/MSFT_SqlServerNetwork.Tests.ps1 +++ b/Tests/Unit/MSFT_SqlServerNetwork.Tests.ps1 @@ -90,10 +90,6 @@ try $TypeName -eq 'Microsoft.SqlServer.Management.Smo.Wmi.ManagedComputer' } - $mockFunction_RegisterSqlWmiManagement = { - return [System.AppDomain]::CreateDomain('DummyTestApplicationDomain') - } - $mockDefaultParameters = @{ InstanceName = $mockInstanceName ProtocolName = $mockTcpProtocolName @@ -103,10 +99,7 @@ try BeforeEach { $testParameters = $mockDefaultParameters.Clone() - Mock -CommandName Register-SqlWmiManagement ` - -MockWith $mockFunction_RegisterSqlWmiManagement ` - -Verifiable - + Mock -CommandName Import-SQLPSModule Mock -CommandName New-Object ` -MockWith $mockFunction_NewObject_ManagedComputer ` -ParameterFilter $mockFunction_NewObject_ManagedComputer_ParameterFilter -Verifiable @@ -126,7 +119,6 @@ try $result.TcpDynamicPort | Should -Be $false $result.TcpPort | Should -Be $mockDynamicValue_TcpPort - Assert-MockCalled -CommandName Register-SqlWmiManagement -Exactly -Times 1 -Scope It Assert-MockCalled -CommandName New-Object -Exactly -Times 1 -Scope It ` -ParameterFilter $mockFunction_NewObject_ManagedComputer_ParameterFilter } @@ -145,10 +137,7 @@ try BeforeEach { $testParameters = $mockDefaultParameters.Clone() - Mock -CommandName Register-SqlWmiManagement ` - -MockWith $mockFunction_RegisterSqlWmiManagement ` - -Verifiable - + Mock -CommandName Import-SQLPSModule Mock -CommandName New-Object ` -MockWith $mockFunction_NewObject_ManagedComputer ` -ParameterFilter $mockFunction_NewObject_ManagedComputer_ParameterFilter -Verifiable @@ -200,6 +189,25 @@ try } } + Context 'When ProtocolName is not in desired state' { + BeforeEach { + $testParameters += @{ + IsEnabled = $false + TcpDynamicPort = $false + TcpPort = '4509' + } + + # Not supporting any other than 'TCP' yet. + $testParameters['ProtocolName'] = 'Unknown' + } + + # Skipped since no other protocol is supported yet (issue #14). + It 'Should return $false' -Skip:$true { + $result = Test-TargetResource @testParameters + $result | Should -Be $false + } + } + Context 'When current state is using static tcp port' { Context 'When TcpDynamicPort is not in desired state' { BeforeEach { @@ -314,10 +322,7 @@ try $testParameters = $mockDefaultParameters.Clone() Mock -CommandName Restart-SqlService -Verifiable - Mock -CommandName Register-SqlWmiManagement ` - -MockWith $mockFunction_RegisterSqlWmiManagement ` - -Verifiable - + Mock -CommandName Import-SQLPSModule Mock -CommandName New-Object ` -MockWith $mockFunction_NewObject_ManagedComputer ` -ParameterFilter $mockFunction_NewObject_ManagedComputer_ParameterFilter -Verifiable @@ -344,22 +349,55 @@ try } Context 'When IsEnabled is not in desired state' { - BeforeEach { - $testParameters += @{ - IsEnabled = $false - TcpDynamicPort = $false - TcpPort = '4509' - RestartService = $true + Context 'When IsEnabled should be $false' { + BeforeEach { + $testParameters += @{ + IsEnabled = $false + TcpDynamicPort = $false + TcpPort = '4509' + RestartService = $true + } + + $mockExpectedValue_IsEnabled = $false } - $mockExpectedValue_IsEnabled = $false + It 'Should call Set-TargetResource without throwing and should call Alter()' { + { Set-TargetResource @testParameters } | Should -Not -Throw + $script:WasMethodAlterCalled | Should -Be $true + + Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It + } } - It 'Should call Set-TargetResource without throwing and should call Alter()' { - { Set-TargetResource @testParameters } | Should -Not -Throw - $script:WasMethodAlterCalled | Should -Be $true + Context 'When IsEnabled should be $true' { + BeforeEach { + $testParameters += @{ + IsEnabled = $true + TcpDynamicPort = $false + TcpPort = '4509' + RestartService = $true + } + + $mockExpectedValue_IsEnabled = $true + + Mock -CommandName Get-TargetResource -MockWith { + return @{ + ProtocolName = $mockTcpProtocolName + IsEnabled = $false + TcpDynamicPort = $testParameters.TcpDynamicPort + TcpPort = $testParameters.TcpPort + } + } + } + + It 'Should call Set-TargetResource without throwing and should call Alter()' { + { Set-TargetResource @testParameters } | Should -Not -Throw + $script:WasMethodAlterCalled | Should -Be $true - Assert-MockCalled -CommandName Restart-SqlService -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Restart-SqlService -ParameterFilter { + $SkipClusterCheck -eq $true + } -Exactly -Times 1 -Scope It + } } } diff --git a/Tests/Unit/SqlServerDSCHelper.Tests.ps1 b/Tests/Unit/SqlServerDSCHelper.Tests.ps1 index 2b12a6ec9..91aa4d079 100644 --- a/Tests/Unit/SqlServerDSCHelper.Tests.ps1 +++ b/Tests/Unit/SqlServerDSCHelper.Tests.ps1 @@ -139,9 +139,30 @@ InModuleScope $script:moduleName { InstanceName = '' ServiceName = 'MSSQLSERVER' Status = $mockDynamicStatus + IsClustered = $false } } -Verifiable -ParameterFilter { $SQLInstanceName -eq 'MSSQLSERVER' } + Mock -CommandName Connect-SQL -MockWith { + return @{ + Name = 'NOCLUSTERCHECK' + InstanceName = 'NOCLUSTERCHECK' + ServiceName = 'NOCLUSTERCHECK' + Status = $mockDynamicStatus + IsClustered = $true + } + } -Verifiable -ParameterFilter { $SQLInstanceName -eq 'NOCLUSTERCHECK' } + + Mock -CommandName Connect-SQL -MockWith { + return @{ + Name = 'NOCONNECT' + InstanceName = 'NOCONNECT' + ServiceName = 'NOCONNECT' + Status = $mockDynamicStatus + IsClustered = $true + } + } -Verifiable -ParameterFilter { $SQLInstanceName -eq 'NOCONNECT' } + Mock -CommandName Connect-SQL -MockWith { return @{ Name = 'NOAGENT' @@ -176,7 +197,7 @@ InModuleScope $script:moduleName { } ) } - } -Verifiable -ParameterFilter { $DisplayName -eq 'SQL Server (MSSQLSERVER)' } + } -Verifiable -ParameterFilter { $Name -eq 'MSSQLSERVER' } ## SQL instance with no installed SQL Agent Service Mock -CommandName Get-Service -MockWith { @@ -185,7 +206,25 @@ InModuleScope $script:moduleName { DisplayName = 'Microsoft SQL Server (NOAGENT)' DependentServices = @() } - } -Verifiable -ParameterFilter { $DisplayName -eq 'SQL Server (NOAGENT)' } + } -Verifiable -ParameterFilter { $Name -eq 'MSSQL$NOAGENT' } + + ## SQL instance with no installed SQL Agent Service + Mock -CommandName Get-Service -MockWith { + return @{ + Name = 'MSSQL$NOCLUSTERCHECK' + DisplayName = 'Microsoft SQL Server (NOCLUSTERCHECK)' + DependentServices = @() + } + } -Verifiable -ParameterFilter { $Name -eq 'MSSQL$NOCLUSTERCHECK' } + + ## SQL instance with no installed SQL Agent Service + Mock -CommandName Get-Service -MockWith { + return @{ + Name = 'MSSQL$NOCONNECT' + DisplayName = 'Microsoft SQL Server (NOCONNECT)' + DependentServices = @() + } + } -Verifiable -ParameterFilter { $Name -eq 'MSSQL$NOCONNECT' } ## SQL instance with stopped SQL Agent Service Mock -CommandName Get-Service -MockWith { @@ -201,7 +240,7 @@ InModuleScope $script:moduleName { } ) } - } -Verifiable -ParameterFilter { $DisplayName -eq 'SQL Server (STOPPEDAGENT)' } + } -Verifiable -ParameterFilter { $Name -eq 'MSSQL$STOPPEDAGENT' } Mock -CommandName Restart-Service -Verifiable Mock -CommandName Start-Service -Verifiable @@ -220,6 +259,30 @@ InModuleScope $script:moduleName { Assert-MockCalled -CommandName Start-Service -Scope It -Exactly -Times 1 } + It 'Should restart SQL Service, and not do cluster cluster check' { + Mock -CommandName Get-CimInstance + + { Restart-SqlService -SQLServer $env:ComputerName -SQLInstanceName 'NOCLUSTERCHECK' -SkipClusterCheck } | Should -Not -Throw + + Assert-MockCalled -CommandName Connect-SQL -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Get-Service -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Restart-Service -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Start-Service -Scope It -Exactly -Times 0 + Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 0 + } + + It 'Should restart SQL Service, and not do cluster cluster check nor check online status' { + Mock -CommandName Get-CimInstance + + { Restart-SqlService -SQLServer $env:ComputerName -SQLInstanceName 'NOCONNECT' -SkipClusterCheck -SkipWaitForOnline } | Should -Not -Throw + + Assert-MockCalled -CommandName Get-Service -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Restart-Service -Scope It -Exactly -Times 1 + Assert-MockCalled -CommandName Connect-SQL -Scope It -Exactly -Times 0 + Assert-MockCalled -CommandName Start-Service -Scope It -Exactly -Times 0 + Assert-MockCalled -CommandName Get-CimInstance -Scope It -Exactly -Times 0 + } + It 'Should restart SQL Service and not try to restart missing SQL Agent service' { { Restart-SqlService -SQLServer $env:ComputerName -SQLInstanceName 'NOAGENT' } | Should -Not -Throw @@ -852,109 +915,6 @@ InModuleScope $script:moduleName { Assert-VerifiableMock } - $mockApplicationDomainName = 'SqlServerDscHelperTests' - $mockApplicationDomainObject = [System.AppDomain]::CreateDomain($mockApplicationDomainName) - - <# - It is not possible to fully test this helper function since we can't mock having the correct assembly - in the GAC. So these test will try to load the wrong assembly and will catch the error. But that means - it will never test the rows after if fails to load the assembly. - #> - Describe 'Testing Register-SqlSmo' -Tag RegisterSqlSmo { - BeforeEach { - Mock -CommandName Get-SqlInstanceMajorVersion -MockWith { - return '0' # Mocking zero because that could never match a correct assembly - } -Verifiable - } - - Context 'When calling Register-SqlSmo to load the wrong assembly' { - It 'Should throw with the correct error' { - { - Register-SqlSmo -SQLInstanceName $mockInstanceName - } | Should -Throw 'Exception calling "Load" with "1" argument(s): "Could not load file or assembly ''Microsoft.SqlServer.Smo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'' or one of its dependencies. The system cannot find the file specified."' - - Assert-MockCalled -CommandName Get-SqlInstanceMajorVersion - } - } - - Context 'When calling Register-SqlSmo with a application domain to load the wrong assembly' { - It 'Should throw with the correct error' { - { - Register-SqlSmo -SQLInstanceName $mockInstanceName -ApplicationDomain $mockApplicationDomainObject - } | Should -Throw 'Exception calling "Load" with "1" argument(s): "Could not load file or assembly ''Microsoft.SqlServer.Smo, Version=0.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'' or one of its dependencies. The system cannot find the file specified."' - - Assert-MockCalled -CommandName Get-SqlInstanceMajorVersion - } - } - - Assert-VerifiableMock - } - - <# - It is not possible to fully test this helper function since we can't mock having the correct assembly - in the GAC. So these test will try to load the wrong assembly and will catch the error. But that means - it will never test the rows after if fails to load the assembly. - #> - Describe 'Testing Register-SqlWmiManagement' -Tag RegisterSqlWmiManagement { - BeforeEach { - Mock -CommandName Get-SqlInstanceMajorVersion -MockWith { - return '0' # Mocking zero because that could never match a correct assembly - } -Verifiable - - Mock -CommandName Register-SqlSmo -MockWith { - [System.AppDomain]::CreateDomain('SqlServerDscHelper') - } -ParameterFilter { - $SQLInstanceName -eq $mockInstanceName - } -Verifiable - } - - Context 'When calling Register-SqlWmiManagement to load the wrong assembly' { - It 'Should throw with the correct error' { - { - Register-SqlWmiManagement -SQLInstanceName $mockInstanceName - } | Should -Throw 'Exception calling "Load" with "1" argument(s): "Could not load file or assembly ''Microsoft.SqlServer.SqlWmiManagement, Version=0.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'' or one of its dependencies. The system cannot find the file specified."' - - Assert-MockCalled -CommandName Get-SqlInstanceMajorVersion - Assert-MockCalled -CommandName Register-SqlSmo -Exactly -Times 1 -Scope It -ParameterFilter { - $SQLInstanceName -eq $mockInstanceName -and $ApplicationDomain -eq $null - } - } - } - - Context 'When calling Register-SqlWmiManagement with a application domain to load the wrong assembly' { - It 'Should throw with the correct error' { - { - Register-SqlWmiManagement -SQLInstanceName $mockInstanceName -ApplicationDomain $mockApplicationDomainObject - } | Should -Throw 'Exception calling "Load" with "1" argument(s): "Could not load file or assembly ''Microsoft.SqlServer.SqlWmiManagement, Version=0.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91'' or one of its dependencies. The system cannot find the file specified."' - - Assert-MockCalled -CommandName Get-SqlInstanceMajorVersion - Assert-MockCalled -CommandName Register-SqlSmo -Exactly -Times 0 -Scope It -ParameterFilter { - $SQLInstanceName -eq $mockInstanceName -and $ApplicationDomain -eq $null - } - - Assert-MockCalled -CommandName Register-SqlSmo -Exactly -Times 1 -Scope It -ParameterFilter { - $SQLInstanceName -eq $mockInstanceName -and $ApplicationDomain.FriendlyName -eq $mockApplicationDomainName - } - } - } - - Assert-VerifiableMock - } - - <# - NOTE! This test must be after the tests for Register-SqlSmo and Register-SqlWmiManagement. - This test unloads the application domain that is used during those tests. - #> - Describe 'Testing Unregister-SqlAssemblies' -Tag UnregisterSqlAssemblies { - Context 'When calling Unregister-SqlAssemblies to unload the assemblies' { - It 'Should not throw an error' { - { - Unregister-SqlAssemblies -ApplicationDomain $mockApplicationDomainObject - } | Should -Not -Throw - } - } - } - Describe 'Testing Get-PrimaryReplicaServerObject' { BeforeEach { $mockServerObject = New-Object -TypeName Microsoft.SqlServer.Management.Smo.Server diff --git a/en-US/SqlServerDscHelper.strings.psd1 b/en-US/SqlServerDscHelper.strings.psd1 index ca2d4614e..33fcb096e 100644 --- a/en-US/SqlServerDscHelper.strings.psd1 +++ b/en-US/SqlServerDscHelper.strings.psd1 @@ -6,10 +6,6 @@ ConvertFrom-StringData @' ConnectedToAnalysisServicesInstance = Connected to Analysis Services instance '{0}'. FailedToConnectToAnalysisServicesInstance = Failed to connected to Analysis Services instance '{0}'. SqlMajorVersion = SQL major version is {0}. - CreatingApplicationDomain = Creating application domain '{0}'. - ReusingApplicationDomain = Reusing application domain '{0}'. - LoadingAssembly = Loading assembly '{0}'. - UnloadingApplicationDomain = Unloading application domain '{0}'. SqlServerVersionIsInvalid = Could not get the SQL version for the instance '{0}'. PropertyTypeInvalidForDesiredValues = Property 'DesiredValues' must be either a [System.Collections.Hashtable], [CimInstance] or [PSBoundParametersDictionary]. The type detected was {0}. PropertyTypeInvalidForValuesToCheck = If 'DesiredValues' is a CimInstance, then property 'ValuesToCheck' must contain a value. diff --git a/sv-SE/SqlServerDscHelper.strings.psd1 b/sv-SE/SqlServerDscHelper.strings.psd1 index 987b25b50..fcf20b6b9 100644 --- a/sv-SE/SqlServerDscHelper.strings.psd1 +++ b/sv-SE/SqlServerDscHelper.strings.psd1 @@ -6,10 +6,6 @@ ConvertFrom-StringData @' ConnectedToAnalysisServicesInstance = Ansluten till Analysis Services instans '{0}'. FailedToConnectToAnalysisServicesInstance = Misslyckades att ansluta till Analysis Services instans '{0}'. SqlMajorVersion = SQL major version är {0}. - CreatingApplicationDomain = Skapar applikationsdomän '{0}'. - ReusingApplicationDomain = Återanvänder applikationsdomän '{0}'. - LoadingAssembly = Laddar samling '{0}'. - UnloadingApplicationDomain = Återställer applikationsdomän '{0}'. SqlServerVersionIsInvalid = Kunde inte hämta SQL version för instansen '{0}'. PropertyTypeInvalidForDesiredValues = Egenskapen 'DesiredValues' måste vara endera en [System.Collections.Hashtable], [CimInstance] eller [PSBoundParametersDictionary]. Den typ som hittades var {0}. PropertyTypeInvalidForValuesToCheck = Om 'DesiredValues' är av typ CimInstance, då måste egenskapen 'ValuesToCheck' sättas till ett värde. @@ -37,7 +33,7 @@ ConvertFrom-StringData @' ExecuteQueryWithResultsFailed = Exekvering av fråga med resultat misslyckades mot databas '{0}'. ExecuteNonQueryFailed = Exekvering av icke-fråga misslyckades på databas '{0}'. AlterAvailabilityGroupReplicaFailed = Misslyckades att ändra Availability Group kopia '{0}'. - GetEffectivePermissionForLogin = Hämtar effektiva behörigeter för inloggningen '{0}' på '{1}'. + GetEffectivePermissionForLogin = Hämtar effektiva behörigheter för inloggningen '{0}' på '{1}'. # - NOTE! # - Below strings are used by helper functions New-TerminatingError and New-WarningMessage.