diff --git a/CHANGELOG.md b/CHANGELOG.md index 15b0d3cefd..f0e93338ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,9 @@ coverage. - Changes to SqlServerMaxDop - Added en-US localization ([issue #616](https://github.com/PowerShell/SqlServerDsc/issues/616)). +- Changes to SqlServerLogin + - Added en-US localization ([issue #615](https://github.com/PowerShell/SqlServerDsc/issues/615)). + - Added unit tests to improved code coverage. ## 12.4.0.0 diff --git a/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 b/DSCResources/MSFT_SqlServerLogin/MSFT_SqlServerLogin.psm1 index 1c7269d0f8..2bdce6b9c9 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 0000000000..a5d61cd0df --- /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/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 b/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 index 4e304ff8cb..c9558d7a54 100644 --- a/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 +++ b/Modules/DscResource.Common/en-US/DscResource.Common.strings.psd1 @@ -103,19 +103,6 @@ ConvertFrom-StringData @' 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. - # AlwaysOnAvailabilityGroup CreateAvailabilityGroupReplicaFailed = Creating the Availability Group Replica '{0}' failed on the instance '{1}'. CreateAvailabilityGroupFailed = Creating the availability group '{0}'. diff --git a/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 b/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 index 4c6a7cd5f5..183e4c7b2e 100644 --- a/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 +++ b/Modules/DscResource.Common/sv-SE/DscResource.Common.strings.psd1 @@ -96,19 +96,6 @@ ConvertFrom-StringData @' 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. - # 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'. CreateAvailabilityGroupReplicaFailed = Creating the Availability Group Replica '{0}' failed on the instance '{1}'. diff --git a/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 b/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 index 32a3b847e8..76ddafe9d3 100644 --- a/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 +++ b/Modules/DscResource.LocalizationHelper/DscResource.LocalizationHelper.psm1 @@ -257,6 +257,62 @@ 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', diff --git a/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 b/Tests/Unit/MSFT_SqlServerLogin.Tests.ps1 index 218f6ea5ee..b5c5318308 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 } } }