diff --git a/CHANGELOG.md b/CHANGELOG.md index ab2cfd5..02e731a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Public command: - `Get-FileProductVersion` - Get the product version of a file. - `Test-PendingRestart` - Test if a pending restart is required. + - Private command + - `Clear-ZeroedEnumPropertyValue` from `DscResource.Base`. +- `Get-DscProperty` + - Add optional parameter `IgnoreZeroEnumValue`. ### Fixed diff --git a/source/Private/Clear-ZeroedEnumPropertyValue.ps1 b/source/Private/Clear-ZeroedEnumPropertyValue.ps1 new file mode 100644 index 0000000..20b31aa --- /dev/null +++ b/source/Private/Clear-ZeroedEnumPropertyValue.ps1 @@ -0,0 +1,47 @@ +<# + .SYNOPSIS + Removes any properties from a hashable which have values that are + type [System.Enum] and have an [System.Int32] value of 0. + + .DESCRIPTION + Removes any properties from a hashable which have values that are + type [System.Enum] and have an [System.Int32] value of 0. + + .PARAMETER InputObject + The hashtable to be checked. + + .EXAMPLE + Clear-ZeroedEnumPropertyValue -InputObject $ht + + .OUTPUTS + [System.Collections.Hashtable] +#> + +function Clear-ZeroedEnumPropertyValue +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param ( + [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [System.Collections.Hashtable] + $InputObject + ) + + process + { + $result = @{} + + foreach ($property in $InputObject.Keys) + { + $value = $InputObject.$property + if ($value -is [System.Enum] -and [System.Int32]$value.value__ -eq 0) + { + continue + } + + $result.$property = $value + } + + return $result + } +} diff --git a/source/Public/Get-DscProperty.ps1 b/source/Public/Get-DscProperty.ps1 index d9693f4..96d59c7 100644 --- a/source/Public/Get-DscProperty.ps1 +++ b/source/Public/Get-DscProperty.ps1 @@ -26,6 +26,9 @@ If left out all properties are returned regardless if there is a value assigned or not. + .PARAMETER IgnoreZeroEnumValue + Specifies to return only Enum properties that has been assigned a non zero value. + .OUTPUTS System.Collections.Hashtable @@ -55,6 +58,12 @@ Returns the DSC resource properties that has the specified attributes and has a non-null value assigned. + .EXAMPLE + Get-DscProperty -InputObject $this -Attribute @('Optional') -HasValue -IgnoreZeroEnumValue + + Returns the DSC resource properties that has the specified attributes and + has a non-null value assigned, and any Enum properties that has a non-zero value. + .OUTPUTS [System.Collections.Hashtable] @@ -64,31 +73,39 @@ #> function Get-DscProperty { - [CmdletBinding()] + [CmdletBinding(DefaultParameterSetName = 'Default')] [OutputType([System.Collections.Hashtable])] param ( - [Parameter(Mandatory = $true, ValueFromPipeline = $true)] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'Default')] + [Parameter(Mandatory = $true, ValueFromPipeline = $true, ParameterSetName = 'HasValue')] [PSObject] $InputObject, - [Parameter()] + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'HasValue')] [System.String[]] $Name, - [Parameter()] + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'HasValue')] [System.String[]] $ExcludeName, - [Parameter()] + [Parameter(ParameterSetName = 'Default')] + [Parameter(ParameterSetName = 'HasValue')] [ValidateSet('Key', 'Mandatory', 'NotConfigurable', 'Optional')] [Alias('Type')] [System.String[]] $Attribute, - [Parameter()] + [Parameter(ParameterSetName = 'HasValue', Mandatory = $true)] [System.Management.Automation.SwitchParameter] - $HasValue + $HasValue, + + [Parameter(ParameterSetName = 'HasValue')] + [System.Management.Automation.SwitchParameter] + $IgnoreZeroEnumValue ) process @@ -167,6 +184,11 @@ function Get-DscProperty $getPropertyResult.$currentProperty = $InputObject.$currentProperty } + if ($IgnoreZeroEnumValue.IsPresent) + { + $getPropertyResult = $getPropertyResult | Clear-ZeroedEnumPropertyValue + } + return $getPropertyResult } } diff --git a/tests/Unit/Private/Clear-ZeroedEnumPropertyValue.Tests.ps1 b/tests/Unit/Private/Clear-ZeroedEnumPropertyValue.Tests.ps1 new file mode 100644 index 0000000..c4b3cb7 --- /dev/null +++ b/tests/Unit/Private/Clear-ZeroedEnumPropertyValue.Tests.ps1 @@ -0,0 +1,154 @@ +[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' 3>&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:moduleName = 'DscResource.Common' + + # Make sure there are not other modules imported that will conflict with mocks. + Get-Module -Name $script:moduleName -All | Remove-Module -Force + + Import-Module -Name $script:moduleName + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:moduleName + $PSDefaultParameterValues['Should:ModuleName'] = $script:moduleName +} + +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:moduleName -All | Remove-Module -Force +} + +Describe 'Clear-ZeroedEnumPropertyValue' -Tag 'Private' { + Context 'When the hashtable does not contain zeroed Enum properties' { + Context 'When input is passed as a named variable' { + It 'Should return the same amount of values' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testParams = @{ + Variable1 = 'SomeString' + Variable2 = [System.Int32] 10 + Variable3 = $true + Variable4 = New-TimeSpan -Days 8 + } + + $result = Clear-ZeroedEnumPropertyValue -InputObject $testParams + + $result.Count | Should -Be $testParams.Count + } + } + } + + Context 'When input is passed via pipeline' { + It 'Should return the same amount of values' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testParams = @{ + Variable1 = 'SomeString' + Variable2 = [System.Int32] 10 + Variable3 = $true + Variable4 = New-TimeSpan -Days 8 + } + + $result = $testParams | Clear-ZeroedEnumPropertyValue + + $result.Count | Should -Be $testParams.Count + } + } + } + } + + Context 'When the hashtable does contain zeroed Enum properties' { + Context 'When input is passed as a named variable' { + It 'Should return the same amount of values' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + enum MyMockEnum + { + Value1 = 1 + Value2 + Value3 + Value4 + Value5 + } + + $testParams = @{ + Variable1 = 'SomeString' + Variable2 = [System.Int32] 10 + Variable3 = $true + Variable4 = New-TimeSpan -Days 8 + Variable5 = [MyMockEnum]::Value1 + Variable6 = [MyMockEnum]::new() + Variable7 = [MyMockEnum]::Value3 + Variable8 = [MyMockEnum]::new() + } + + $result = Clear-ZeroedEnumPropertyValue -InputObject $testParams + + $result.Count | Should -Be ($testParams.Count - 2) + } + } + } + + Context 'When input is passed via pipeline' { + It 'Should return the same amount of values' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + enum MyMockEnum + { + Value1 = 1 + Value2 + Value3 + Value4 + Value5 + } + + $testParams = @{ + Variable1 = 'SomeString' + Variable2 = [System.Int32] 10 + Variable3 = $true + Variable4 = New-TimeSpan -Days 8 + Variable5 = [MyMockEnum]::Value1 + Variable6 = [MyMockEnum]::new() + Variable7 = [MyMockEnum]::Value3 + Variable8 = [MyMockEnum]::new() + } + + $result = $testParams | Clear-ZeroedEnumPropertyValue + + $result.Count | Should -Be ($testParams.Count - 2) + } + } + } + } +} diff --git a/tests/Unit/Public/Get-DscProperty.Tests.ps1 b/tests/Unit/Public/Get-DscProperty.Tests.ps1 index 9d90f82..5a565db 100644 --- a/tests/Unit/Public/Get-DscProperty.Tests.ps1 +++ b/tests/Unit/Public/Get-DscProperty.Tests.ps1 @@ -625,6 +625,69 @@ Describe 'Get-DscProperty' -Tag 'Public' { } } + Context 'When using parameter IgnoreZeroEnumValue' { + Context 'When getting all optional properties' { + BeforeAll { + enum MyEnum + { + MyValue1 = 1 + MyValue2 + MyValue3 + } + + class MyMockResource + { + [DscProperty(Key)] + [System.String] + $MyResourceKeyProperty1 + + [DscProperty(Key)] + [System.String] + $MyResourceKeyProperty2 + + [DscProperty(Mandatory)] + [System.String] + $MyResourceMandatoryProperty + + [DscProperty()] + [MyEnum] + $MyResourceProperty1 + + [DscProperty()] + [MyEnum] + $MyResourceProperty2 + + [DscProperty(NotConfigurable)] + [System.String] + $MyResourceReadProperty + } + + $script:mockResourceBaseInstance = [MyMockResource]::new() + $script:mockResourceBaseInstance.MyResourceKeyProperty1 = 'MockValue1' + $script:mockResourceBaseInstance.MyResourceKeyProperty2 = 'MockValue2' + $script:mockResourceBaseInstance.MyResourceMandatoryProperty = 'MockValue3' + $script:mockResourceBaseInstance.MyResourceProperty1 = [MyEnum]::new() + $script:mockResourceBaseInstance.MyResourceProperty2 = [MyEnum]::MyValue3 + } + + It 'Should return the correct value' { + $result = Get-DscProperty -Attribute 'Optional' -HasValue -InputObject $script:mockResourceBaseInstance -IgnoreZeroEnumValue + + $result | Should -BeOfType [System.Collections.Hashtable] + + $result.Keys | Should -Not -Contain 'MyResourceMandatoryProperty' -Because 'mandatory properties should not be part of the collection' + $result.Keys | Should -Not -Contain 'MyResourceKeyProperty1' -Because 'key properties should not be part of the collection' + $result.Keys | Should -Not -Contain 'MyResourceKeyProperty2' -Because 'key properties should not be part of the collection' + $result.Keys | Should -Not -Contain 'MyResourceReadProperty' -Because 'read properties should not be part of the collection' + + $result.Keys | Should -Not -Contain 'MyResourceProperty1' -Because 'the enum property has a zero value' + + $result.Keys | Should -Contain 'MyResourceProperty2' -Because 'the enum property has a non zero value' + $result.MyResourceProperty2 | Should -Be MyValue3 + } + } + } + Context 'When getting specific named properties' { BeforeAll { class MyMockResource