diff --git a/.vscode/settings.json b/.vscode/settings.json index f8efa40..6d73575 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -36,7 +36,9 @@ "keepachangelog", "notin", "pscmdlet", - "steppable" + "steppable", + "Serverv", + "Dhcpv" ], "cSpell.ignorePaths": [ ".git" diff --git a/CHANGELOG.md b/CHANGELOG.md index a7170e1..7b9674a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Unit tests for `DhcpServerDsc.OptionValueHelper` - Unit tests for `DSC_xDhcpServerReservation` +- Resource `DhcpServerv4DnsDynamicUpdates`. Fixes [#65](https://github.com/dsccommunity/DhcpServerDsc/issues/65) ## [4.0.0] - 2025-01-20 diff --git a/RequiredModules.psd1 b/RequiredModules.psd1 index 7f54f00..38f3588 100644 --- a/RequiredModules.psd1 +++ b/RequiredModules.psd1 @@ -27,12 +27,18 @@ # Build dependent modules 'DscResource.Common' = 'latest' + 'DscResource.Base' = 'latest' # Analyzer rules 'DscResource.AnalyzerRules' = 'latest' 'Indented.ScriptAnalyzerRules' = 'latest' # Prerequisite modules for documentation. - 'DscResource.DocGenerator' = 'latest' + 'DscResource.DocGenerator' = @{ + Version = 'latest' + Parameters = @{ + AllowPrerelease = $true + } + } PlatyPS = 'latest' } diff --git a/build.yaml b/build.yaml index e55a211..0bf24ed 100644 --- a/build.yaml +++ b/build.yaml @@ -6,6 +6,8 @@ CopyPaths: - en-US - DSCResources + - Modules +Prefix: prefix.ps1 Encoding: UTF8 VersionedOutputDirectory: true BuiltModuleSubdirectory: builtModule @@ -20,6 +22,11 @@ NestedModule: Path: ./output/RequiredModules/DscResource.Common AddToManifest: false Exclude: PSGetModuleInfo.xml + DscResource.Base: + CopyOnly: true + Path: ./output/RequiredModules/DscResource.Base + AddToManifest: false + Exclude: PSGetModuleInfo.xml DhcpServerDsc.Common: Prefix: prefix.ps1 VersionedOutputDirectory: false @@ -102,6 +109,7 @@ Pester: OutputEncoding: ascii ExcludeFromCodeCoverage: - Modules/DscResource.Common + - Modules/DscResource.Base CodeCoverage: CodeCoverageMergedOutputFile: CodeCov_Merged.xml @@ -112,7 +120,7 @@ DscTest: Configuration: Filter: ExcludeTag: - - "Common Tests - New Error-Level Script Analyzer Rules" + - 'Common Tests - New Error-Level Script Analyzer Rules' Output: Verbosity: Detailed CIFormat: Auto @@ -126,6 +134,7 @@ DscTest: - output ExcludeModuleFile: - Modules/DscResource.Common + - Modules/DscResource.Base # Must exclude built module file because it should not be tested like MOF-based resources - DhcpServerDsc.psm1 MainGitBranch: main diff --git a/source/Classes/001.DhcpServerReason.ps1 b/source/Classes/001.DhcpServerReason.ps1 new file mode 100644 index 0000000..88f17b7 --- /dev/null +++ b/source/Classes/001.DhcpServerReason.ps1 @@ -0,0 +1,21 @@ +<# + .SYNOPSIS + The reason a property of a DSC resource is not in desired state. + + .DESCRIPTION + A DSC resource can have a read-only property `Reasons` that the compliance + part (audit via Azure Policy) of Azure AutoManage Machine Configuration + uses. The property Reasons holds an array of DhcpServerReason. Each DhcpServerReason + explains why a property of a DSC resource is not in desired state. +#> + +class DhcpServerReason +{ + [DscProperty()] + [System.String] + $Code + + [DscProperty()] + [System.String] + $Phrase +} diff --git a/source/Classes/010.DhcpServerDnsDynamicUpdatesBase.ps1 b/source/Classes/010.DhcpServerDnsDynamicUpdatesBase.ps1 new file mode 100644 index 0000000..bfc5201 --- /dev/null +++ b/source/Classes/010.DhcpServerDnsDynamicUpdatesBase.ps1 @@ -0,0 +1,42 @@ +<# + .SYNOPSIS + A class with DSC properties that are used in multiple child classes. + + .DESCRIPTION + A class with DSC properties that are used in multiple child classes. + + .PARAMETER Reasons + Returns the reason a property is not in desired state. +#> + +class DhcpServerDnsDynamicUpdatesBase : ResourceBase +{ + [DscProperty(Mandatory)] + [Ensure] + $Ensure = [Ensure]::Present + + [DscProperty()] + [System.Nullable[System.Boolean]] + $NameProtection + + [DscProperty()] + [System.Nullable[System.Boolean]] + $DeleteDnsRROnLeaseExpiry + + [DscProperty()] + [DynamicUpdatesType] + $DynamicUpdates + + [DscProperty()] + [System.String] + $IPAddress + + [DscProperty(NotConfigurable)] + [DhcpServerReason[]] + $Reasons + + DhcpServerDnsDynamicUpdatesBase () : base ($PSScriptRoot) + { + $this.FeatureOptionalEnums = $true + } +} diff --git a/source/Classes/020.DhcpServerv4DnsDynamicUpdates.ps1 b/source/Classes/020.DhcpServerv4DnsDynamicUpdates.ps1 new file mode 100644 index 0000000..d2729ec --- /dev/null +++ b/source/Classes/020.DhcpServerv4DnsDynamicUpdates.ps1 @@ -0,0 +1,397 @@ +<# + .SYNOPSIS + The `DhcpServerv4DnsDynamicUpdates` DSC resource is used to create, modify or remove + IPv4 DnsDynamicUpdates on a Dhcp Server, ServerPolicy, Scope, ScopePolicy or Reservation. + + .DESCRIPTION + This resource is used to create, edit or remove DnsDynamicUpdate settings on DhcpServers. + + .PARAMETER TargetScope + The target scope type of the operation. + + .PARAMETER Ensure + Specifies whether the configuration should exist. + + .PARAMETER NameProtection + Specifies whether Name Protection is enabled. + + .PARAMETER DeleteDnsRROnLeaseExpiry + Whether the setting to discard A and PTR records when a lease is deleted. + + .PARAMETER DynamicUpdates + The dynamic update mode, this can be Always, Never or OnClientRequest. + + .PARAMETER DisableDnsPtrRRUpdate + + + .PARAMETER UpdateDnsRRForOlderClients + + + .PARAMETER IPAddress + The IpAddress to target. This is only applicable to Reservation TargetScope. + + .PARAMETER ScopeId + The scope Id to target. This is only applicable to Scope and ScopePolicy TargetScope. + + .PARAMETER PolicyName + The name of the policy to target. This is only applicable to ServerPolicy and ScopePolicy TargetScope. + + .PARAMETER DnsSuffix + The DNS Suffix to register DHCP clients to. This is only applicable to ServerPolicy and ScopePolicy TargetScope. +#> + +[DscResource()] +class DhcpServerv4DnsDynamicUpdates : DhcpServerDnsDynamicUpdatesBase +{ + [DscProperty(Key)] + [Dhcpv4TargetScopeType] + $TargetScope + + [DscProperty()] + [System.Nullable[System.Boolean]] + $UpdateDnsRRForOlderClients + + [DscProperty()] + [System.String] + $ScopeId + + [DscProperty()] + [System.String] + $PolicyName + + [DscProperty()] + [System.Nullable[System.Boolean]] + $DisableDnsPtrRRUpdate + + [DscProperty()] + [System.String] + $DnsSuffix + + DhcpServerv4DnsDynamicUpdates () : base () + { + } + + # Required DSC Methods, these call the method in the base class. + [DhcpServerv4DnsDynamicUpdates] Get() + { + # Call the base method to return the properties. + return ([ResourceBase] $this).Get() + } + + [void] Set() + { + # Call the base method to enforce the properties. + ([ResourceBase] $this).Set() + } + + [System.Boolean] Test() + { + # Call the base method to test all of the properties that should be enforced. + return ([ResourceBase] $this).Test() + } + + # Base method Get() call this method to get the current state as a Hashtable. + [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties) + { + $state = @{} + $getParameters = @{} + + #TODO: Make this stop outputting 'loading module' + $SavedVerbosePreference = $global:VerbosePreference + $SavedOutputPreference = $global:OutputPreference + $global:VerbosePreference = $global:OutputPreference = 'SilentlyContinue' + $null = Import-Module 'DhcpServer' + $global:VerbosePreference = $SavedVerbosePreference + $global:OutputPreference = $SavedOutputPreference + + switch ($properties.TargetScope) + { + ServerPolicy + { + # Need to check the Policy exists + $policy = Get-DhcpServerv4Policy -Name $this.PolicyName -ErrorAction SilentlyContinue + + if ($null -eq $policy) + { + New-InvalidOperationException -Message ($this.localizedData.ServerPolicyDoesNotExist -f $this.PolicyName) + } + + $getParameters.PolicyName = $this.PolicyName + break + } + + Scope + { + # Need to check the Scope exists + $scope = Get-DhcpServerv4Scope -ScopeId $this.ScopeId -ErrorAction SilentlyContinue + + if ($null -eq $scope) + { + New-InvalidOperationException -Message ($this.localizedData.ScopeDoesNotExist -f $this.ScopeId) + } + + $getParameters.ScopeId = $this.ScopeId + break + } + + ScopePolicy + { + # Need to check the ScopePolicy exists + $scope = Get-DhcpServerv4Scope -ScopeId $this.ScopeId -ErrorAction SilentlyContinue + + if ($null -eq $scope) + { + New-InvalidOperationException -Message ($this.localizedData.ScopeDoesNotExist -f $this.ScopeId) + } + + $policy = Get-DhcpServerv4Policy -Name $this.PolicyName -ScopeId $scope.ScopeId -ErrorAction SilentlyContinue + + if ($null -eq $policy) + { + New-InvalidOperationException -Message ($this.localizedData.ScopePolicyDoesNotExist -f $this.ScopeId, $this.PolicyName) + } + + $getParameters.ScopeId = $this.ScopeId + $getParameters.PolicyName = $this.PolicyName + break + } + + Reservation + { + # Need to check the reservation exists + $reservation = Get-DhcpServerv4Reservation -IPAddress $this.IPAddress -ErrorAction SilentlyContinue + + if ($null -eq $reservation) + { + New-InvalidOperationException -Message ($this.localizedData.ReservationDoesNotExist -f $this.IPAddress) + } + + $getParameters.IPAddress = $this.IPAddress + break + } + } + + $getCurrentStateResult = Get-DhcpServerv4DnsSetting @getParameters + + if ($getCurrentStateResult) + { + $state = @{ + TargetScope = [Dhcpv4TargetScopeType] $properties.TargetScope + DeleteDnsRROnLeaseExpiry = $getCurrentStateResult.DeleteDnsRROnLeaseExpiry + DisableDnsPtrRRUpdate = $getCurrentStateResult.DisableDnsPtrRRUpdate + DnsSuffix = $getCurrentStateResult.DnsSuffix + DynamicUpdates = [DynamicUpdatesType] $getCurrentStateResult.DynamicUpdates + NameProtection = $getCurrentStateResult.NameProtection + UpdateDnsRRForOlderClients = $getCurrentStateResult.UpdateDnsRRForOlderClients + } + + switch ($properties.TargetScope) + { + ServerPolicy + { + $state.PolicyName = $this.PolicyName + break + } + + Scope + { + $state.ScopeId = $this.ScopeId + break + } + + ScopePolicy + { + $state.ScopeId = $this.ScopeId + $state.PolicyName = $this.PolicyName + break + } + + Reservation + { + $state.IPAddress = $this.IPAddress + break + } + } + } + + return $state + } + + <# + Base method Set() call this method with the properties that should be + enforced and that are not in desired state. + #> + hidden [void] Modify([System.Collections.Hashtable] $properties) + { + $setParams = @{} + + switch ($this.TargetScope) + { + ServerPolicy + { + $setParams.PolicyName = $this.PolicyName + break + } + + Scope + { + $setParams.ScopeId = $this.ScopeId + break + } + + ScopePolicy + { + $setParams.ScopeId = $this.ScopeId + $setParams.PolicyName = $this.PolicyName + break + } + + Reservation + { + $setParams.IPAddress = $this.IPAddress + break + } + } + + Set-DhcpServerv4DnsSetting @setParams @properties + } + + <# + Base method Assert() call this method with the properties that was assigned + a value. + #> + hidden [void] AssertProperties([System.Collections.Hashtable] $properties) + { + Assert-Module -ModuleName 'DHCPServer' + + # Test at least one of the following exists + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'DeleteDnsRROnLeaseExpiry' + 'DynamicUpdates' + 'NameProtection' + 'UpdateDnsRRForOlderClients' + 'DnsSuffix' + 'DisableDnsPtrRRUpdate' + ) + RequiredBehavior = 'Any' + } + + Assert-BoundParameter @assertBoundParameterParameters + + # Scopes + switch ($properties.TargetScope) + { + Server + { + $disallowedParameters = @( + 'ScopeId' + 'IPAddress' + 'PolicyName' + 'DnsSuffix' + ) + + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + MutuallyExclusiveList1 = 'TargetScope' + MutuallyExclusiveList2 = $disallowedParameters + } + + Assert-BoundParameter @assertBoundParameterParameters + break + } + + ServerPolicy + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'PolicyName' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + break + } + + Scope + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'ScopeId' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + + $disallowedParameters = @( + 'DnsSuffix' + ) + + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + MutuallyExclusiveList1 = 'TargetScope' + MutuallyExclusiveList2 = $disallowedParameters + } + + Assert-BoundParameter @assertBoundParameterParameters + break + } + + ScopePolicy + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'ScopeId' + 'PolicyName' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + break + } + + Reservation + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'IPAddress' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + + $disallowedParameters = @( + 'DnsSuffix' + 'NameProtection' + ) + + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + MutuallyExclusiveList1 = 'TargetScope' + MutuallyExclusiveList2 = $disallowedParameters + } + + Assert-BoundParameter @assertBoundParameterParameters + break + } + } + + foreach ($ipString in @('IPAddress', 'ScopeId')) + { + if ($properties.ContainsKey($ipString)) + { + $getValidIpAddressParams = @{ + Address = $properties.$ipString + AddressFamily = 'IPv4' + } + + Assert-IPAddress @getValidIpAddressParams + } + } + } +} diff --git a/source/Classes/020.DhcpServerv6DnsDynamicUpdates.ps1 b/source/Classes/020.DhcpServerv6DnsDynamicUpdates.ps1 new file mode 100644 index 0000000..1bbc253 --- /dev/null +++ b/source/Classes/020.DhcpServerv6DnsDynamicUpdates.ps1 @@ -0,0 +1,157 @@ +<# + .SYNOPSIS + The `DhcpServerv6DnsDynamicUpdates` DSC resource is used to create, modify or remove + IPv6 DnsDynamicUpdates on a Dhcp Server, ServerPolicy, Scope, ScopePolicy or Reservation. + + .DESCRIPTION + This resource is used to create, edit or remove DnsDynamicUpdate settings on DhcpServers. + + .PARAMETER TargetScope + The target scope type of the operation. + + .PARAMETER Ensure + Specifies whether the configuration should exist. + + .PARAMETER NameProtection + + + .PARAMETER DeleteDnsRROnLeaseExpiry + + + .PARAMETER DynamicUpdates + + + .PARAMETER IPAddress + + + .PARAMETER Prefix + + .PARAMETER Reasons + Returns the reason a property is not in desired state. +#> + +[DscResource()] +class DhcpServerv6DnsDynamicUpdates : DhcpServerDnsDynamicUpdatesBase +{ + [DscProperty(Key)] + [Dhcpv6TargetScopeType] + $TargetScope + + [DscProperty()] + [System.String] + $Prefix + + DhcpServerv6DnsDynamicUpdates () : base () + { + $this.ExcludeDscProperties = @() + } + + # Required DSC Methods, these call the method in the base class. + [DhcpServerv6DnsDynamicUpdates] Get() + { + # Call the base method to return the properties. + return ([ResourceBase] $this).Get() + } + + [void] Set() + { + # Call the base method to enforce the properties. + ([ResourceBase] $this).Set() + } + + [System.Boolean] Test() + { + # Call the base method to test all of the properties that should be enforced. + return ([ResourceBase] $this).Test() + } + + # Base method Get() call this method to get the current state as a Hashtable. + [System.Collections.Hashtable] GetCurrentState([System.Collections.Hashtable] $properties) + { + return @{} + } + + <# + Base method Set() call this method with the properties that should be + enforced and that are not in desired state. + #> + hidden [void] Modify([System.Collections.Hashtable] $properties) + { + } + + <# + Base method Assert() call this method with the properties that was assigned + a value. + #> + hidden [void] AssertProperties([System.Collections.Hashtable] $properties) + { + Assert-Module -ModuleName 'DHCPServer' + + # Test at least one of the following exists + $mustHaveOne = @( + 'DeleteDnsRROnLeaseExpiry' + 'DynamicUpdates' + 'NameProtection' + ) + + $optionalProperties = $properties.Keys.Where({ $_ -in $mustHaveOne }) + + if (-not $optionalProperties) + { + $errorMessage = $this.localizedData.SpecificParametersOneMustBeSet -f ($mustHaveOne -join ''', ''') + + $PSCmdlet.ThrowTerminatingError( + [System.Management.Automation.ErrorRecord]::new( + $errorMessage, + 'DS6DDU0001', # cspell: disable-line + [System.Management.Automation.ErrorCategory]::InvalidOperation, + 'Required optional parameters' + ) + ) + } + + # Scopes + switch ($properties.TargetScope) + { + Server + { + $disallowedParameters = @( + 'Prefix' + 'IPAddress' + ) + + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + MutuallyExclusiveList1 = $disallowedParameters + MutuallyExclusiveList2 = $disallowedParameters + } + + Assert-BoundParameter @assertBoundParameterParameters + } + + Scope + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'Prefix' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + } + + Reservation + { + $assertBoundParameterParameters = @{ + BoundParameterList = $properties + RequiredParameter = @( + 'IPAddress' + ) + } + + Assert-BoundParameter @assertBoundParameterParameters + } + } + } +} diff --git a/source/DhcpServerDsc.psm1 b/source/DhcpServerDsc.psm1 deleted file mode 100644 index 81d556e..0000000 --- a/source/DhcpServerDsc.psm1 +++ /dev/null @@ -1,4 +0,0 @@ -<# - This file is intentionally left empty. It is must be left here for the module - manifest to refer to. It is recreated during the build process. -#> diff --git a/source/Enum/Dhcpv4TargetScopeType.ps1 b/source/Enum/Dhcpv4TargetScopeType.ps1 new file mode 100644 index 0000000..a4f4d39 --- /dev/null +++ b/source/Enum/Dhcpv4TargetScopeType.ps1 @@ -0,0 +1,8 @@ +enum Dhcpv4TargetScopeType +{ + Server = 1 + ServerPolicy + Scope + ScopePolicy + Reservation +} diff --git a/source/Enum/Dhcpv6TargetScopeType.ps1 b/source/Enum/Dhcpv6TargetScopeType.ps1 new file mode 100644 index 0000000..9760fcd --- /dev/null +++ b/source/Enum/Dhcpv6TargetScopeType.ps1 @@ -0,0 +1,6 @@ +enum Dhcpv6TargetScopeType +{ + Server = 1 + Scope + Reservation +} diff --git a/source/Enum/DynamicUpdatesType.ps1 b/source/Enum/DynamicUpdatesType.ps1 new file mode 100644 index 0000000..e6438ba --- /dev/null +++ b/source/Enum/DynamicUpdatesType.ps1 @@ -0,0 +1,6 @@ +enum DynamicUpdatesType +{ + Always = 1 + Never + OnClientRequest +} diff --git a/source/en-US/DhcpServerDnsDynamicUpdatesBase.strings.psd1 b/source/en-US/DhcpServerDnsDynamicUpdatesBase.strings.psd1 new file mode 100644 index 0000000..f056c5b --- /dev/null +++ b/source/en-US/DhcpServerDnsDynamicUpdatesBase.strings.psd1 @@ -0,0 +1,10 @@ +<# + .SYNOPSIS + The localized resource strings in English (en-US) for the + resource DhcpServerDnsDynamicUpdatesBase base class. This file should only contain + localized strings for private functions, public command, and + classes (that are not a DSC resource). +#> + +ConvertFrom-StringData @' +'@ diff --git a/source/en-US/DhcpServerv4DnsDynamicUpdates.strings.psd1 b/source/en-US/DhcpServerv4DnsDynamicUpdates.strings.psd1 new file mode 100644 index 0000000..09b6e00 --- /dev/null +++ b/source/en-US/DhcpServerv4DnsDynamicUpdates.strings.psd1 @@ -0,0 +1,18 @@ +<# + .SYNOPSIS + The localized resource strings in English (en-US) for the + resource DhcpServerDnsDynamicUpdates module. This file should only contain + localized strings for private functions, public command, and + classes (that are not a DSC resource). +#> + +ConvertFrom-StringData @' + ## Strings overrides for the ResourceBase's default strings. + # None + + ## Strings directly used by the derived class DhcpServerv4DnsDynamicUpdates. + ServerPolicyDoesNotExist = The Server Policy '{0}' does not exist. (DS4DDU0001) + ScopeDoesNotExist = The Scope '{0}' does not exist. (DS4DDU0002) + ScopePolicyDoesNotExist = The Scope Policy '{0}', '{1}' does not exist. (DS4DDU0003) + ReservationDoesNotExist = The Reservation '{0}' does not exist. (DS4DDU0004) +'@ diff --git a/source/en-US/DhcpServerv6DnsDynamicUpdates.strings.psd1 b/source/en-US/DhcpServerv6DnsDynamicUpdates.strings.psd1 new file mode 100644 index 0000000..51a0501 --- /dev/null +++ b/source/en-US/DhcpServerv6DnsDynamicUpdates.strings.psd1 @@ -0,0 +1,15 @@ +<# + .SYNOPSIS + The localized resource strings in English (en-US) for the + resource DhcpServerDnsDynamicUpdates module. This file should only contain + localized strings for private functions, public command, and + classes (that are not a DSC resource). +#> + +ConvertFrom-StringData @' + ## Strings overrides for the ResourceBase's default strings. + # None + + ## Strings directly used by the derived class WSManListener. + SpecificParametersOneMustBeSet = At least one of the parameters '{0}' must be specified. (DS4DDU0001). +'@ diff --git a/source/prefix.ps1 b/source/prefix.ps1 new file mode 100644 index 0000000..168dd74 --- /dev/null +++ b/source/prefix.ps1 @@ -0,0 +1,7 @@ +using module .\Modules\DscResource.Base + +# Import nested, 'DscResource.Common' module +$script:dscResourceCommonModulePath = Join-Path -Path $PSScriptRoot -ChildPath 'Modules\DscResource.Common' +Import-Module -Name $script:dscResourceCommonModulePath + +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' diff --git a/tests/Unit/Classes/DhcpServerDnsDynamicUpdatesBase.Tests.ps1 b/tests/Unit/Classes/DhcpServerDnsDynamicUpdatesBase.Tests.ps1 new file mode 100644 index 0000000..ece395b --- /dev/null +++ b/tests/Unit/Classes/DhcpServerDnsDynamicUpdatesBase.Tests.ps1 @@ -0,0 +1,79 @@ +<# + .SYNOPSIS + Unit test for DhcpServerDnsDynamicUpdatesBase base class. +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[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:dscModuleName = 'DhcpServerDsc' + + 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 'DhcpServerDnsDynamicUpdatesBase' { + Context 'When class is instantiated' { + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { [DhcpServerDnsDynamicUpdatesBase]::new() } | Should -Not -Throw + } + } + + It 'Should have a default or empty constructor' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $instance = [DhcpServerDnsDynamicUpdatesBase]::new() + $instance | Should -Not -BeNullOrEmpty + } + } + + It 'Should be the correct type' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $instance = [DhcpServerDnsDynamicUpdatesBase]::new() + $instance.GetType().Name | Should -Be 'DhcpServerDnsDynamicUpdatesBase' + } + } + } +} diff --git a/tests/Unit/Classes/DhcpServerv4DnsDynamicUpdates.Tests.ps1 b/tests/Unit/Classes/DhcpServerv4DnsDynamicUpdates.Tests.ps1 new file mode 100644 index 0000000..ee43c96 --- /dev/null +++ b/tests/Unit/Classes/DhcpServerv4DnsDynamicUpdates.Tests.ps1 @@ -0,0 +1,79 @@ +<# + .SYNOPSIS + Unit test for DhcpServerv4DnsDynamicUpdates DSC resource. +#> + +# Suppressing this rule because Script Analyzer does not understand Pester's syntax. +[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:dscModuleName = 'DhcpServerDsc' + + 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 'DhcpServerv4DnsDynamicUpdates' { + Context 'When class is instantiated' { + It 'Should not throw an exception' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + { [DhcpServerv4DnsDynamicUpdates]::new() } | Should -Not -Throw + } + } + + It 'Should have a default or empty constructor' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $instance = [DhcpServerv4DnsDynamicUpdates]::new() + $instance | Should -Not -BeNullOrEmpty + } + } + + It 'Should be the correct type' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $instance = [DhcpServerv4DnsDynamicUpdates]::new() + $instance.GetType().Name | Should -Be 'DhcpServerv4DnsDynamicUpdates' + } + } + } +}