Skip to content

Commit

Permalink
Add Assert-RequiredCommandParameter and `Test-AccountRequirePasswor…
Browse files Browse the repository at this point in the history
…d` (#94)

- 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](#92)
  - Related to SqlServerDsc [Issue #1796](dsccommunity/SqlServerDsc#1796).
- Added public function `Test-AccountRequirePassword` that returns true or
  false whether an account need a password to be passed - [Issue #93](#93)
  - Related to SqlServerDsc [Issue #1794](dsccommunity/SqlServerDsc#1794).
- 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 unit tests for `Assert-ElevatedUser` and `Test-IsNumericType` so
  the public function is tested correctly using the exported function.
  • Loading branch information
johlju authored Dec 30, 2022
1 parent b2201f0 commit 052cfde
Show file tree
Hide file tree
Showing 12 changed files with 610 additions and 52 deletions.
11 changes: 10 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
24 changes: 24 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
76 changes: 71 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

<!-- markdownlint-disable MD013 - Line length -->
```plaintext
Assert-BoundParameter [-BoundParameterList] <hashtable> [-MutuallyExclusiveList1] <string[]>
[-MutuallyExclusiveList2] <string[]> [<CommonParameters>]
Assert-BoundParameter -BoundParameterList <hashtable> -MutuallyExclusiveList1 <string[]> -MutuallyExclusiveList2 <string[]> [<CommonParameters>]
Assert-BoundParameter -BoundParameterList <hashtable> -RequiredParameter <string[]> [-IfParameterPresent <string[]>] [<CommonParameters>]
```
<!-- markdownlint-enable MD013 - Line length -->

Expand All @@ -75,6 +86,23 @@ Assert-BoundParameter @assertBoundParameterParameters
This example throws an exception if `$PSBoundParameters` contains both
the parameters `Parameter1` and `Parameter2`.

<!-- markdownlint-disable MD013 - Line length -->
```powershell
Assert-RequiredCommandParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('PBStartPortRange', 'PBEndPortRange')
```
<!-- markdownlint-enable MD013 - Line length -->

Throws an exception if either of the two parameters are not specified.

<!-- markdownlint-disable MD013 - Line length -->
```powershell
Assert-RequiredCommandParameter -BoundParameterList $PSBoundParameters -RequiredParameter @('Property2', 'Property3') -IfParameterPresent @('Property1')
```
<!-- markdownlint-enable MD013 - Line length -->

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.
Expand Down Expand Up @@ -843,6 +871,44 @@ Set-PSModulePath -Path '<Path 1>;<Path 2>' -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

<!-- markdownlint-disable MD013 - Line length -->
```plaintext
Test-AccountRequirePassword [-Name] <string> [<CommonParameters>]
```
<!-- markdownlint-enable MD013 - Line length -->

#### 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
Expand Down
89 changes: 89 additions & 0 deletions source/Private/Assert-RequiredCommandParameter.ps1
Original file line number Diff line number Diff line change
@@ -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'
)
)
}
}
}
}
63 changes: 52 additions & 11 deletions source/Public/Assert-BoundParameter.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
{
Expand All @@ -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
}
}
}
Loading

0 comments on commit 052cfde

Please sign in to comment.