From a53ae947b3b38d164f5eec4008953e4850501d5e Mon Sep 17 00:00:00 2001 From: Johan Ljunggren Date: Wed, 7 Aug 2019 10:56:06 +0200 Subject: [PATCH] Changes to ActiveDirectoryDsc - New resource ADDomainControllerProperties (issue #301). --- CHANGELOG.md | 1 + .../MSFT_ADDomainControllerProperties.psm1 | 197 +++++++++++++++ ...FT_ADDomainControllerProperties.schema.mof | 6 + .../README.md | 8 + ..._ADDomainControllerProperties.strings.psd1 | 8 + ...bout_ADDomainControllerProperties.help.txt | 39 +++ ...rProperties_SetContentFreshness_Config.ps1 | 36 +++ .../ActiveDirectoryDsc.Common.psm1 | 1 + ...ControllerProperties.Integration.Tests.ps1 | 137 ++++++++++ ...FT_ADDomainControllerProperties.config.ps1 | 60 +++++ Tests/Unit/ActiveDirectory.Common.Tests.ps1 | 54 ++++ ...SFT_ADDomainControllerProperties.Tests.ps1 | 235 ++++++++++++++++++ 12 files changed, 782 insertions(+) create mode 100644 DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.psm1 create mode 100644 DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.schema.mof create mode 100644 DSCResources/MSFT_ADDomainControllerProperties/README.md create mode 100644 DSCResources/MSFT_ADDomainControllerProperties/en-US/MSFT_ADDomainControllerProperties.strings.psd1 create mode 100644 DSCResources/MSFT_ADDomainControllerProperties/en-US/about_ADDomainControllerProperties.help.txt create mode 100644 Examples/Resources/ADDomainControllerProperties/1-ADDomainControllerProperties_SetContentFreshness_Config.ps1 create mode 100644 Tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 create mode 100644 Tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 create mode 100644 Tests/Unit/MSFT_ADDomainControllerProperties.Tests.ps1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 68d4f98a2..e5d0ebc88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - BREAKING CHANGE: ADRecycleBin is replaced by the new resource ADOptionalFeature ([issue #162](https://github.com/PowerShell/ActiveDirectoryDsc/issues/162)). - New resource ADOptionalFeature ([issue #162](https://github.com/PowerShell/ActiveDirectoryDsc/issues/162)). + - New resource ADDomainControllerProperties ([issue #301](https://github.com/PowerShell/ActiveDirectoryDsc/issues/301)). - BREAKING CHANGE: Renamed the xActiveDirectory to ActiveDirectoryDsc and removed the 'x' from all resource names ([issue #312](https://github.com/PowerShell/ActiveDirectoryDsc/issues/312)). - The helper function `Find-DomainController` is exported in the module diff --git a/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.psm1 b/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.psm1 new file mode 100644 index 000000000..80d3b5bdf --- /dev/null +++ b/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.psm1 @@ -0,0 +1,197 @@ +$script:resourceModulePath = Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent +$script:modulesFolderPath = Join-Path -Path $script:resourceModulePath -ChildPath 'Modules' + +$script:localizationModulePath = Join-Path -Path $script:modulesFolderPath -ChildPath 'ActiveDirectoryDsc.Common' +Import-Module -Name (Join-Path -Path $script:localizationModulePath -ChildPath 'ActiveDirectoryDsc.Common.psm1') + +$script:localizedData = Get-LocalizedData -ResourceName 'MSFT_ADDomainControllerProperties' + +<# + .SYNOPSIS + Returns the current state of the properties of the domain controller. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. +#> +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance + ) + + Write-Verbose -Message ( + $script:localizedData.RetrievingProperties -f $env:COMPUTERNAME + ) + + $getTargetResourceReturnValue = @{ + IsSingleInstance = $IsSingleInstance + ContentFreshness = 0 + } + + $getCimInstanceParameters = @{ + Namespace = 'ROOT/MicrosoftDfs' + Query = 'select MaxOfflineTimeInDays from DfsrMachineConfig' + } + + $getTargetResourceReturnValue['ContentFreshness'] = (Get-CimInstance @getCimInstanceParameters).MaxOfflineTimeInDays + + return $getTargetResourceReturnValue +} + +<# + .SYNOPSIS + Determines if the properties are in the desired state. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + + .PARAMETER ContentFreshness + Specifies the Distributed File System Replication (DFSR) server threshold + after the number of days its content is considered stale (MaxOfflineTimeInDays) + Once the content is considered stale, the Distributed File System Replication + (DFSR) server will no longer be able to replicate. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.UInt32] + $ContentFreshness + ) + + Write-Verbose -Message ( + $script:localizedData.TestConfiguration -f $env:COMPUTERNAME + ) + + $compareTargetResourceStateResult = Compare-TargetResourceState @PSBoundParameters + + if ($false -in $compareTargetResourceStateResult.InDesiredState) + { + Write-Verbose -Message $script:localizedData.DomainControllerNotInDesiredState + + $testTargetResourceReturnValue = $false + } + else + { + Write-Verbose -Message $script:localizedData.DomainControllerInDesiredState + + $testTargetResourceReturnValue = $true + } + + return $testTargetResourceReturnValue +} + +<# + .SYNOPSIS + Sets the properties on the Active Directory domain controller. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + + .PARAMETER ContentFreshness + Specifies the Distributed File System Replication (DFSR) server threshold + after the number of days its content is considered stale (MaxOfflineTimeInDays) + Once the content is considered stale, the Distributed File System Replication + (DFSR) server will no longer be able to replicate. +#> +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.UInt32] + $ContentFreshness + ) + + $compareTargetResourceStateResult = Compare-TargetResourceState @PSBoundParameters + + # Get all properties that are not in desired state. + $propertiesNotInDesiredState = $compareTargetResourceStateResult | Where-Object -FilterScript { + -not $_.InDesiredState + } + + if ($propertiesNotInDesiredState.Where( { $_.ParameterName -eq 'ContentFreshness' })) + { + Write-Verbose -Message ( + $script:localizedData.ContentFreshnessUpdated -f $ContentFreshness + ) + + $setCimInstanceParameters = @{ + Namespace = 'ROOT/MicrosoftDfs' + Query = 'select MaxOfflineTimeInDays from DfsrMachineConfig' + Property = @{ + MaxOfflineTimeInDays = $ContentFreshness + } + + } + + $null = Set-CimInstance @setCimInstanceParameters + } +} + +<# + .SYNOPSIS + Compares the properties in the current state with the properties of the + desired state and returns a hashtable with the comparison result. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + + .PARAMETER ContentFreshness + Specifies the Distributed File System Replication (DFSR) server threshold + after the number of days its content is considered stale (MaxOfflineTimeInDays) + Once the content is considered stale, the Distributed File System Replication + (DFSR) server will no longer be able to replicate. +#> +function Compare-TargetResourceState +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [System.UInt32] + $ContentFreshness + ) + + $getTargetResourceParameters = @{ + IsSingleInstance = $IsSingleInstance + } + + $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters + + $compareTargetResourceStateParameters = @{ + CurrentValues = $getTargetResourceResult + DesiredValues = $PSBoundParameters + Properties = @('ContentFreshness') + } + + return Compare-ResourcePropertyState @compareTargetResourceStateParameters +} diff --git a/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.schema.mof b/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.schema.mof new file mode 100644 index 000000000..b358aa4bf --- /dev/null +++ b/DSCResources/MSFT_ADDomainControllerProperties/MSFT_ADDomainControllerProperties.schema.mof @@ -0,0 +1,6 @@ +[ClassVersion("1.0.0.0"), FriendlyName("ADDomainControllerProperties")] +class MSFT_ADDomainControllerProperties : OMI_BaseResource +{ + [Key, Description("Specifies the resource is a single instance, the value must be 'Yes'."), ValueMap{"Yes"}, Values{"Yes"}] String IsSingleInstance; + [Write, Description("Specifies the Distributed File System Replication (DFSR) server threshold after the number of days its content is considered stale (MaxOfflineTimeInDays). Once the content is considered stale, the Distributed File System Replication (DFSR) server will no longer be able to replicate.")] UInt32 ContentFreshness; +}; diff --git a/DSCResources/MSFT_ADDomainControllerProperties/README.md b/DSCResources/MSFT_ADDomainControllerProperties/README.md new file mode 100644 index 000000000..8c24edca8 --- /dev/null +++ b/DSCResources/MSFT_ADDomainControllerProperties/README.md @@ -0,0 +1,8 @@ +# Description + +This resource enforces the single instance properties of a domain controller. +*Properties that must always have a value, but the value can be changed.* + +## Requirements + +* Target machine must be running Windows Server 2008 R2 or later. diff --git a/DSCResources/MSFT_ADDomainControllerProperties/en-US/MSFT_ADDomainControllerProperties.strings.psd1 b/DSCResources/MSFT_ADDomainControllerProperties/en-US/MSFT_ADDomainControllerProperties.strings.psd1 new file mode 100644 index 000000000..efda497f6 --- /dev/null +++ b/DSCResources/MSFT_ADDomainControllerProperties/en-US/MSFT_ADDomainControllerProperties.strings.psd1 @@ -0,0 +1,8 @@ +# culture="en-US" +ConvertFrom-StringData @' + RetrievingProperties = Retrieving the properties for the domain controller '{0}'. (ADDCP0001) + TestConfiguration = Determining the current state of the properties on the domain controller '{0}'. (ADDCP0002) + DomainControllerInDesiredState = The domain controller is in the desired state. (ADDCP0003) + DomainControllerNotInDesiredState = The domain controller is not in the desired state. (ADDCP0004) + ContentFreshnessUpdated = The content freshness property (MaxOfflineTimeInDays) will be updated to {0} days. (ADDCP0005) +'@ diff --git a/DSCResources/MSFT_ADDomainControllerProperties/en-US/about_ADDomainControllerProperties.help.txt b/DSCResources/MSFT_ADDomainControllerProperties/en-US/about_ADDomainControllerProperties.help.txt new file mode 100644 index 000000000..3b6ecf3ec --- /dev/null +++ b/DSCResources/MSFT_ADDomainControllerProperties/en-US/about_ADDomainControllerProperties.help.txt @@ -0,0 +1,39 @@ +.NAME + ADDomainControllerProperties + +.DESCRIPTION + This resource enforces the single instance properties of a domain controller. + *Properties that must always have a value, but the value can be changed.* + + ## Requirements + + * Target machine must be running Windows Server 2008 R2 or later. + +.PARAMETER IsSingleInstance + Key - String + Allowed values: Yes + Specifies the resource is a single instance, the value must be 'Yes'. + +.PARAMETER ContentFreshness + Write - UInt32 + Specifies the Distributed File System Replication (DFSR) server threshold after the number of days its content is considered stale (MaxOfflineTimeInDays). Once the content is considered stale, the Distributed File System Replication (DFSR) server will no longer be able to replicate. + +.EXAMPLE 1 + +This configuration will set the content freshness to 100 days. + +Configuration ADDomainControllerProperties_SetContentFreshness_Config +{ + Import-DscResource -ModuleName ActiveDirectoryDsc + + node localhost + { + ADDomainControllerProperties 'ContentFreshness' + { + IsSingleInstance = 'Yes' + ContentFreshness = 100 + } + } +} + + diff --git a/Examples/Resources/ADDomainControllerProperties/1-ADDomainControllerProperties_SetContentFreshness_Config.ps1 b/Examples/Resources/ADDomainControllerProperties/1-ADDomainControllerProperties_SetContentFreshness_Config.ps1 new file mode 100644 index 000000000..755134167 --- /dev/null +++ b/Examples/Resources/ADDomainControllerProperties/1-ADDomainControllerProperties_SetContentFreshness_Config.ps1 @@ -0,0 +1,36 @@ +<#PSScriptInfo +.VERSION 1.0.0 +.GUID 924568d9-9764-4277-ab85-5a03b818bf6d +.AUTHOR Microsoft Corporation +.COMPANYNAME Microsoft Corporation +.COPYRIGHT (c) Microsoft Corporation. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/PowerShell/ActiveDirectoryDsc/blob/master/LICENSE +.PROJECTURI https://github.com/PowerShell/ActiveDirectoryDsc +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES First version. +.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core +#> + +#Requires -module ActiveDirectoryDsc + +<# + .DESCRIPTION + This configuration will set the content freshness to 100 days. +#> +Configuration ADDomainControllerProperties_SetContentFreshness_Config +{ + Import-DscResource -ModuleName ActiveDirectoryDsc + + node localhost + { + ADDomainControllerProperties 'ContentFreshness' + { + IsSingleInstance = 'Yes' + ContentFreshness = 100 + } + } +} diff --git a/Modules/ActiveDirectoryDsc.Common/ActiveDirectoryDsc.Common.psm1 b/Modules/ActiveDirectoryDsc.Common/ActiveDirectoryDsc.Common.psm1 index 832da6ba6..fe73a4193 100644 --- a/Modules/ActiveDirectoryDsc.Common/ActiveDirectoryDsc.Common.psm1 +++ b/Modules/ActiveDirectoryDsc.Common/ActiveDirectoryDsc.Common.psm1 @@ -1831,6 +1831,7 @@ function Test-DscPropertyState $supportedTypes = @( 'String' 'Int32' + 'UInt32' 'Int16' 'UInt16' 'Single' diff --git a/Tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 b/Tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 new file mode 100644 index 000000000..a9a263d1a --- /dev/null +++ b/Tests/Integration/MSFT_ADDomainControllerProperties.Integration.Tests.ps1 @@ -0,0 +1,137 @@ +if ($env:APPVEYOR -eq $true) +{ + Write-Warning -Message 'Integration test is not supported in AppVeyor.' + return +} + +$script:dscModuleName = 'ActiveDirectoryDsc' +$script:dscResourceFriendlyName = 'ADDomainControllerProperties' +$script:dscResourceName = "MSFT_$($script:dscResourceFriendlyName)" + +#region HEADER +# Integration Test Template Version: 1.3.3 +[System.String] $script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests')) +} + +Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -TestType Integration +#endregion + +try +{ + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" + . $configFile + + Describe "$($script:dscResourceName)_Integration" { + BeforeAll { + $resourceId = "[$($script:dscResourceFriendlyName)]Integration_Test" + } + + $configurationName = "$($script:dscResourceName)_SetPropertyValues_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' + $resourceCurrentState.ContentFreshness | Should -Be 100 + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + + $configurationName = "$($script:dscResourceName)_RestoreDefaultValues_Config" + + Context ('When using configuration {0}' -f $configurationName) { + It 'Should compile and apply the MOF without throwing' { + { + $configurationParameters = @{ + OutputPath = $TestDrive + # The variable $ConfigurationData was dot-sourced above. + ConfigurationData = $ConfigurationData + } + + & $configurationName @configurationParameters + + $startDscConfigurationParameters = @{ + Path = $TestDrive + ComputerName = 'localhost' + Wait = $true + Verbose = $true + Force = $true + ErrorAction = 'Stop' + } + + Start-DscConfiguration @startDscConfigurationParameters + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { + $script:currentConfiguration = Get-DscConfiguration -Verbose -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $resourceCurrentState = $script:currentConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq $configurationName ` + -and $_.ResourceId -eq $resourceId + } + + $resourceCurrentState.IsSingleInstance | Should -Be 'Yes' + $resourceCurrentState.ContentFreshness | Should -Be 60 + } + + It 'Should return $true when Test-DscConfiguration is run' { + Test-DscConfiguration -Verbose | Should -Be 'True' + } + } + } +} +finally +{ + #region FOOTER + Restore-TestEnvironment -TestEnvironment $TestEnvironment + #endregion +} diff --git a/Tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 b/Tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 new file mode 100644 index 000000000..36ff9b3e8 --- /dev/null +++ b/Tests/Integration/MSFT_ADDomainControllerProperties.config.ps1 @@ -0,0 +1,60 @@ +#region HEADER +# Integration Test Config Template Version: 1.2.0 +#endregion + +$configFile = [System.IO.Path]::ChangeExtension($MyInvocation.MyCommand.Path, 'json') +if (Test-Path -Path $configFile) +{ + <# + Allows reading the configuration data from a JSON file, for real testing + scenarios outside of the CI. + #> + $ConfigurationData = Get-Content -Path $configFile | ConvertFrom-Json +} +else +{ + $ConfigurationData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + CertificateFile = $env:DscPublicCertificatePath + } + ) + } +} + +<# + .SYNOPSIS + Sets the supported property values. +#> +Configuration MSFT_ADDomainControllerProperties_SetPropertyValues_Config +{ + Import-DscResource -ModuleName 'ActiveDirectoryDsc' + + node $AllNodes.NodeName + { + ADDomainControllerProperties 'Integration_Test' + { + IsSingleInstance = 'Yes' + ContentFreshness = 100 + } + } +} + +<# + .SYNOPSIS + Restore domain controller properties to the default values. +#> +Configuration MSFT_ADDomainControllerProperties_RestoreDefaultValues_Config +{ + Import-DscResource -ModuleName 'ActiveDirectoryDsc' + + node $AllNodes.NodeName + { + ADDomainControllerProperties 'Integration_Test' + { + IsSingleInstance = 'Yes' + ContentFreshness = 60 + } + } +} diff --git a/Tests/Unit/ActiveDirectory.Common.Tests.ps1 b/Tests/Unit/ActiveDirectory.Common.Tests.ps1 index e7dbcfd7f..568d768fb 100644 --- a/Tests/Unit/ActiveDirectory.Common.Tests.ps1 +++ b/Tests/Unit/ActiveDirectory.Common.Tests.ps1 @@ -1676,6 +1676,15 @@ InModuleScope 'ActiveDirectoryDsc.Common' { Test-DscPropertyState -Values $mockValues | Should -BeFalse } + + It 'Should return true when two strings are equal' { + $mockValues = @{ + CurrentValue = [System.String] 'Something' + DesiredValue = [System.String] 'Something' + } + + Test-DscPropertyState -Values $mockValues | Should -Be $true + } } Context 'When comparing integers' { @@ -1688,6 +1697,33 @@ InModuleScope 'ActiveDirectoryDsc.Common' { Test-DscPropertyState -Values $mockValues | Should -BeFalse } + It 'Should return true when the values are the same for [System.Int32]' { + $mockValues = @{ + CurrentValue = [System.Int32] 2 + DesiredValue = [System.Int32] 2 + } + + Test-DscPropertyState -Values $mockValues | Should -Be $true + } + + It 'Should return false when a value is different for [System.UInt32]' { + $mockValues = @{ + CurrentValue = [System.UInt32] 1 + DesiredValue = [System.UInt32] 2 + } + + Test-DscPropertyState -Values $mockValues | Should -Be $false + } + + It 'Should return true when the values are the same for [System.UInt32]' { + $mockValues = @{ + CurrentValue = [System.UInt32] 2 + DesiredValue = [System.UInt32] 2 + } + + Test-DscPropertyState -Values $mockValues | Should -Be $true + } + It 'Should return false when a value is different for [System.Int16]' { $mockValues = @{ CurrentValue = [System.Int16] 1 @@ -1697,6 +1733,15 @@ InModuleScope 'ActiveDirectoryDsc.Common' { Test-DscPropertyState -Values $mockValues | Should -BeFalse } + It 'Should return true when the values are the same for [System.Int16]' { + $mockValues = @{ + CurrentValue = [System.Int16] 2 + DesiredValue = [System.Int16] 2 + } + + Test-DscPropertyState -Values $mockValues | Should -Be $true + } + It 'Should return false when a value is different for [System.UInt16]' { $mockValues = @{ CurrentValue = [System.UInt16] 1 @@ -1706,6 +1751,15 @@ InModuleScope 'ActiveDirectoryDsc.Common' { Test-DscPropertyState -Values $mockValues | Should -BeFalse } + It 'Should return true when the values are the same for [System.UInt16]' { + $mockValues = @{ + CurrentValue = [System.UInt16] 2 + DesiredValue = [System.UInt16] 2 + } + + Test-DscPropertyState -Values $mockValues | Should -Be $true + } + It 'Should return false when a Integer value is missing' { $mockValues = @{ CurrentValue = $null diff --git a/Tests/Unit/MSFT_ADDomainControllerProperties.Tests.ps1 b/Tests/Unit/MSFT_ADDomainControllerProperties.Tests.ps1 new file mode 100644 index 000000000..2e22143ca --- /dev/null +++ b/Tests/Unit/MSFT_ADDomainControllerProperties.Tests.ps1 @@ -0,0 +1,235 @@ +$script:dscModuleName = 'ActiveDirectoryDsc' +$script:dscResourceName = 'MSFT_ADDomainControllerProperties' + +#region HEADER + +# Unit Test Template Version: 1.2.4 +$script:moduleRoot = Split-Path -Parent (Split-Path -Parent $PSScriptRoot) +if ( (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests'))) -or ` + (-not (Test-Path -Path (Join-Path -Path $script:moduleRoot -ChildPath 'DSCResource.Tests\TestHelper.psm1'))) ) +{ + & git @('clone', 'https://github.com/PowerShell/DscResource.Tests.git', (Join-Path -Path $script:moduleRoot -ChildPath 'DscResource.Tests')) +} + +Import-Module -Name (Join-Path -Path $script:moduleRoot -ChildPath (Join-Path -Path 'DSCResource.Tests' -ChildPath 'TestHelper.psm1')) -Force + +# TODO: Insert the correct and for your resource +$TestEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType Unit + +#endregion HEADER + +function Invoke-TestSetup +{ +} + +function Invoke-TestCleanup +{ + Restore-TestEnvironment -TestEnvironment $TestEnvironment +} + +# Begin Testing +try +{ + Invoke-TestSetup + + InModuleScope $script:dscResourceName { + $mockDefaultParameters = @{ + IsSingleInstance = 'Yes' + Verbose = $true + } + + Describe 'MSFT_ADDomainControllerProperties\Get-TargetResource' -Tag 'Get' { + Context 'When the current property values are returned' { + BeforeAll { + Mock -CommandName Get-CimInstance -MockWith { + return @{ + MaxOfflineTimeInDays = 60 + } + } + } + + It 'Should return the correct values' { + $getTargetResourceResult = Get-TargetResource @mockDefaultParameters + $getTargetResourceResult.IsSingleInstance | Should -Be $mockDefaultParameters.IsSingleInstance + $getTargetResourceResult.ContentFreshness | Should -Be 60 + + Assert-MockCalled -CommandName Get-CimInstance -Exactly -Times 1 -Scope It + } + } + } + + Describe 'MSFT_ADDomainControllerProperties\Test-TargetResource' -Tag 'Test' { + Context 'When the system is in the desired state' { + Context 'When the property ContentFreshness is in desired state' { + BeforeAll { + Mock -CommandName Compare-TargetResourceState -MockWith { + return @( + @{ + ParameterName = 'ContentFreshness' + InDesiredState = $true + } + ) + } + + $testTargetResourceParameters = $mockDefaultParameters.Clone() + $testTargetResourceParameters['ContentFreshness'] = 60 + } + + It 'Should return $true' { + $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + $testTargetResourceResult | Should -BeTrue + + Assert-MockCalled -CommandName Compare-TargetResourceState -Exactly -Times 1 -Scope It + } + } + } + + Context 'When the system is not in the desired state' { + Context 'When the property ContentFreshness is not in desired state' { + BeforeAll { + Mock -CommandName Compare-TargetResourceState -MockWith { + return @( + @{ + ParameterName = 'ContentFreshness' + InDesiredState = $false + } + ) + } + + $testTargetResourceParameters = $mockDefaultParameters.Clone() + $testTargetResourceParameters['ContentFreshness'] = 100 + } + + It 'Should return $false' { + $testTargetResourceResult = Test-TargetResource @testTargetResourceParameters + $testTargetResourceResult | Should -BeFalse + + Assert-MockCalled -CommandName Compare-TargetResourceState -Exactly -Times 1 -Scope It + } + } + } + } + + Describe 'MSFT_ADDomainControllerProperties\Compare-TargetResourceState' -Tag 'Compare' { + Context 'When the system is in the desired state' { + Context 'When the property ContentFreshness is in desired state' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + IsSingleInstance = 'Yes' + ContentFreshness = 60 + } + } + + $compareTargetResourceStateParameters = $mockDefaultParameters.Clone() + $compareTargetResourceStateParameters['ContentFreshness'] = 60 + } + + It 'Should return $true' { + $compareTargetResourceStateResult = Compare-TargetResourceState @compareTargetResourceStateParameters + $compareTargetResourceStateResult | Should -HaveCount 1 + + $comparedReturnValue = $compareTargetResourceStateResult.Where( { $_.ParameterName -eq 'ContentFreshness' }) + $comparedReturnValue | Should -Not -BeNullOrEmpty + $comparedReturnValue.Expected | Should -Be 60 + $comparedReturnValue.Actual | Should -Be 60 + $comparedReturnValue.InDesiredState | Should -BeTrue + + Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It + } + } + } + + Context 'When the system is not in the desired state' { + Context 'When the property ContentFreshness is not in desired state' { + BeforeAll { + Mock -CommandName Get-TargetResource -MockWith { + return @{ + IsSingleInstance = 'Yes' + ContentFreshness = 60 + } + } + + $compareTargetResourceStateParameters = $mockDefaultParameters.Clone() + $compareTargetResourceStateParameters['ContentFreshness'] = 100 + } + + It 'Should return $false' { + $compareTargetResourceStateResult = Compare-TargetResourceState @compareTargetResourceStateParameters + $compareTargetResourceStateResult | Should -HaveCount 1 + + $comparedReturnValue = $compareTargetResourceStateResult.Where( { $_.ParameterName -eq 'ContentFreshness' }) + $comparedReturnValue | Should -Not -BeNullOrEmpty + $comparedReturnValue.Expected | Should -Be 100 + $comparedReturnValue.Actual | Should -Be 60 + $comparedReturnValue.InDesiredState | Should -BeFalse + + Assert-MockCalled -CommandName Get-TargetResource -Exactly -Times 1 -Scope It + } + } + } + } + + Describe 'MSFT_ADDomainControllerProperties\Set-TargetResource' -Tag 'Set' { + Context 'When the system is in the desired state' { + Context 'When the property ContentFreshness is in desired state' { + BeforeAll { + Mock -CommandName Set-CimInstance + Mock -CommandName Compare-TargetResourceState -MockWith { + return @( + @{ + ParameterName = 'ContentFreshness' + InDesiredState = $true + } + ) + } + + $setTargetResourceParameters = $mockDefaultParameters.Clone() + $setTargetResourceParameters['ContentFreshness'] = 60 + } + + It 'Should not throw and do not call Set-CimInstance' { + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + + Assert-MockCalled -CommandName Compare-TargetResourceState -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Set-CimInstance -Exactly -Times 0 -Scope It + } + } + } + + Context 'When the system is not in the desired state' { + Context 'When the property ContentFreshness is not in desired state' { + BeforeAll { + Mock -CommandName Set-CimInstance + Mock -CommandName Compare-TargetResourceState -MockWith { + return @( + @{ + ParameterName = 'ContentFreshness' + InDesiredState = $false + } + ) + } + + $setTargetResourceParameters = $mockDefaultParameters.Clone() + $setTargetResourceParameters['ContentFreshness'] = 100 + } + + It 'Should not throw and call the correct mocks' { + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + + Assert-MockCalled -CommandName Compare-TargetResourceState -Exactly -Times 1 -Scope It + Assert-MockCalled -CommandName Set-CimInstance -Exactly -Times 1 -Scope It + } + } + } + } + } +} +finally +{ + Invoke-TestCleanup +}