diff --git a/.vscode/settings.json b/.vscode/settings.json index 2f0a10e..c524097 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,5 +37,14 @@ "[markdown]": { "files.trimTrailingWhitespace": true, "files.encoding": "utf8" - } + }, + "powershell.pester.useLegacyCodeLens": false, + "pester.testFilePath": [ + "[tT]ests/[uU]nit/*.[tT]ests.[pP][sS]1", + "[tT]ests/[uU]nit/**/*.[tT]ests.[pP][sS]1" + ], + "pester.runTestsInNewProcess": false, + "pester.pesterModulePath": "./output/RequiredModules/Pester", + "powershell.pester.codeLens": true, + "pester.suppressCodeLensNotice": true } diff --git a/CHANGELOG.md b/CHANGELOG.md index 9770f0b..4e42c0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Added private function `Assert-RequiredCommandParameter` that throws an + exception if a specified parameter is not assigned a value, and optionally + throws only if a specific parameter is passed. - [Issue #92](https://github.com/dsccommunity/DscResource.Common/issues/92) + - Related to SqlServerDsc [Issue #1796](https://github.com/dsccommunity/SqlServerDsc/issues/1796). +- Added public function `Test-AccountRequirePassword` that returns true or + false whether an account need a password to be passed - [Issue #93](https://github.com/dsccommunity/DscResource.Common/issues/93) + - Related to SqlServerDsc [Issue #1794](https://github.com/dsccommunity/SqlServerDsc/issues/1794). + +### Changed + +- DscResource.Common + - Updated Visual Studio Code project settings to configure testing for Pester 5. +- `Assert-BoundParameter` + - Now has a new parameter set that calls `Assert-RequiredCommandParameter` + which will throw an exception if a specified parameter is not assigned + a value, and optionally throws only if a specific parameter is passed. + +### Fixed + +- Fixed unit tests for `Assert-ElevatedUser` and `Test-IsNumericType` so + the public function is tested correctly using the exported function. + ## [0.13.1] - 2022-12-18 ### Changed diff --git a/README.md b/README.md index a4a291a..06ff659 100644 --- a/README.md +++ b/README.md @@ -37,18 +37,29 @@ functions. ### `Assert-BoundParameter` +This command asserts passed parameters. It takes a hashtable, normally +`$PSBoundParameters`. There are two parameter sets for this command. + +#### Mutually exclusive parameters are not set + Asserts that a specified set of parameters are not passed together with another set of parameters. -There is no built in logic to validate against parameters sets for DSC -so this can be used instead to validate the parameters that were set in -the configuration. + +>There is no built in logic to validate against parameters sets for DSC +>so this can be used instead to validate the parameters that were set in +>the configuration. + +#### Required parameter is set + +Assert that required parameters has been specified, and throws an exception if not. #### Syntax ```plaintext -Assert-BoundParameter [-BoundParameterList] [-MutuallyExclusiveList1] - [-MutuallyExclusiveList2] [] +Assert-BoundParameter -BoundParameterList -MutuallyExclusiveList1 -MutuallyExclusiveList2 [] + +Assert-BoundParameter -BoundParameterList -RequiredParameter [-IfParameterPresent ] [] ``` @@ -75,6 +86,23 @@ Assert-BoundParameter @assertBoundParameterParameters This example throws an exception if `$PSBoundParameters` contains both the parameters `Parameter1` and `Parameter2`. + +```powershell +Assert-RequiredCommandParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('PBStartPortRange', 'PBEndPortRange') +``` + + +Throws an exception if either of the two parameters are not specified. + + +```powershell +Assert-RequiredCommandParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('Property2', 'Property3') -IfParameterPresent @('Property1') +``` + + +Throws an exception if the parameter 'Property1' is specified and either +of the required parameters are not. + ### `Assert-ElevatedUser` Assert that the user has elevated the PowerShell session. @@ -843,6 +871,44 @@ Set-PSModulePath -Path ';' -Machine Sets the machine environment variable `PSModulePath` to the specified path or paths (separated with semi-colons). +### `Test-AccountRequirePassword` + +Returns whether the specified account require a password to be provided. +If the account is a (global) managed service account, virtual account, or a +built-in account then there is no need to provide a password. + +#### Syntax + + +```plaintext +Test-AccountRequirePassword [-Name] [] +``` + + +#### Outputs + +None. + +#### Example + +```powershell +Test-AccountRequirePassword -Name 'DOMAIN\MySqlUser' +``` + +Returns $true as a user account need a password. + +```powershell +Test-AccountRequirePassword -Name 'DOMAIN\MyMSA$' +``` + +Returns $false as a manged service account does not need a password. + +```powershell +Test-AccountRequirePassword -Name 'NT SERVICE\MSSQL$PAYROLL' +``` + +Returns $false as a virtual account does not need a password. + ### `Test-DscParameterState` This function is used to compare the values in the current state against diff --git a/source/Private/Assert-RequiredCommandParameter.ps1 b/source/Private/Assert-RequiredCommandParameter.ps1 new file mode 100644 index 0000000..37c157f --- /dev/null +++ b/source/Private/Assert-RequiredCommandParameter.ps1 @@ -0,0 +1,89 @@ +<# + .SYNOPSIS + Assert that required parameters has been specified. + + .DESCRIPTION + Assert that required parameters has been specified, and throws an exception if not. + + .PARAMETER BoundParameterList + A hashtable containing the parameters to evaluate. Normally this is set to + $PSBoundParameters. + + .PARAMETER RequiredParameter + One or more parameter names that is required to have been specified. + + .PARAMETER IfParameterPresent + One or more parameter names that if specified will trigger the evaluation. + If neither of the parameter names has been specified the evaluation of required + parameters are not made. + + .EXAMPLE + Assert-RequiredCommandParameter -BoundParameter $PSBoundParameters -RequiredParameter @('PBStartPortRange', 'PBEndPortRange') + + Throws an exception if either of the two parameters are not specified. + + .EXAMPLE + Assert-RequiredCommandParameter -BoundParameter $PSBoundParameters -RequiredParameter @('Property2', 'Property3') -IfParameterPresent @('Property1') + + Throws an exception if the parameter 'Property1' is specified and either of the required parameters are not. + + .OUTPUTS + None. +#> +function Assert-RequiredCommandParameter +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [System.Collections.Hashtable] + $BoundParameterList, + + [Parameter(Mandatory = $true)] + [System.String[]] + $RequiredParameter, + + [Parameter()] + [System.String[]] + $IfParameterPresent + ) + + $evaluateRequiredParameter = $true + + if ($PSBoundParameters.ContainsKey('IfParameterPresent')) + { + $hasIfParameterPresent = $BoundParameterList.Keys.Where( { $_ -in $IfParameterPresent } ) + + if (-not $hasIfParameterPresent) + { + $evaluateRequiredParameter = $false + } + } + + if ($evaluateRequiredParameter) + { + foreach ($parameter in $RequiredParameter) + { + if ($parameter -notin $BoundParameterList.Keys) + { + $errorMessage = if ($PSBoundParameters.ContainsKey('IfParameterPresent')) + { + $script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSetWhenParameterExist -f ($RequiredParameter -join ''', '''), ($IfParameterPresent -join ''', ''') + } + else + { + $script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSet -f ($RequiredParameter -join ''', ''') + } + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + $errorMessage, + 'ARCP0001', # cspell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidOperation, + 'Command parameters' + ) + ) + } + } + } +} diff --git a/source/Public/Assert-BoundParameter.ps1 b/source/Public/Assert-BoundParameter.ps1 index cdf7db9..5b7702b 100644 --- a/source/Public/Assert-BoundParameter.ps1 +++ b/source/Public/Assert-BoundParameter.ps1 @@ -20,6 +20,14 @@ An array of parameter names that are not allowed to be bound at the same time as those in MutuallyExclusiveList1. + .PARAMETER RequiredParameter + One or more parameter names that is required to have been specified. + + .PARAMETER IfParameterPresent + One or more parameter names that if specified will trigger the evaluation. + If neither of the parameter names has been specified the evaluation of required + parameters are not made. + .EXAMPLE $assertBoundParameterParameters = @{ BoundParameterList = $PSBoundParameters @@ -35,6 +43,16 @@ This example throws an exception if `$PSBoundParameters` contains both the parameters `Parameter1` and `Parameter2`. + + .EXAMPLE + Assert-BoundParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('PBStartPortRange', 'PBEndPortRange') + + Throws an exception if either of the two parameters are not specified. + + .EXAMPLE + Assert-BoundParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('Property2', 'Property3') -IfParameterPresent @('Property1') + + Throws an exception if the parameter 'Property1' is specified and either of the required parameters are not. #> function Assert-BoundParameter { @@ -46,24 +64,47 @@ function Assert-BoundParameter [System.Collections.Hashtable] $BoundParameterList, - [Parameter(Mandatory = $true)] + [Parameter(ParameterSetName = 'MutuallyExclusiveParameters', Mandatory = $true)] [System.String[]] $MutuallyExclusiveList1, - [Parameter(Mandatory = $true)] + [Parameter(ParameterSetName = 'MutuallyExclusiveParameters', Mandatory = $true)] [System.String[]] - $MutuallyExclusiveList2 - ) + $MutuallyExclusiveList2, - $itemFoundFromList1 = $BoundParameterList.Keys.Where({ $_ -in $MutuallyExclusiveList1 }) - $itemFoundFromList2 = $BoundParameterList.Keys.Where({ $_ -in $MutuallyExclusiveList2 }) + [Parameter(ParameterSetName = 'RequiredParameter', Mandatory = $true)] + [System.String[]] + $RequiredParameter, - if ($itemFoundFromList1.Count -gt 0 -and $itemFoundFromList2.Count -gt 0) + [Parameter(ParameterSetName = 'RequiredParameter')] + [System.String[]] + $IfParameterPresent + ) + + switch ($PSCmdlet.ParameterSetName) { - $errorMessage = ` - $script:localizedData.ParameterUsageWrong ` - -f ($MutuallyExclusiveList1 -join "','"), ($MutuallyExclusiveList2 -join "','") + 'MutuallyExclusiveParameters' + { + $itemFoundFromList1 = $BoundParameterList.Keys.Where({ $_ -in $MutuallyExclusiveList1 }) + $itemFoundFromList2 = $BoundParameterList.Keys.Where({ $_ -in $MutuallyExclusiveList2 }) + + if ($itemFoundFromList1.Count -gt 0 -and $itemFoundFromList2.Count -gt 0) + { + $errorMessage = ` + $script:localizedData.ParameterUsageWrong ` + -f ($MutuallyExclusiveList1 -join "','"), ($MutuallyExclusiveList2 -join "','") - New-InvalidArgumentException -ArgumentName 'Parameters' -Message $errorMessage + New-InvalidArgumentException -ArgumentName 'Parameters' -Message $errorMessage + } + + break + } + + 'RequiredParameter' + { + Assert-RequiredCommandParameter @PSBoundParameters + + break + } } } diff --git a/source/Public/Test-AccountRequirePassword.ps1 b/source/Public/Test-AccountRequirePassword.ps1 new file mode 100644 index 0000000..986c86a --- /dev/null +++ b/source/Public/Test-AccountRequirePassword.ps1 @@ -0,0 +1,73 @@ +<# + .SYNOPSIS + Returns whether the specified account require a password to be provided. + + .DESCRIPTION + Returns whether the specified account require a password to be provided. + If the account is a (global) managed service account, virtual account, or a + built-in account then there is no need to provide a password. + + .PARAMETER Name + Credential name for the account. + + .EXAMPLE + Test-AccountRequirePassword -Name 'DOMAIN\MyMSA$' + + Returns $false as a manged service account does not need a password. + + .EXAMPLE + Test-AccountRequirePassword -Name 'DOMAIN\MySqlUser' + + Returns $true as a user account need a password. + + .EXAMPLE + Test-AccountRequirePassword -Name 'NT SERVICE\MSSQL$PAYROLL' + + Returns $false as a virtual account does not need a password. + + .OUTPUTS + [System.Boolean] +#> +function Test-AccountRequirePassword +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [System.String] + $Name + ) + + # Assume local or domain service account. + $requirePassword = $true + + switch -Regex ($Name.ToUpper()) + { + # Built-in account. + '^(?:NT ?AUTHORITY\\)?(SYSTEM|LOCALSERVICE|LOCAL SERVICE|NETWORKSERVICE|NETWORK SERVICE)$' # CSpell: disable-line + { + $requirePassword = $false + + break + } + + # Virtual account. + '^(?:NT SERVICE\\)(.*)$' + { + $requirePassword = $false + + break + } + + # (Global) Managed Service Account. + '\$$' + { + $requirePassword = $false + + break + } + } + + return $requirePassword +} diff --git a/source/en-US/DscResource.Common.strings.psd1 b/source/en-US/DscResource.Common.strings.psd1 index 7928fd5..8acc2d1 100644 --- a/source/en-US/DscResource.Common.strings.psd1 +++ b/source/en-US/DscResource.Common.strings.psd1 @@ -39,4 +39,8 @@ ConvertFrom-StringData @' ## Assert-ElevatedUser ElevatedUser_UserNotElevated = This command must run in an elevated PowerShell session. (DRC0043) + + ## Assert-RequiredCommandParameter + RequiredCommandParameter_SpecificParametersMustAllBeSet = The parameters '{0}' must all be specified. (DRC0044) + RequiredCommandParameter_SpecificParametersMustAllBeSetWhenParameterExist = The parameters '{0}' must all be specified if either parameter '{1}' is specified. (DRC0045) '@ diff --git a/tests/Unit/Private/Assert-RequiredCommandParameter.Tests.ps1 b/tests/Unit/Private/Assert-RequiredCommandParameter.Tests.ps1 new file mode 100644 index 0000000..b410eef --- /dev/null +++ b/tests/Unit/Private/Assert-RequiredCommandParameter.Tests.ps1 @@ -0,0 +1,121 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + + Import-Module -Name $script:dscModuleName + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force +} + +Describe 'Assert-RequiredCommandParameter' -Tag 'Private' { + Context 'When required parameter is missing' { + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + $mockErrorMessage = $script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSet -f 'Parameter1' + + { Assert-RequiredCommandParameter -BoundParameterList @{} -RequiredParameter 'Parameter1' } | + Should -Throw -ExpectedMessage $mockErrorMessage + } + } + } + + Context 'When the required parameter is present' { + It 'Should not throw an error' { + InModuleScope -ScriptBlock { + { Assert-RequiredCommandParameter -BoundParameterList @{ + Parameter1 = 'Value1' + } -RequiredParameter 'Parameter1' } | + Should -Not -Throw + } + } + } + + Context 'When both required parameter and parameter in IfParameterPresent is not present' { + It 'Should not throw an error' { + InModuleScope -ScriptBlock { + { Assert-RequiredCommandParameter -BoundParameterList @{} -RequiredParameter 'Parameter1' -IfParameterPresent 'Parameter2' } | + Should -Not -Throw + } + } + } + + Context 'When the required parameter is not present and parameter in IfParameterPresent is present' { + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + $mockErrorMessage = $script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSetWhenParameterExist -f 'Parameter1', 'Parameter2' + + { + Assert-RequiredCommandParameter -BoundParameterList @{ + Parameter2 = 'Value2' + } -RequiredParameter 'Parameter1' -IfParameterPresent 'Parameter2' + } | Should -Throw -ExpectedMessage $mockErrorMessage + } + } + } + + Context 'When the parameters in IfParameterPresent is present and the required parameters are not present' { + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + $mockErrorMessage = $script:localizedData.RequiredCommandParameter_SpecificParametersMustAllBeSetWhenParameterExist -f "Parameter3', 'Parameter4", "Parameter1', 'Parameter2" + + { + Assert-RequiredCommandParameter -BoundParameterList @{ + Parameter1 = 'Value1' + Parameter2 = 'Value2' + } -RequiredParameter @('Parameter3', 'Parameter4') -IfParameterPresent @('Parameter1', 'Parameter2') + } | Should -Throw -ExpectedMessage $mockErrorMessage + } + } + } + + Context 'When the parameters in IfParameterPresent is present and required parameters are present' { + It 'Should throw the correct error' { + InModuleScope -ScriptBlock { + { + Assert-RequiredCommandParameter -BoundParameterList @{ + Parameter1 = 'Value1' + Parameter2 = 'Value2' + } -RequiredParameter @('Parameter1', 'Parameter2') -IfParameterPresent @('Parameter1', 'Parameter2') + } | Should -Not -Throw + } + } + } +} diff --git a/tests/Unit/Public/Assert-BoundParameter.Tests.ps1 b/tests/Unit/Public/Assert-BoundParameter.Tests.ps1 index 0bd50d2..835c66b 100644 --- a/tests/Unit/Public/Assert-BoundParameter.Tests.ps1 +++ b/tests/Unit/Public/Assert-BoundParameter.Tests.ps1 @@ -25,6 +25,39 @@ AfterAll { } Describe 'Assert-BoundParameter' -Tag 'AssertBoundParameter' { + It 'Should have the correct parameters in parameter set ' -ForEach @( + @{ + MockParameterSetName = 'MutuallyExclusiveParameters' + # cSpell: disable-next + MockExpectedParameters = '-BoundParameterList -MutuallyExclusiveList1 -MutuallyExclusiveList2 []' + } + @{ + MockParameterSetName = 'RequiredParameter' + # cSpell: disable-next + MockExpectedParameters = '-BoundParameterList -RequiredParameter [-IfParameterPresent ] []' + } + ) { + InModuleScope -Parameters $_ -ScriptBlock { + $result = (Get-Command -Name 'Assert-BoundParameter').ParameterSets | + Where-Object -FilterScript { + $_.Name -eq $mockParameterSetName + } | + Select-Object -Property @( + @{ + Name = 'ParameterSetName' + Expression = { $_.Name } + }, + @{ + Name = 'ParameterListAsString' + Expression = { $_.ToString() } + } + ) + + $result.ParameterSetName | Should -Be $MockParameterSetName + $result.ParameterListAsString | Should -Be $MockExpectedParameters + } + } + Context 'When the assert is successful' { Context 'When there are no bound parameters' { It 'Should not throw an error' { @@ -88,6 +121,21 @@ Describe 'Assert-BoundParameter' -Tag 'AssertBoundParameter' { } | Should -Not -Throw } } + + Context 'When the required parameter is present' { + BeforeAll { + Mock -CommandName Assert-RequiredCommandParameter + } + + It 'Should not throw an error' { + InModuleScope -ScriptBlock { + { Assert-BoundParameter -BoundParameterList @{ + Parameter1 = 'Value1' + } -RequiredParameter 'Parameter1' } | + Should -Not -Throw + } + } + } } Context 'When the assert fails' { @@ -138,5 +186,20 @@ Describe 'Assert-BoundParameter' -Tag 'AssertBoundParameter' { } | Should -Throw -ExpectedMessage "$errorMessage*" } } + + Context 'When the required parameter is not present' { + BeforeAll { + Mock -CommandName Assert-RequiredCommandParameter -MockWith { + throw 'Mocked error' + } + } + + It 'Should not throw an error' { + InModuleScope -ScriptBlock { + { Assert-BoundParameter -BoundParameterList @{} -RequiredParameter 'Parameter1' } | + Should -Throw -ExpectedMessage '*Mocked error*' + } + } + } } } diff --git a/tests/Unit/Public/Assert-ElevatedUser.Tests.ps1 b/tests/Unit/Public/Assert-ElevatedUser.Tests.ps1 index cde42c5..c45484c 100644 --- a/tests/Unit/Public/Assert-ElevatedUser.Tests.ps1 +++ b/tests/Unit/Public/Assert-ElevatedUser.Tests.ps1 @@ -24,7 +24,10 @@ BeforeDiscovery { } BeforeAll { - $script:dscModuleName = 'DSCResource.Common' + $script:dscModuleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force Import-Module -Name $script:dscModuleName @@ -61,17 +64,15 @@ Describe 'Assert-ElevatedUser' -Tag 'Public' { } It 'Should throw the correct error' -Skip:$mockIsElevated { - InModuleScope -ScriptBlock { - $mockErrorMessage = $script:localizedData.ElevatedUser_UserNotElevated - - { Assert-ElevatedUser } | Should -Throw -ExpectedMessage $mockErrorMessage + $mockErrorMessage = InModuleScope -ScriptBlock { + $script:localizedData.ElevatedUser_UserNotElevated } + + { Assert-ElevatedUser } | Should -Throw -ExpectedMessage $mockErrorMessage } It 'Should not throw an exception' -Skip:(-not $mockIsElevated) { - InModuleScope -ScriptBlock { - { Assert-ElevatedUser } | Should -Not -Throw - } + { Assert-ElevatedUser } | Should -Not -Throw } Context 'When on Linux or macOS' { @@ -106,9 +107,7 @@ Describe 'Assert-ElevatedUser' -Tag 'Public' { } It 'Should not throw an exception' { - InModuleScope -ScriptBlock { - { Assert-ElevatedUser } | Should -Not -Throw - } + { Assert-ElevatedUser } | Should -Not -Throw } } } diff --git a/tests/Unit/Public/Test-AccountRequirePassword.Tests.ps1 b/tests/Unit/Public/Test-AccountRequirePassword.Tests.ps1 new file mode 100644 index 0000000..3e12643 --- /dev/null +++ b/tests/Unit/Public/Test-AccountRequirePassword.Tests.ps1 @@ -0,0 +1,78 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '')] +param () + +BeforeDiscovery { + try + { + if (-not (Get-Module -Name 'DscResource.Test')) + { + # Assumes dependencies has been resolved, so if this module is not available, run 'noop' task. + if (-not (Get-Module -Name 'DscResource.Test' -ListAvailable)) + { + # Redirect all streams to $null, except the error stream (stream 2) + & "$PSScriptRoot/../../build.ps1" -Tasks 'noop' 2>&1 4>&1 5>&1 6>&1 > $null + } + + # If the dependencies has not been resolved, this will throw an error. + Import-Module -Name 'DscResource.Test' -Force -ErrorAction 'Stop' + } + } + catch [System.IO.FileNotFoundException] + { + throw 'DscResource.Test module dependency not found. Please run ".\build.ps1 -ResolveDependency -Tasks build" first.' + } +} + +BeforeAll { + $script:dscModuleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + + Import-Module -Name $script:dscModuleName + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscModuleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscModuleName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force +} + +Describe 'Test-AccountRequirePassword' -Tag 'Public' { + Context 'When service account is a built-in account' { + It 'Should return $false' { + Test-AccountRequirePassword -Name 'NT Authority\NETWORK SERVICE' | Should -BeFalse + } + } + + Context 'When service account is a virtual account' { + It 'Should return $false' { + Test-AccountRequirePassword -Name 'NT SERVICE\MSSQL$PAYROLL' | Should -BeFalse + } + } + + Context 'When service account is a (global) managed service account' { + It 'Should return $false' { + Test-AccountRequirePassword -Name 'DOMAIN\MyMSA$' | Should -BeFalse + } + } + + Context 'When service account is a local user account' { + It 'Should return $true' { + Test-AccountRequirePassword -Name 'MySqlUser' | Should -BeTrue + } + } + + Context 'When service account is a domain user account' { + It 'Should return $true' { + Test-AccountRequirePassword -Name 'DOMAIN\MySqlUser' | Should -BeTrue + } + } +} diff --git a/tests/Unit/Public/Test-IsNumericType.Tests.ps1 b/tests/Unit/Public/Test-IsNumericType.Tests.ps1 index 06dbf38..6db38c3 100644 --- a/tests/Unit/Public/Test-IsNumericType.Tests.ps1 +++ b/tests/Unit/Public/Test-IsNumericType.Tests.ps1 @@ -26,6 +26,9 @@ BeforeDiscovery { BeforeAll { $script:dscModuleName = 'DscResource.Common' + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:dscModuleName -All | Remove-Module -Force + Import-Module -Name $script:dscModuleName $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscModuleName @@ -46,21 +49,17 @@ Describe 'Test-IsNumericType' -Tag 'Public' { Context 'When passing value with named parameter' { Context 'When type is numeric' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = Test-IsNumericType -Object ([System.UInt32] 3) + $result = Test-IsNumericType -Object ([System.UInt32] 3) - $result | Should -BeTrue - } + $result | Should -BeTrue } } Context 'When type is not numeric' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = Test-IsNumericType -Object ([System.String] 'a') + $result = Test-IsNumericType -Object ([System.String] 'a') - $result | Should -BeFalse - } + $result | Should -BeFalse } } } @@ -68,41 +67,33 @@ Describe 'Test-IsNumericType' -Tag 'Public' { Context 'When passing value in pipeline' { Context 'When type is numeric' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = ([System.UInt32] 3) | Test-IsNumericType + $result = ([System.UInt32] 3) | Test-IsNumericType - $result | Should -BeTrue - } + $result | Should -BeTrue } } Context 'When type is not numeric' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = ([System.String] 'a') | Test-IsNumericType + $result = ([System.String] 'a') | Test-IsNumericType - $result | Should -BeFalse - } + $result | Should -BeFalse } } Context 'When type is an array with no numeric values' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = ('a', 'b') | Test-IsNumericType + $result = ('a', 'b') | Test-IsNumericType - $result | Should -BeFalse - } + $result | Should -BeFalse } } Context 'When type is an array with a numeric value' { It 'Should return the correct value' { - InModuleScope -ScriptBlock { - $result = ('a', 1, 'b') | Test-IsNumericType + $result = ('a', 1, 'b') | Test-IsNumericType - $result | Should -BeTrue - } + $result | Should -BeTrue } } }