Skip to content

Commit

Permalink
Adding latest version of 'Test-DscParameterState' from JeaDsc (#46)
Browse files Browse the repository at this point in the history
- Test-DscParameterState can now handle scriptblocks. The parameter 'ValuesToCheck' was
   renamed to 'Properties' but an alias was added so it is not a braking change. The parameter 
   'ExcludeProperties' was added.
- Added a new test for the alias 'ValuesToCheck' pointing to 'Properties'.
  • Loading branch information
raandree authored Jul 22, 2020
1 parent baec570 commit e914604
Show file tree
Hide file tree
Showing 6 changed files with 288 additions and 41 deletions.
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## Added
### Added

- `Test-DscParameterState` can now handle scriptblocks. The parameter 'ValuesToCheck' was renamed to 'Properties' but an alias
was added so it is not a braking change. The parameter 'ExcludeProperties' was added.
- Added a new test for the alias 'ValuesToCheck' pointing to 'Properties'.
- Added cmdlet `Compare-ResourcePropertyState` that also introduces a new
design pattern to evaluate properties in both _Test_ and _Set_ - fixes
[issue #47](https://github.com/dsccommunity/DscResource.Common/issues/47).
Expand Down
22 changes: 19 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -674,8 +674,9 @@ A new design pattern was introduces that uses the cmdlet [`Compare-ResourcePrope
<!-- markdownlint-disable MD013 - Line length -->
```plaintext
Test-DscParameterState [-CurrentValues] <Object> [-DesiredValues] <Object>
[[-ValuesToCheck] <string[]>] [-TurnOffTypeChecking] [-ReverseCheck]
[-SortArrayValues] [<CommonParameters>]
[-Properties] <string[]> [[-ExcludeProperties] <string[]>]
[-TurnOffTypeChecking] [-ReverseCheck] [-SortArrayValues]
[<CommonParameters>]
```
<!-- markdownlint-enable MD013 - Line length -->

Expand Down Expand Up @@ -711,12 +712,27 @@ $getTargetResourceParameters = @{
$returnValue = Test-DscParameterState `
-CurrentValues (Get-TargetResource @getTargetResourceParameters) `
-DesiredValues $PSBoundParameters `
-ValuesToCheck @(
-ExcludeProperties @(
'FailsafeOperator'
'NotificationMethod'
)
```

##### Example 3

```powershell
$getTargetResourceParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
Name = $Name
}
$returnValue = Test-DscParameterState `
-CurrentValues (Get-TargetResource @getTargetResourceParameters) `
-DesiredValues $PSBoundParameters `
-Properties ServerName, Name
```

This compares the values in the current state against the desires state.
The function `Get-TargetResource` is called using just the required parameters
to get the values in the current state.
Expand Down
133 changes: 116 additions & 17 deletions source/Public/Test-DscParameterState.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
The hashtable of desired values. For example $PSBoundParameters with the
desired values.
.PARAMETER ValuesToCheck
.PARAMETER Properties
This is a list of properties in the desired values list should be checked.
If this is empty then all values in DesiredValues are checked.
.PARAMETER ExcludeProperties
This is a list of which properties in the desired values list should be checked.
If this is empty then all values in DesiredValues are checked.
Expand Down Expand Up @@ -48,14 +52,33 @@
$returnValue = Test-DscParameterState `
-CurrentValues (Get-TargetResource @getTargetResourceParameters) `
-DesiredValues $PSBoundParameters `
-ValuesToCheck @(
-ExcludeProperties @(
'FailsafeOperator'
'NotificationMethod'
)
This compares the values in the current state against the desires state.
The function Get-TargetResource is called using just the required parameters
to get the values in the current state.
to get the values in the current state. The parameter 'ExcludeProperties'
is used to exclude the properties 'FailsafeOperator' and
'NotificationMethod' from the comparison.
.EXAMPLE
$getTargetResourceParameters = @{
ServerName = $ServerName
InstanceName = $InstanceName
Name = $Name
}
$returnValue = Test-DscParameterState `
-CurrentValues (Get-TargetResource @getTargetResourceParameters) `
-DesiredValues $PSBoundParameters `
-Properties ServerName, Name
This compares the values in the current state against the desires state.
The function Get-TargetResource is called using just the required parameters
to get the values in the current state. The 'Properties' parameter is used
to to only compare the properties 'ServerName' and 'Name'.
#>
function Test-DscParameterState
{
Expand All @@ -72,7 +95,12 @@ function Test-DscParameterState

[Parameter()]
[System.String[]]
$ValuesToCheck,
[Alias('ValuesToCheck')]
$Properties,

[Parameter()]
[System.String[]]
$ExcludeProperties,

[Parameter()]
[System.Management.Automation.SwitchParameter]
Expand Down Expand Up @@ -117,22 +145,26 @@ function Test-DscParameterState
-ArgumentName 'CurrentValues'
}

if ($DesiredValues -is [Microsoft.Management.Infrastructure.CimInstance] -and -not $ValuesToCheck)
if ($DesiredValues -is [Microsoft.Management.Infrastructure.CimInstance] -and -not $Properties)
{
New-InvalidArgumentException `
-Message $script:localizedData.InvalidValuesToCheckError `
-ArgumentName 'ValuesToCheck'
-Message $script:localizedData.InvalidPropertiesError `
-ArgumentName Properties
}

$desiredValuesClean = Remove-CommonParameter -Hashtable $DesiredValues

if (-not $ValuesToCheck)
if (-not $Properties)
{
$keyList = $desiredValuesClean.Keys
}
else
{
$keyList = $ValuesToCheck
$keyList = $Properties
}
if ($ExcludeProperties)
{
$keyList = $keyList | Where-Object -FilterScript { $_ -notin $ExcludeProperties }
}

foreach ($key in $keyList)
Expand All @@ -151,7 +183,7 @@ function Test-DscParameterState
$currentValue = ConvertTo-HashTable -CimInstance $currentValue
}

if ($null -ne $desiredValue)
if ($desiredValue)
{
$desiredType = $desiredValue.GetType()
}
Expand All @@ -162,7 +194,7 @@ function Test-DscParameterState
}
}

if ($null -ne $currentValue)
if ($currentValue)
{
$currentType = $currentValue.GetType()
}
Expand Down Expand Up @@ -260,13 +292,13 @@ function Test-DscParameterState

if ($SortArrayValues)
{
$desiredArrayValues = $desiredArrayValues | Sort-Object
$currentArrayValues = $currentArrayValues | Sort-Object
$desiredArrayValues = @($desiredArrayValues | Sort-Object)
$currentArrayValues = @($currentArrayValues | Sort-Object)
}

for ($i = 0; $i -lt $desiredArrayValues.Count; $i++)
{
if ($null -ne $desiredArrayValues[$i])
if ($desiredArrayValues[$i])
{
$desiredType = $desiredArrayValues[$i].GetType()
}
Expand All @@ -277,7 +309,7 @@ function Test-DscParameterState
}
}

if ($null -ne $currentArrayValues[$i])
if ($currentArrayValues[$i])
{
$currentType = $currentArrayValues[$i].GetType()
}
Expand All @@ -299,6 +331,49 @@ function Test-DscParameterState
}
}

#Convert a scriptblock into a string as scriptblocks are not comparable
$wasCurrentArrayValuesConverted = $false
if ($currentArrayValues[$i] -is [scriptblock])
{
$currentArrayValues[$i] = if ($desiredArrayValues[$i] -is [string])
{
$currentArrayValues[$i] = $currentArrayValues[$i].Invoke()
}
else
{
$currentArrayValues[$i].ToString()
}
$wasCurrentArrayValuesConverted = $true
}
if ($desiredArrayValues[$i] -is [scriptblock])
{
$desiredArrayValues[$i] = if ($currentArrayValues[$i] -is [string] -and -not $wasCurrentArrayValuesConverted)
{
$desiredArrayValues[$i].Invoke()
}
else
{
$desiredArrayValues[$i].ToString()
}
}

if ($desiredType -eq [System.Collections.Hashtable] -and $currentType -eq [System.Collections.Hashtable])
{
$param = $PSBoundParameters
$param.CurrentValues = $currentArrayValues[$i]
$param.DesiredValues = $desiredArrayValues[$i]

if ($returnValue)
{
$returnValue = Test-DscParameterState @param
}
else
{
Test-DscParameterState @param | Out-Null
}
continue
}

if ($desiredArrayValues[$i] -ne $currentArrayValues[$i])
{
Write-Verbose -Message ($script:localizedData.NoMatchElementValueMismatchMessage -f $i, $desiredType.FullName, $key, $currentArrayValues[$i], $desiredArrayValues[$i])
Expand All @@ -319,7 +394,6 @@ function Test-DscParameterState
$param = $PSBoundParameters
$param.CurrentValues = $currentValue
$param.DesiredValues = $desiredValue
$null = $param.Remove('ValuesToCheck')

if ($returnValue)
{
Expand All @@ -333,6 +407,32 @@ function Test-DscParameterState
}
else
{
#Convert a scriptblock into a string as scriptblocks are not comparable
$wasCurrentValue = $false
if ($currentValue -is [scriptblock])
{
$currentValue = if ($desiredValue -is [string])
{
$currentValue = $currentValue.Invoke()
}
else
{
$currentValue.ToString()
}
$wasCurrentValue = $true
}
if ($desiredValue -is [scriptblock])
{
$desiredValue = if ($currentValue -is [string] -and -not $wasCurrentValue)
{
$desiredValue.Invoke()
}
else
{
$desiredValue.ToString()
}
}

if ($desiredValue -ne $currentValue)
{
Write-Verbose -Message ($script:localizedData.NoMatchValueMessage -f $desiredType.FullName, $key, $currentValue, $desiredValue)
Expand Down Expand Up @@ -360,6 +460,5 @@ function Test-DscParameterState
}

Write-Verbose -Message ($script:localizedData.TestDscParameterResultMessage -f $returnValue)

return $returnValue
}
2 changes: 1 addition & 1 deletion source/en-US/DscResource.Common.strings.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ ConvertFrom-StringData @'
AddressIPv6MismatchError = Address '{0}' is in IPv6 format, which does not match server address family {1}. Please correct either of them in the configuration and try again. (DRC0013)
InvalidDesiredValuesError = Property 'DesiredValues' in Test-DscParameterState must be either a Hashtable or CimInstance. Type detected was '{0}'. (DRC0014)
InvalidCurrentValuesError = Property 'CurrentValues' in Test-DscParameterState must be either a Hashtable, CimInstance, or CimIntance[]. Type detected was '{0}'. (DRC0015)
InvalidValuesToCheckError = If 'DesiredValues' is a CimInstance then property 'ValuesToCheck' must contain a value. (DRC0016)
InvalidPropertiesError = If 'DesiredValues' is a CimInstance then property 'Properties' must contain a value. (DRC0016)
MatchPsCredentialUsernameMessage = MATCH: PSCredential username match. Current state is '{0}' and desired state is '{1}'. (DRC0017)
NoMatchPsCredentialUsernameMessage = NOTMATCH: PSCredential username mismatch. Current state is '{0}' and desired state is '{1}'. (DRC0018)
NoMatchTypeMismatchMessage = NOTMATCH: Type mismatch for property '{0}' Current state type is '{1}' and desired type is '{2}'. (DRC0019)
Expand Down
3 changes: 2 additions & 1 deletion tests/Unit/Private/Test-DscObjectHasProperty.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ $ProjectName = ((Get-ChildItem -Path $ProjectPath\*\*.psd1).Where{
Import-Module $ProjectName

InModuleScope $ProjectName {
Describe 'NetworkingDsc.Common\Test-DscObjectHasProperty' {
Describe 'Test-DscObjectHasProperty' {

# Use the Get-Verb cmdlet to just get a simple object fast
$testDscObject = (Get-Verb)[0]

Expand Down
Loading

0 comments on commit e914604

Please sign in to comment.