diff --git a/CHANGELOG.md b/CHANGELOG.md index d683a386..48e8e3e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +- Added the following resources: + - **DnsClientNrptGlobal**: Configure DNS Client global Name Resolution Policy Table (NRPT) settings. + - **DnsClientNrptRule**: Sets a DNS Client NRPT rule on a node. + - Updated CHANGELOG.md - Renamed NetworkingDSc to NetworkingDsc in CHANGELOG.md - fixes [Issue #513](https://github.com/dsccommunity/NetworkingDsc/issues/513). - CI Pipeline diff --git a/README.md b/README.md index fb2129bd..a01c3905 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,8 @@ The **NetworkingDsc** module contains the following resources: - **DefaultGatewayAddress**: Sets a node's default gateway address. - **DnsClientGlobalSetting**: Configure DNS client global settings. +- **DnsClientNrptGlobal**: Configure DNS client global Name Resolution Policy Table (NRPT) settings. +- **DnsClientNrptRule**: Sets a DNS client NRPT rule on a node. - **DnsConnectionSuffix**: Sets a node's network interface connection-specific DNS suffix. - **DnsServerAddress**: Sets a node's DNS server address(s). diff --git a/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.data.psd1 b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.data.psd1 new file mode 100644 index 00000000..363e78e3 --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.data.psd1 @@ -0,0 +1,16 @@ +@{ + ParameterList = @( + @{ + Name = 'EnableDAForAllNetworks' + Type = 'String' + }, + @{ + Name = 'QueryPolicy' + Type = 'String' + }, + @{ + Name = 'SecureNameQueryFallback' + Type = 'String' + } + ) +} diff --git a/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.psm1 b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.psm1 new file mode 100644 index 00000000..66fb4373 --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.psm1 @@ -0,0 +1,229 @@ +$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' + +# Import the Networking Common Modules +Import-Module -Name (Join-Path -Path $modulePath ` + -ChildPath (Join-Path -Path 'NetworkingDsc.Common' ` + -ChildPath 'NetworkingDsc.Common.psm1')) + +Import-Module -Name (Join-Path -Path $modulePath -ChildPath 'DscResource.Common') + +# Import Localization Strings +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' + +<# + This is an array of all the parameters used by this resource. +#> +$resourceData = Import-LocalizedData ` + -BaseDirectory $PSScriptRoot ` + -FileName 'DSC_DnsClientNrptGlobal.data.psd1' + +# This must be a script parameter so that it is accessible +$script:parameterList = $resourceData.ParameterList + +<# + .SYNOPSIS + Returns the current DNS Client Nrpt Global Settings. + + .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 ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.GettingDnsClientNrptGlobalMessage) + ) -join '' ) + + # Get the current DNS Client Global Settings + $DnsClientNrptGlobal = Get-DnsClientNrptGlobal ` + -ErrorAction Stop + + # Generate the return object. + $returnValue = @{ + IsSingleInstance = 'Yes' + } + + foreach ($parameter in $script:parameterList) + { + $returnValue += @{ + $parameter.Name = $DnsClientNrptGlobal.$($parameter.name) + } + } # foreach + + return $returnValue +} # Get-TargetResource + +<# + .SYNOPSIS + Sets the DNS Client NRPT Global Settings. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + + .PARAMETER EnableDAForAllNetworks + Specifies DirectAccess (DA) settings. + + .PARAMETER QueryPolicy. + Specifies the DNS client query policy. + + .PARAMETER SecureNameQueryFallback + Specifies the DNS client name resolution fallback policy. +#> +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + + [Parameter()] + [ValidateSet('EnableOnNetworkID', 'EnableAlways', 'Disable', 'DisableDA')] + [System.String] + $EnableDAForAllNetworks, + + [Parameter()] + [System.String] + [ValidateSet('Disable', 'QueryIPv6Only', 'QueryBoth')] + $QueryPolicy, + + [Parameter()] + [System.String] + [ValidateSet('Disable', 'FallbackSecure', 'FallbackUnsecure', 'FallbackPrivate')] + $SecureNameQueryFallback + ) + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.SettingDnsClientNrptGlobalMessage) + ) -join '' ) + + # Get the current DNS Client Nrpt Global Settings + $DnsClientNrptGlobal = Get-DnsClientNrptGlobal ` + -ErrorAction Stop + + # Generate a list of parameters that will need to be changed. + $changeParameters = @{} + + foreach ($parameter in $script:parameterList) + { + $parameterSourceValue = $DnsClientNrptGlobal.$($parameter.name) + $parameterNewValue = (Get-Variable -Name ($parameter.name)).Value + + if ($PSBoundParameters.ContainsKey($parameter.Name) ` + -and (Compare-Object -ReferenceObject $parameterSourceValue -DifferenceObject $parameterNewValue -SyncWindow 0)) + { + $changeParameters += @{ + $($parameter.name) = $parameterNewValue + } + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.DnsClientNrptGlobalUpdateParameterMessage) ` + -f $parameter.Name,($parameterNewValue -join ',') + ) -join '' ) + } # if + } # foreach + + if ($changeParameters.Count -gt 0) + { + # Update any parameters that were identified as different + $null = Set-DnsClientNrptGlobal ` + @ChangeParameters ` + -ErrorAction Stop + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.DnsClientNrptGlobalUpdatedMessage) + ) -join '' ) + } # if +} # Set-TargetResource + +<# + .SYNOPSIS + Tests the state of DNS Client Nrpt Global Settings. + + .PARAMETER IsSingleInstance + Specifies the resource is a single instance, the value must be 'Yes'. + + .PARAMETER EnableDAForAllNetworks + Specifies DirectAccess (DA) settings. + + .PARAMETER QueryPolicy. + Specifies the DNS client query policy. + + .PARAMETER SecureNameQueryFallback + Specifies the DNS client name resolution fallback policy. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateSet('Yes')] + [System.String] + $IsSingleInstance, + + [Parameter()] + [ValidateSet('EnableOnNetworkID', 'EnableAlways', 'Disable', 'DisableDA')] + [System.String] + $EnableDAForAllNetworks, + + [Parameter()] + [System.String] + [ValidateSet('Disable', 'QueryIPv6Only', 'QueryBoth')] + $QueryPolicy, + + [Parameter()] + [System.String] + [ValidateSet('Disable', 'FallbackSecure', 'FallbackUnsecure', 'FallbackPrivate')] + $SecureNameQueryFallback + ) + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.TestingDnsClientNrptGlobalMessage) + ) -join '' ) + + # Flag to signal whether settings are correct + $desiredConfigurationMatch = $true + + # Get the current DNS Client Nrpt Global Settings + $DnsClientNrptGlobal = Get-DnsClientNrptGlobal ` + -ErrorAction Stop + + # Check each parameter + foreach ($parameter in $script:parameterList) + { + $parameterSourceValue = $DnsClientNrptGlobal.$($parameter.name) + $parameterNewValue = (Get-Variable -Name ($parameter.name)).Value + + if ($parameterNewValue -ne $parameterSourceValue) + { + Write-Verbose -Message ( @( "$($MyInvocation.MyCommand): " + $($script:localizedData.DnsClientNrptGlobalParameterNeedsUpdateMessage) ` + -f $parameter.Name, ($parameterSourceValue -join ','), ($parameterNewValue -join ',') + ) -join '') + $desiredConfigurationMatch = $false + } + + } # foreach + + return $desiredConfigurationMatch +} # Test-TargetResource + +Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.schema.mof b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.schema.mof new file mode 100644 index 00000000..c28c364f --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptGlobal/DSC_DnsClientNrptGlobal.schema.mof @@ -0,0 +1,8 @@ +[ClassVersion("1.0.0.0"), FriendlyName("DnsClientNrptGlobal")] +class DSC_DnsClientNrptGlobal : 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 DirectAccess (DA) settings."), ValueMap{"EnableOnNetworkID", "EnableAlways", "Disable", "DisableDA"},Values{"EnableOnNetworkID", "EnableAlways", "Disable", "DisableDA"}] string EnableDAForAllNetworks; + [Write, Description("Specifies the DNS client query policy."), ValueMap{"Disable", "QueryIPv6Only", "QueryBoth"},Values{"Disable", "QueryIPv6Only", "QueryBoth"}] string QueryPolicy; + [Write, Description("SecureNameQueryFallback."), ValueMap{"Disable", "FallbackSecure", "FallbackUnsecure", "FallbackPrivate"},Values{"Disable", "FallbackSecure", "FallbackUnsecure", "FallbackPrivate"}] string SecureNameQueryFallback; +}; diff --git a/source/DSCResources/DSC_DnsClientNrptGlobal/README.MD b/source/DSCResources/DSC_DnsClientNrptGlobal/README.MD new file mode 100644 index 00000000..354ca235 --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptGlobal/README.MD @@ -0,0 +1,3 @@ +# Description + +This resource is used to control DNS Client NRPT Global Settings for a node. diff --git a/source/DSCResources/DSC_DnsClientNrptGlobal/en-US/DSC_DnsClientNrptGlobal.strings.psd1 b/source/DSCResources/DSC_DnsClientNrptGlobal/en-US/DSC_DnsClientNrptGlobal.strings.psd1 new file mode 100644 index 00000000..7d1d1af7 --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptGlobal/en-US/DSC_DnsClientNrptGlobal.strings.psd1 @@ -0,0 +1,10 @@ +# Localized resources for DSC_DnsClientNrptGlobal + +ConvertFrom-StringData @' + GettingDnsClientNrptGlobalMessage = Getting DNS Client NRPT Global Settings. + SettingDnsClientNrptGlobalMessage = Setting DNS Client NRPT Global Settings. + DnsClientNrptGlobalUpdateParameterMessage = Setting DNS Client NRPT Global Settings parameter {0} to "{1}". + DnsClientNrptGlobalUpdatedMessage = Setting DNS Client NRPT Global Settings updated. + TestingDnsClientNrptGlobalMessage = Testing DNS Client NRPT Global Settings. + DnsClientNrptGlobalParameterNeedsUpdateMessage = DNS Client NRPT Global Setting "{0}" is "{1}" but should be "{2}". Change required. +'@ diff --git a/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.psm1 b/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.psm1 new file mode 100644 index 00000000..8a8d559e --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.psm1 @@ -0,0 +1,734 @@ +$modulePath = Join-Path -Path (Split-Path -Path (Split-Path -Path $PSScriptRoot -Parent) -Parent) -ChildPath 'Modules' + +# Import the Networking Common Modules +Import-Module -Name (Join-Path -Path $modulePath ` + -ChildPath (Join-Path -Path 'NetworkingDsc.Common' ` + -ChildPath 'NetworkingDsc.Common.psm1')) + +Import-Module -Name (Join-Path -Path $modulePath -ChildPath 'DscResource.Common') + +# Import Localization Strings +$script:localizedData = Get-LocalizedData -DefaultUICulture 'en-US' + +# This must be a script parameter so that it is accessible +$script:dnsPolicyConfigRegistryPath = 'HKLM:\SYSTEM\CurrentControlSet\Services\Dnscache\Parameters\DnsPolicyConfig' + +<# + .SYNOPSIS + Returns the current state of a DNS Client NRPT Rule. + + .PARAMETER Name + Specifies the name which uniquely identifies a rule. +#> +function Get-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Collections.Hashtable])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name + ) + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.GettingNrptRuleMessage) ` + -f $Name ` + ) -join '' ) + + # Lookup the existing NrptRule + $NrptRule = Get-NrptRule -Name $Name + + $returnValue = @{ + Name = $Name + } + + if ($NrptRule) + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleExistsMessage) ` + -f $Name ` + ) -join '' ) + + $returnValue += @{ + Ensure = 'Present' + Comment = [System.String] $NrptRule.Comment + DAEnable = [System.Boolean] $NrptRule.DAEnable + DAIPsecEncryptionType = [System.String] $NrptRule.DAIPsecEncryptionType + DAIPsecRequired = [System.Boolean] $NrptRule.DAIPsecRequired + DANameServers = [System.String[]] $NrptRule.DANameServers + DAProxyServerName = [System.String] $NrptRule.DAProxyServerName + DAProxyType = [System.String] $NrptRule.DAProxyType + DisplayName = [System.String] $NrptRule.DisplayName + DnsSecEnable = [System.Boolean] $NrptRule.DnsSecEnable + DnsSecIPsecEncryptionType = [System.String] $NrptRule.DnsSecIPsecEncryptionType + DnsSecIPsecRequired = [System.Boolean] $NrptRule.DnsSecIPsecRequired + DnsSecValidationRequired = [System.Boolean] $NrptRule.DnsSecValidationRequired + IPsecTrustAuthority = [System.String] $NrptRule.IPsecTrustAuthority + NameEncoding = [System.String] $NrptRule.NameEncoding + NameServers = [System.String[]] $NrptRule.NameServers + Namespace = [System.String] $NrptRule.Namespace + } + } + else + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleDoesNotExistMessage) ` + -f $Name ` + ) -join '' ) + + $returnValue += @{ + Ensure = 'Absent' + } + } + + return $returnValue +} # Get-TargetResource + +<# + .SYNOPSIS + Sets a NRPT Rule. + + .PARAMETER Name + Specifies the name which uniquely identifies a rule. + + .PARAMETER Comment + Stores administrator notes. + + .PARAMETER DAEnable + Indicates the rule state for DirectAccess. + + .PARAMETER DAIPsecEncryptionType + Specifies the Internet Protocol security (IPsec) encryption setting for DirectAccess. + + .PARAMETER DAIPsecRequired + Indicates that IPsec is required for DirectAccess. + + .PARAMETER DANameServers + Specifies an array of DNS servers to query when DirectAccess is enabled. + + .PARAMETER DAProxyServerName + "Specifies the proxy server to use when connecting to the Internet. + This parameter is only applicable if the DAProxyType parameter is set to UseProxyName. + + .PARAMETER DAProxyType + Specifies the proxy server type to be used when connecting to the Internet. + + .PARAMETER DisplayName + Specifies an optional friendly name for the NRPT rule. + + .PARAMETER DnsSecEnable + Enables Domain Name System Security Extensions (DNSSEC) on the rule. + + .PARAMETER DnsSecIPsecEncryptionType + Specifies the IPsec tunnel encryption setting. + + .PARAMETER DnsSecIPsecRequired + Indicates the DNS client must set up an IPsec connection to the DNS server. + + .PARAMETER DnsSecValidationRequired + Indicates that DNSSEC validation is required. + + .PARAMETER IPsecTrustAuthority + Specifies the certification authority to validate the IPsec channel. + + .PARAMETER NameEncoding + Specifies the encoding format for host names in the DNS query. + + .PARAMETER NameServers + Specifies the DNS servers to which the DNS query is sent when DirectAccess is disabled. + + .PARAMETER Namespace + Specifies the DNS namespace. +#> +function Set-TargetResource +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.String] + $Comment, + + [Parameter()] + [System.Boolean] + $DAEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DAIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DAIPsecRequired, + + [Parameter()] + [System.String[]] + $DANameServers, + + [Parameter()] + [System.String] + $DAProxyServerName, + + [Parameter()] + [ValidateSet('NoProxy', 'UseDefault', 'UseProxyName')] + [System.String] + $DAProxyType, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $DnsSecEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DnsSecIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DnsSecIPsecRequired, + + [Parameter()] + [System.Boolean] + $DnsSecValidationRequired, + + [Parameter()] + [System.String] + $IPsecTrustAuthority, + + [Parameter()] + [ValidateSet('Disable', 'Utf8WithMapping', 'Utf8WithoutMapping', 'Punycode')] + [System.String] + $NameEncoding, + + [Parameter()] + [System.String[]] + $NameServers, + + [Parameter()] + [System.String] + $Namespace + ) + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.SettingNrptRuleMessage) ` + -f $Name ` + ) -join '' ) + + # Remove any parameters that can't be splatted. + $null = $PSBoundParameters.Remove('Ensure') + + # Lookup the existing NrptRule + $NrptRule = Get-NrptRule -Name $Name + + if ($Ensure -eq 'Present') + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.EnsureNrptRuleExistsMessage) ` + -f $Name ` + ) -join '' ) + + if ($NrptRule) + { + # The NrptRule exists - update it + Set-DnsClientNrptRule @PSBoundParameters ` + -ErrorAction Stop + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleUpdatedMessage) ` + -f $Name ` + ) -join '' ) + } + else + { + # The NrptRule does not exit - create it + Add-NrptRule @PSBoundParameters ` + -ErrorAction Stop + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleCreatedMessage) ` + -f $Name ` + ) -join '' ) + } + } + else + { + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.EnsureNrptRuleDoesNotExistMessage) ` + -f $Name ` + ) -join '' ) + + if ($NrptRule) + { + <# + The NrptRule exists - remove it + Use Force as confirm does not work in DnsClientNrptRule + #> + + Remove-DnsClientNrptRule -Name $Name ` + -Force ` + -ErrorAction Stop + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleRemovedMessage) ` + -f $Name ` + ) -join '' ) + } # if + } # if +} # Set-TargetResource + +<# + .SYNOPSIS + Tests the state of a NRPT Rule. + + .PARAMETER Name + Specifies the name which uniquely identifies a rule. + + .PARAMETER Comment + Stores administrator notes. + + .PARAMETER DAEnable + Indicates the rule state for DirectAccess. + + .PARAMETER DAIPsecEncryptionType + Specifies the Internet Protocol security (IPsec) encryption setting for DirectAccess. + + .PARAMETER DAIPsecRequired + Indicates that IPsec is required for DirectAccess. + + .PARAMETER DANameServers + Specifies an array of DNS servers to query when DirectAccess is enabled. + + .PARAMETER DAProxyServerName + "Specifies the proxy server to use when connecting to the Internet. + This parameter is only applicable if the DAProxyType parameter is set to UseProxyName. + + .PARAMETER DAProxyType + Specifies the proxy server type to be used when connecting to the Internet. + + .PARAMETER DisplayName + Specifies an optional friendly name for the NRPT rule. + + .PARAMETER DnsSecEnable + Enables Domain Name System Security Extensions (DNSSEC) on the rule. + + .PARAMETER DnsSecIPsecEncryptionType + Specifies the IPsec tunnel encryption setting. + + .PARAMETER DnsSecIPsecRequired + Indicates the DNS client must set up an IPsec connection to the DNS server. + + .PARAMETER DnsSecValidationRequired + Indicates that DNSSEC validation is required. + + .PARAMETER IPsecTrustAuthority + Specifies the certification authority to validate the IPsec channel. + + .PARAMETER NameEncoding + Specifies the encoding format for host names in the DNS query. + + .PARAMETER NameServers + Specifies the DNS servers to which the DNS query is sent when DirectAccess is disabled. + + .PARAMETER Namespace + Specifies the DNS namespace. +#> +function Test-TargetResource +{ + [CmdletBinding()] + [OutputType([System.Boolean])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name, + + [Parameter()] + [ValidateSet('Present', 'Absent')] + [System.String] + $Ensure = 'Present', + + [Parameter()] + [System.String] + $Comment, + + [Parameter()] + [System.Boolean] + $DAEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DAIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DAIPsecRequired, + + [Parameter()] + [System.String[]] + $DANameServers, + + [Parameter()] + [System.String] + $DAProxyServerName, + + [Parameter()] + [ValidateSet('NoProxy', 'UseDefault', 'UseProxyName')] + [System.String] + $DAProxyType, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $DnsSecEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DnsSecIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DnsSecIPsecRequired, + + [Parameter()] + [System.Boolean] + $DnsSecValidationRequired, + + [Parameter()] + [System.String] + $IPsecTrustAuthority, + + [Parameter()] + [ValidateSet('Disable', 'Utf8WithMapping', 'Utf8WithoutMapping', 'Punycode')] + [System.String] + $NameEncoding, + + [Parameter()] + [System.String[]] + $NameServers, + + [Parameter()] + [System.String] + $Namespace + ) + + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.TestingNrptRuleMessage) ` + -f $Name ` + ) -join '' ) + + # Flag to signal whether settings are correct + [System.Boolean] $desiredConfigurationMatch = $true + + # Remove any parameters that can't be splatted. + $null = $PSBoundParameters.Remove('Ensure') + + # Check the parameters + # Assert-ResourceProperty @PSBoundParameters + + # Lookup the existing NrptRule + $NrptRule = Get-NrptRule -Name $Name + + if ($Ensure -eq 'Present') + { + # The NrptRule should exist + if ($NrptRule) + { + # The NrptRule exists and does - but check the parameters + $currentState = Get-TargetResource -Name $Name + + return Test-DscParameterState -CurrentValues $currentState -DesiredValues $PSBoundParameters + } + else + { + # The NrptRule doesn't exist but should + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleDoesNotExistButShouldMessage) ` + -f $Name ` + ) -join '' ) + + $desiredConfigurationMatch = $false + } + } + else + { + # The NrptRule should not exist + if ($NrptRule) + { + # The NrptRule exists but should not + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleExistsButShouldNotMessage) ` + -f $Name ` + ) -join '' ) + + $desiredConfigurationMatch = $false + } + else + { + # The NrptRule does not exist and should not + Write-Verbose -Message ( @( + "$($MyInvocation.MyCommand): " + $($script:localizedData.NrptRuleDoesNotExistAndShouldNotMessage) ` + -f $Name ` + ) -join '' ) + } + } # if + + return $desiredConfigurationMatch +} # Test-TargetResource + +<# + .SYNOPSIS + This function looks up DNS Client NRPT Rule using the parameters and returns + it. If the rule is not found $null is returned. + + .PARAMETER Name + Specifies the name which uniquely identifies a rule. +#> + +function Get-NrptRule +{ + param + ( + [Parameter()] + [System.String] + $Name + ) + + try + { + $nrptRule = Get-DnsClientNrptRule ` + -Name $Name ` + -ErrorAction SilentlyContinue + } + catch [Microsoft.PowerShell.Cmdletization.Cim.CimJobException] + { + $nrptRule = $null + } + catch + { + throw $_ + } + + return $nrptRule +} + +<# + .SYNOPSIS + This function create a DNS Client NRPT Rule using the parameters. + This is a dedicated function adding the Rule Name parameter as + the built-in Add-DnsClientNrptRule cmdlet does not support it. + + .PARAMETER Name + Specifies the name which uniquely identifies a rule. + + .PARAMETER Comment + Stores administrator notes. + + .PARAMETER DAEnable + Indicates the rule state for DirectAccess. + + .PARAMETER DAIPsecEncryptionType + Specifies the Internet Protocol security (IPsec) encryption setting for DirectAccess. + + .PARAMETER DAIPsecRequired + Indicates that IPsec is required for DirectAccess. + + .PARAMETER DANameServers + Specifies an array of DNS servers to query when DirectAccess is enabled. + + .PARAMETER DAProxyServerName + "Specifies the proxy server to use when connecting to the Internet. + This parameter is only applicable if the DAProxyType parameter is set to UseProxyName. + + .PARAMETER DAProxyType + Specifies the proxy server type to be used when connecting to the Internet. + + .PARAMETER DisplayName + Specifies an optional friendly name for the NRPT rule. + + .PARAMETER DnsSecEnable + Enables Domain Name System Security Extensions (DNSSEC) on the rule. + + .PARAMETER DnsSecIPsecEncryptionType + Specifies the IPsec tunnel encryption setting. + + .PARAMETER DnsSecIPsecRequired + Indicates the DNS client must set up an IPsec connection to the DNS server. + + .PARAMETER DnsSecValidationRequired + Indicates that DNSSEC validation is required. + + .PARAMETER IPsecTrustAuthority + Specifies the certification authority to validate the IPsec channel. + + .PARAMETER NameEncoding + Specifies the encoding format for host names in the DNS query. + + .PARAMETER NameServers + Specifies the DNS servers to which the DNS query is sent when DirectAccess is disabled. + + .PARAMETER Namespace + Specifies the DNS namespace. +#> +function Add-NrptRule +{ + [CmdletBinding()] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $Name, + + [Parameter()] + [System.String] + $Comment, + + [Parameter()] + [System.Boolean] + $DAEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DAIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DAIPsecRequired, + + [Parameter()] + [System.String[]] + $DANameServers, + + [Parameter()] + [System.String] + $DAProxyServerName, + + [Parameter()] + [ValidateSet('NoProxy', 'UseDefault', 'UseProxyName')] + [System.String] + $DAProxyType, + + [Parameter()] + [System.String] + $DisplayName, + + [Parameter()] + [System.Boolean] + $DnsSecEnable, + + [Parameter()] + [ValidateSet('None', 'Low', 'Medium', 'High')] + [System.String] + $DnsSecIPsecEncryptionType, + + [Parameter()] + [System.Boolean] + $DnsSecIPsecRequired, + + [Parameter()] + [System.Boolean] + $DnsSecValidationRequired, + + [Parameter()] + [System.String] + $IPsecTrustAuthority, + + [Parameter()] + [ValidateSet('Disable', 'Utf8WithMapping', 'Utf8WithoutMapping', 'Punycode')] + [System.String] + $NameEncoding, + + [Parameter()] + [System.String[]] + $NameServers, + + [Parameter()] + [System.String] + $Namespace + ) + + # Remove Name parameter as Add-DnsClientNrptRule cmdlet doesn't support it + $null = $PSBoundParameters.Remove("Name") + + # The NrptRule does not exit - create it (PassThru to get the name of the rule created) + $NrptRuleName = (Add-DnsClientNrptRule @PSBoundParameters -PassThru).Name + # If rule has been created, rename it by registry as Name cannot be provided in Add-DnsClientNrptRule cmdlet + if (Test-IsGuid -InputValue $NrptRuleName) + { + # Rename the registry key + Rename-Item -Path "$($script:dnsPolicyConfigRegistryPath)\$($NrptRuleName)" ` + -NewName $Name ` + -ErrorAction Stop + } +} + +<# + .SYNOPSIS + This function check if the string provided is a GUID. + + .PARAMETER InputValue + Specifies the value to test. +#> +function Test-IsGuid +{ + [OutputType([System.Boolean])] + param + ( + [Parameter()] + [System.String] + $InputValue + ) + + try + { + # Attempt to parse the string as a GUID + [void][Guid]::Parse($InputValue) + # If successful, return true + return $true + } + catch + { + # If an exception is thrown, the string is not a valid GUID + return $false + } +} + + +Export-ModuleMember -Function *-TargetResource diff --git a/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.schema.mof b/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.schema.mof new file mode 100644 index 00000000..cfdce6bf --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptRule/DSC_DnsClientNrptRule.schema.mof @@ -0,0 +1,22 @@ +[ClassVersion("1.0.0.0"), FriendlyName("DnsClientNrptRule")] +class DSC_DnsClientNrptRule : OMI_BaseResource +{ + [Key, Description("Specifies the DNS Client NRPT rule name.")] string Name; + [Write, Description("Specifies whether the DNS Client NRPT rule should exist. Defaults to 'Present'."), ValueMap{"Present","Absent"}, Values{"Present","Absent"}] String Ensure; + [Write, Description("Stores administrator notes.")] string Comment; + [Write, Description("Indicates the rule state for DirectAccess.")] Boolean DAEnable; + [Write, Description("Specifies the Internet Protocol security (IPsec) encryption setting for DirectAccess."), ValueMap{"None", "Low", "Medium", "High"},Values{"None", "Low", "Medium", "High"}] string DAIPsecEncryptionType; + [Write, Description("Indicates that IPsec is required for DirectAccess.")] Boolean DAIPsecRequired; + [Write, Description("Specifies an array of DNS servers to query when DirectAccess is enabled.")] string DANameServers[]; + [Write, Description("Specifies the proxy server to use when connecting to the Internet. This parameter is only applicable if the DAProxyType parameter is set to UseProxyName.")] string DAProxyServerName; + [Write, Description("Specifies the proxy server type to be used when connecting to the Internet."), ValueMap{"NoProxy", "UseDefault", "UseProxyName"},Values{"NoProxy", "UseDefault", "UseProxyName"}] string DAProxyType; + [Write, Description("Specifies an optional friendly name for the NRPT rule.")] String DisplayName; + [Write, Description("Enables Domain Name System Security Extensions (DNSSEC) on the rule.")] Boolean DnsSecEnable; + [Write, Description("Specifies the IPsec tunnel encryption setting."), ValueMap{"None", "Low", "Medium", "High"},Values{"None", "Low", "Medium", "High"}] string DnsSecIPsecEncryptionType; + [Write, Description("Indicates the DNS client must set up an IPsec connection to the DNS server.")] Boolean DnsSecIPsecRequired; + [Write, Description("Indicates that DNSSEC validation is required.")] Boolean DnsSecValidationRequired; + [Write, Description("Specifies the certification authority to validate the IPsec channel.")] String IPsecTrustAuthority; + [Write, Description("Specifies the encoding format for host names in the DNS query."), ValueMap{"Disable", "Utf8WithMapping", "Utf8WithoutMapping", "Punycode"},Values{"Disable", "Utf8WithMapping", "Utf8WithoutMapping", "Punycode"}] string NameEncoding; + [Write, Description("Specifies the DNS servers to which the DNS query is sent when DirectAccess is disabled.")] string NameServers[]; + [Write, Description("Specifies the DNS namespace.")] string Namespace; +}; diff --git a/source/DSCResources/DSC_DnsClientNrptRule/README.MD b/source/DSCResources/DSC_DnsClientNrptRule/README.MD new file mode 100644 index 00000000..b7ae95aa --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptRule/README.MD @@ -0,0 +1,3 @@ +# Description + +This resource is used to control DNS Client NRPT rules for a node. diff --git a/source/DSCResources/DSC_DnsClientNrptRule/en-US/DSC_DnsClientNrptRule.strings.psd1 b/source/DSCResources/DSC_DnsClientNrptRule/en-US/DSC_DnsClientNrptRule.strings.psd1 new file mode 100644 index 00000000..dfcc838b --- /dev/null +++ b/source/DSCResources/DSC_DnsClientNrptRule/en-US/DSC_DnsClientNrptRule.strings.psd1 @@ -0,0 +1,17 @@ +# Localized resources for DSC_DnsClientNrptRule + +ConvertFrom-StringData @' + GettingNrptRuleMessage = Getting '{0}' DNS Client NRPT rule. + NrptRuleExistsMessage = '{0}' DNS Client NRPT rule exists. + NrptRuleDoesNotExistMessage = '{0}' DNS Client NRPT rule does not exist. + SettingNrptRuleMessage = Setting '{0}' DNS Client NRPT rule. + EnsureNrptRuleExistsMessage = Ensuring '{0}' DNS Client NRPT rule exists. + EnsureNrptRuleDoesNotExistMessage = Ensuring '{0}' DNS Client NRPT rule does not exist. + NrptRuleCreatedMessage = '{0}' DNS Client NRPT rule has been created. + NrptRuleUpdatedMessage = '{0}' DNS Client NRPT rule has been updated. + NrptRuleRemovedMessage = '{0}' DNS Client NRPT rule has been removed. + TestingNrptRuleMessage = Testing '{0}' DNS Client NRPT rule. + NrptRuleDoesNotExistButShouldMessage = '{0}' DNS Client NRPT rule does not exist but should. Change required. + NrptRuleExistsButShouldNotMessage = '{0}' DNS Client NRPT rule exists but should not. Change required. + NrptRuleDoesNotExistAndShouldNotMessage = '{0}' DNS Client NRPT rule does not exist and should not. Change not required. +'@ diff --git a/source/Examples/Resources/DnsClientNrptGlobal/1-DnsClientNrptGlobal_Config.ps1 b/source/Examples/Resources/DnsClientNrptGlobal/1-DnsClientNrptGlobal_Config.ps1 new file mode 100644 index 00000000..c1f93379 --- /dev/null +++ b/source/Examples/Resources/DnsClientNrptGlobal/1-DnsClientNrptGlobal_Config.ps1 @@ -0,0 +1,38 @@ +<#PSScriptInfo +.VERSION 1.0.0 +.GUID 1b31527d-8de4-4a7e-a000-9182a0e87cfb +.AUTHOR DSC Community +.COMPANYNAME DSC Community +.COPYRIGHT Copyright the DSC Community contributors. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/dsccommunity/NetworkingDsc/blob/main/LICENSE +.PROJECTURI https://github.com/dsccommunity/NetworkingDsc +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES First version. +.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core +#> + +#Requires -module NetworkingDsc + +<# + .DESCRIPTION + Configure DNS Client NRPT global configuration and set EnableDAForAllNetworks to 'EnableAlways', QueryPolicy to 'QueryBoth' and SecureNameQueryFallback to 'FallbackSecure'. +#> +Configuration DnsClientNrptGlobal_Config +{ + Import-DscResource -Module NetworkingDsc + + Node localhost + { + DnsClientNrptGlobal DnsClientNrptGlobal + { + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'EnableAlways' + QueryPolicy = 'QueryBoth' + SecureNameQueryFallback = 'FallbackSecure' + } + } +} diff --git a/source/Examples/Resources/DnsClientNrptRule/1-DnsClientNrptRule_Server_Config.ps1 b/source/Examples/Resources/DnsClientNrptRule/1-DnsClientNrptRule_Server_Config.ps1 new file mode 100644 index 00000000..bf701ebf --- /dev/null +++ b/source/Examples/Resources/DnsClientNrptRule/1-DnsClientNrptRule_Server_Config.ps1 @@ -0,0 +1,37 @@ +<#PSScriptInfo +.VERSION 1.0.0 +.GUID ffeb7cf3-f0d8-4e26-8f1f-132d889e639b +.AUTHOR DSC Community +.COMPANYNAME DSC Community +.COPYRIGHT Copyright the DSC Community contributors. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/dsccommunity/NetworkingDsc/blob/main/LICENSE +.PROJECTURI https://github.com/dsccommunity/NetworkingDsc +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES First version. +.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core +#> + +#Requires -module NetworkingDsc + +<# + .DESCRIPTION + Sets a DNS Client NRPT rule named 'Contoso DNS Policy' to configure a conditional DNS forwarder (192.168.1.1) for a specific namespace (contoso.com). +#> +Configuration DnsClientNrptRule_Server_Config +{ + Import-DscResource -Module NetworkingDsc + + Node localhost + { + DnsClientNrptRule Server + { + Name = 'Contoso DNS Policy' + Namespace = '.contoso.com' + NameServers = ('192.168.1.1') + } + } +} diff --git a/source/Examples/Resources/DnsClientNrptRule/2-DnsClientNrptRule_DNSSEC_Config.ps1 b/source/Examples/Resources/DnsClientNrptRule/2-DnsClientNrptRule_DNSSEC_Config.ps1 new file mode 100644 index 00000000..78314727 --- /dev/null +++ b/source/Examples/Resources/DnsClientNrptRule/2-DnsClientNrptRule_DNSSEC_Config.ps1 @@ -0,0 +1,37 @@ +<#PSScriptInfo +.VERSION 1.0.0 +.GUID 2c8c4bf7-04ca-464a-941b-3b95c566693d +.AUTHOR DSC Community +.COMPANYNAME DSC Community +.COPYRIGHT Copyright the DSC Community contributors. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/dsccommunity/NetworkingDsc/blob/main/LICENSE +.PROJECTURI https://github.com/dsccommunity/NetworkingDsc +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES First version. +.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core +#> + +#Requires -module NetworkingDsc + +<# + .DESCRIPTION + Sets a DNS Client NRPT rule named 'DNSSEC' to enable DNSSEC queries for a specific namespace (contoso.com). +#> +Configuration DnsClientNrptRule_DNSSEC_Config +{ + Import-DscResource -Module NetworkingDsc + + Node localhost + { + DnsClientNrptRule DNSSEC + { + Name = 'DNSSEC' + Namespace = 'contoso.com' + DnsSecEnable = $true + } + } +} diff --git a/source/Examples/Resources/DnsClientNrptRule/3-DnsClientNrptRule_Punycode_Config.ps1 b/source/Examples/Resources/DnsClientNrptRule/3-DnsClientNrptRule_Punycode_Config.ps1 new file mode 100644 index 00000000..00eb0952 --- /dev/null +++ b/source/Examples/Resources/DnsClientNrptRule/3-DnsClientNrptRule_Punycode_Config.ps1 @@ -0,0 +1,38 @@ +<#PSScriptInfo +.VERSION 1.0.0 +.GUID eafe8bba-ac2c-4509-b6c5-3dc9d57facfd +.AUTHOR DSC Community +.COMPANYNAME DSC Community +.COPYRIGHT Copyright the DSC Community contributors. All rights reserved. +.TAGS DSCConfiguration +.LICENSEURI https://github.com/dsccommunity/NetworkingDsc/blob/main/LICENSE +.PROJECTURI https://github.com/dsccommunity/NetworkingDsc +.ICONURI +.EXTERNALMODULEDEPENDENCIES +.REQUIREDSCRIPTS +.EXTERNALSCRIPTDEPENDENCIES +.RELEASENOTES First version. +.PRIVATEDATA 2016-Datacenter,2016-Datacenter-Server-Core +#> + +#Requires -module NetworkingDsc + +<# + .DESCRIPTION + Sets a DNS Client NRPT rule named 'Punycode' to send Punycode DNS queries using a conditional DNS forwarder for a specific namespace(contoso.com). +#> +Configuration DnsClientNrptRule_Punycode_Config +{ + Import-DscResource -Module NetworkingDsc + + Node localhost + { + DnsClientNrptRule Punycode + { + Name = 'Punycode' + Namespace = 'contoso.com' + NameEncoding = 'Punycode' + NameServers = ('192.168.1.1') + } + } +} diff --git a/tests/Integration/DSC_DnsClientNrptGlobal.Integration.Tests.ps1 b/tests/Integration/DSC_DnsClientNrptGlobal.Integration.Tests.ps1 new file mode 100644 index 00000000..e1e4b209 --- /dev/null +++ b/tests/Integration/DSC_DnsClientNrptGlobal.Integration.Tests.ps1 @@ -0,0 +1,131 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +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.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscResourceFriendlyName = 'DnsClientNrptGlobal' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" +} + +BeforeAll { + # Need to define the variables here which will be used in Pester Run. + $script:dscModuleName = 'NetworkingDsc' + $script:dscResourceFriendlyName = 'DnsClientNrptGlobal' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') +} + +AfterAll { + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment +} + + +Describe 'DnsClientNrptGlobal Integration Tests' { + BeforeAll { + # Backup the existing settings + $script:currentDnsClientNrptGlobal = Get-DnsClientNrptGlobal + + # Set the DNS Client Global settings to known values + Set-DnsClientNrptGlobal ` + -EnableDAForAllNetworks 'Disable' ` + -QueryPolicy 'Disable' ` + -SecureNameQueryFallback 'Disable' + + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + EnableDAForAllNetworks = 'EnableAlways' + QueryPolicy = 'QueryBoth' + SecureNameQueryFallback = 'FallbackSecure' + } + ) + } + + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" + . $configFile + } + + AfterAll { + # Clean up + Set-DnsClientNrptGlobal ` + -EnableDAForAllNetworks $script:currentDnsClientNrptGlobal.EnableDAForAllNetworks ` + -QueryPolicy $script:currentDnsClientNrptGlobal.QueryPolicy ` + -SecureNameQueryFallback $script:currentDnsClientNrptGlobal.SecureNameQueryFallback + } + + Describe "$($script:dscResourceName)_Integration" { + AfterEach { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + Context 'When testing each of the parameter values' { + BeforeAll { + # Get the DNS Client Global Settings details + $DnsClientNrptGlobalNew = Get-DnsClientNrptGlobal + } + + It 'Should have the correct value for <_>' -ForEach @( + 'EnableDAForAllNetworks', + 'QueryPolicy', + 'SecureNameQueryFallback' + ) { + $parameterCurrentValue = (Get-Variable -Name DnsClientNrptGlobalNew).value.$_ + $parameterNewValue = (Get-Variable -Name configData).Value.AllNodes[0].$_ + + $parameterCurrentValue | Should -Be $parameterNewValue + } + } + } +} diff --git a/tests/Integration/DSC_DnsClientNrptGlobal.config.ps1 b/tests/Integration/DSC_DnsClientNrptGlobal.config.ps1 new file mode 100644 index 00000000..cdc72a11 --- /dev/null +++ b/tests/Integration/DSC_DnsClientNrptGlobal.config.ps1 @@ -0,0 +1,12 @@ +Configuration DSC_DnsClientNrptGlobal_Config { + Import-DscResource -ModuleName NetworkingDsc + + node localhost { + DnsClientNrptGlobal Integration_Test { + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = $Node.EnableDAForAllNetworks + QueryPolicy = $Node.QueryPolicy + SecureNameQueryFallback = $Node.SecureNameQueryFallback + } + } +} diff --git a/tests/Integration/DSC_DnsClientNrptRule.Integration.Tests.ps1 b/tests/Integration/DSC_DnsClientNrptRule.Integration.Tests.ps1 new file mode 100644 index 00000000..4d097c53 --- /dev/null +++ b/tests/Integration/DSC_DnsClientNrptRule.Integration.Tests.ps1 @@ -0,0 +1,182 @@ +[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Suppressing this rule because Script Analyzer does not understand Pester syntax.')] +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.' + } + + <# + Need to define that variables here to be used in the Pester Discover to + build the ForEach-blocks. + #> + $script:dscResourceFriendlyName = 'DnsClientNrptRule' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" +} + +BeforeAll { + # Need to define the variables here which will be used in Pester Run. + $script:dscModuleName = 'NetworkingDsc' + $script:dscResourceFriendlyName = 'DnsClientNrptRule' + $script:dscResourceName = "DSC_$($script:dscResourceFriendlyName)" + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Integration' + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') +} + +AfterAll { + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment +} + +Describe 'DnsClientNrptRule Integration Tests' { + BeforeAll { + $script:dummyRule = [PSObject] @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + } + + $configFile = Join-Path -Path $PSScriptRoot -ChildPath "$($script:dscResourceName).config.ps1" + . $configFile + } + + AfterAll { + # Clean up any created rules just in case the integration tests fail + if (Get-DnsClientNrptRule -Name $script:dummyRule.Name -ErrorAction SilentlyContinue) + { + Remove-DnsClientNrptRule -Name $script:dummyRule.Name -Force -ErrorAction SilentlyContinue + } + } + + Describe "$($script:dscResourceName)_Add_Integration" { + BeforeAll { + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + Name = $script:dummyRule.Name + Namespace = $script:dummyRule.Namespace + NameServers = $script:dummyRule.NameServers + Ensure = 'Present' + } + ) + } + } + + AfterEach { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" + } + + $current.Name | Should -Be $configData.AllNodes[0].Name + $current.Namespace | Should -Be $configData.AllNodes[0].Namespace + $current.NameServers | Should -Be $configData.AllNodes[0].NameServers + $current.Ensure | Should -Be $configData.AllNodes[0].Ensure + } + + It 'Should have created the NRPT rule' { + Get-DnsClientNrptRule -Name $script:dummyRule.Name -ErrorAction SilentlyContinue | Should -Not -BeNullOrEmpty + } + } + + Describe "$($script:dscResourceName)_Remove_Integration" { + BeforeAll { + $configData = @{ + AllNodes = @( + @{ + NodeName = 'localhost' + Name = $script:dummyRule.Name + Namespace = $script:dummyRule.Namespace + NameServers = $script:dummyRule.NameServers + Ensure = 'Absent' + } + ) + } + } + + AfterEach { + Wait-ForIdleLcm + } + + It 'Should compile and apply the MOF without throwing' { + { + & "$($script:dscResourceName)_Config" ` + -OutputPath $TestDrive ` + -ConfigurationData $configData + + Start-DscConfiguration ` + -Path $TestDrive ` + -ComputerName localhost ` + -Wait ` + -Verbose ` + -Force ` + -ErrorAction Stop + } | Should -Not -Throw + } + + It 'Should be able to call Get-DscConfiguration without throwing' { + { Get-DscConfiguration -Verbose -ErrorAction Stop } | Should -Not -Throw + } + + It 'Should have set the resource and all the parameters should match' { + $current = Get-DscConfiguration | Where-Object -FilterScript { + $_.ConfigurationName -eq "$($script:dscResourceName)_Config" + } + + $current.Name | Should -Be $configData.AllNodes[0].Name + $current.Ensure | Should -Be $configData.AllNodes[0].Ensure + } + + It 'Should have deleted the NRPT rule' { + Get-DnsClientNrptRule -Name $script:dummyRule.Name -ErrorAction SilentlyContinue | Should -BeNullOrEmpty + } + } +} diff --git a/tests/Integration/DSC_DnsClientNrptRule.config.ps1 b/tests/Integration/DSC_DnsClientNrptRule.config.ps1 new file mode 100644 index 00000000..764fa281 --- /dev/null +++ b/tests/Integration/DSC_DnsClientNrptRule.config.ps1 @@ -0,0 +1,19 @@ +configuration DSC_DnsClientNrptRule_Config { + param + ( + [Parameter()] + [System.String[]] + $NodeName = 'localhost' + ) + + Import-DscResource -ModuleName NetworkingDsc + + Node $NodeName { + DnsClientNrptRule Integration_Test { + Name = $Node.Name + Namespace = $Node.Namespace + NameServers = $Node.NameServers + Ensure = $Node.Ensure + } + } +} diff --git a/tests/Unit/DSC_DnsClientNrptGlobal.Tests.ps1 b/tests/Unit/DSC_DnsClientNrptGlobal.Tests.ps1 new file mode 100644 index 00000000..c756d4d3 --- /dev/null +++ b/tests/Unit/DSC_DnsClientNrptGlobal.Tests.ps1 @@ -0,0 +1,311 @@ +# 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 = 'NetworkingDsc' + $script:dscResourceName = 'DSC_DnsClientNrptGlobal' + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Unit' + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force +} + +Describe 'DSC_DnsClientNrptGlobal\Get-TargetResource' -Tag 'Get' { + BeforeEach { + Mock -CommandName Get-DnsClientNrptGlobal -MockWith { + @{ + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + } + } + + Context 'DNS Client NRPT Global Settings Exists' { + It 'Should return correct DNS Client NRPT Global Settings values' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $getTargetResourceParameters = Get-TargetResource -IsSingleInstance 'Yes' + + $getTargetResourceParameters.EnableDAForAllNetworks | Should -Be 'Disable' + $getTargetResourceParameters.QueryPolicy | Should -Be 'Disable' + $getTargetResourceParameters.SecureNameQueryFallback | Should -Be 'Disable' + } + } + + It 'Should call the expected mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } +} + +Describe 'DSC_DnsClientNrptGlobal\Set-TargetResource' -Tag 'Set' { + BeforeEach { + Mock -CommandName Get-DnsClientNrptGlobal -MockWith { + @{ + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + } + } + + Context 'DNS Client NRPT Global Settings all parameters are the same' { + BeforeAll { + Mock -CommandName Set-DnsClientNrptGlobal + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptGlobal -Exactly -Times 0 -Scope Context + } + } + + Context 'DNS Client NRPT Global Settings EnableDAForAllNetworks is different' { + BeforeAll { + Mock -CommandName Set-DnsClientNrptGlobal + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $setTargetResourceParameters.EnableDAForAllNetworks = 'EnableAlways' + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } + + + Context 'DNS Client NRPT Global Settings QueryPolicy is different' { + BeforeAll { + Mock -CommandName Set-DnsClientNrptGlobal + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $setTargetResourceParameters.QueryPolicy = 'QueryBoth' + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } + + Context 'DNS Client NRPT Global Settings SecureNameQueryFallback is different' { + BeforeAll { + Mock -CommandName Set-DnsClientNrptGlobal + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $setTargetResourceParameters.SecureNameQueryFallback = 'FallbackSecure' + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } +} + +Describe 'DSC_DnsClientNrptGlobal\Test-TargetResource' -Tag 'Test' { + BeforeEach { + Mock -CommandName Get-DnsClientNrptGlobal -MockWith { + @{ + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + } + } + + Context 'DNS Client NRPT Global Settings all parameters are the same' { + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + Test-TargetResource @testTargetResourceParameters | Should -BeTrue + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } + + Context 'DNS Client NRPT Global Settings EnableDAForAllNetworks is different' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $testTargetResourceParameters.EnableDAForAllNetworks = 'EnableAlways' + + Test-TargetResource @testTargetResourceParameters | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } + + Context 'DNS Client NRPT Global Settings QueryPolicy is different' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $testTargetResourceParameters.QueryPolicy = 'QueryBoth' + + Test-TargetResource @testTargetResourceParameters | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } + + Context 'DNS Client NRPT Global Settings UseDevolution is different' { + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = @{ + IsSingleInstance = 'Yes' + EnableDAForAllNetworks = 'Disable' + QueryPolicy = 'Disable' + SecureNameQueryFallback = 'Disable' + } + + $testTargetResourceParameters.SecureNameQueryFallback = 'FallbackSecure' + + Test-TargetResource @testTargetResourceParameters | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptGlobal -Exactly -Times 1 -Scope Context + } + } +} diff --git a/tests/Unit/DSC_DnsClientNrptRule.Tests.ps1 b/tests/Unit/DSC_DnsClientNrptRule.Tests.ps1 new file mode 100644 index 00000000..631c579a --- /dev/null +++ b/tests/Unit/DSC_DnsClientNrptRule.Tests.ps1 @@ -0,0 +1,456 @@ +# 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 = 'NetworkingDsc' + $script:dscResourceName = 'DSC_DnsClientNrptRule' + + $script:testEnvironment = Initialize-TestEnvironment ` + -DSCModuleName $script:dscModuleName ` + -DSCResourceName $script:dscResourceName ` + -ResourceType 'Mof' ` + -TestType 'Unit' + + Import-Module -Name (Join-Path -Path $PSScriptRoot -ChildPath '..\TestHelpers\CommonTestHelper.psm1') + + $PSDefaultParameterValues['InModuleScope:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Mock:ModuleName'] = $script:dscResourceName + $PSDefaultParameterValues['Should:ModuleName'] = $script:dscResourceName +} + +AfterAll { + $PSDefaultParameterValues.Remove('InModuleScope:ModuleName') + $PSDefaultParameterValues.Remove('Mock:ModuleName') + $PSDefaultParameterValues.Remove('Should:ModuleName') + + Restore-TestEnvironment -TestEnvironment $script:testEnvironment + + # Remove module common test helper. + Get-Module -Name 'CommonTestHelper' -All | Remove-Module -Force + + # Unload the module being tested so that it doesn't impact any other tests. + Get-Module -Name $script:dscResourceName -All | Remove-Module -Force +} + +Describe 'DSC_DnsClientNrptRule\Get-TargetResource' -Tag 'Get' { + BeforeAll { + $mockNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + $testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + InModuleScope -ScriptBlock { + $script:testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + } + } + Context 'NRPT Rule does not exist' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule + } + + It 'Should return absent NRPT Rule' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource -Name 'Contoso Dns Policy' + $result.Ensure | Should -Be 'Absent' + } + } + + It 'Should call the expected mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + } + } + + Context 'NRPT Rule does exist' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + } + + It 'Should return correct NRPT Rule' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $result = Get-TargetResource -Name 'Contoso Dns Policy' + $result.Ensure | Should -Be 'Present' + $result.Namespace | Should -Be $testNrptRule.Namespace + $result.NameServers | Should -Be $testNrptRule.NameServers + } + } + + It 'Should call the expected mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + } + } +} + +Describe 'DSC_DnsClientNrptRule\Set-TargetResource' -Tag 'Set' { + BeforeAll { + $mockNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + $testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + InModuleScope -ScriptBlock { + $script:testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + } + } + + Context 'NRPT Rule does not exist but should' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule + Mock -CommandName Add-DnsClientNrptRule + Mock -CommandName Set-DnsClientNrptRule + Mock -CommandName Remove-DnsClientNrptRule + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = $testNrptRule.Clone() + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Add-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Remove-DnsClientNrptRule -Exactly -Times 0 -Scope Context + } + } + + Context 'NRPT Rule exists and should but has a different Namespace' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + Mock -CommandName Add-DnsClientNrptRule + Mock -CommandName Set-DnsClientNrptRule + Mock -CommandName Remove-DnsClientNrptRule + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = $script:testNrptRule.Clone() + $setTargetResourceParameters.Namespace = '.fabrikam.com' + + $result = Set-TargetResource @setTargetResourceParameters + + { $result } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Add-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Remove-DnsClientNrptRule -Exactly -Times 0 -Scope Context + } + } + + Context 'NRPT Rule exists and should but has a different NameServers' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + Mock -CommandName Add-DnsClientNrptRule + Mock -CommandName Set-DnsClientNrptRule + Mock -CommandName Remove-DnsClientNrptRule + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = $testNrptRule.Clone() + $setTargetResourceParameters.NameServers = @('192.168.0.1') + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Add-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Remove-DnsClientNrptRule -Exactly -Times 0 -Scope Context + } + } + + Context 'NRPT Rule exists and but should not' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + Mock -CommandName Add-DnsClientNrptRule + Mock -CommandName Set-DnsClientNrptRule + Mock -CommandName Remove-DnsClientNrptRule ` + -ParameterFilter { + ($Name -eq $testNrptRule.Name) + } + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = $testNrptRule.Clone() + $setTargetResourceParameters.Ensure = 'Absent' + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected mocks and parameters' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Add-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Remove-DnsClientNrptRule ` + -ParameterFilter { + ($Name -eq $testNrptRule.Name) + } -Exactly -Times 1 -Scope Context + } + } + + Context 'NRPT Rule does not exist and should not' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule + Mock -CommandName Add-DnsClientNrptRule + Mock -CommandName Set-DnsClientNrptRule + Mock -CommandName Remove-DnsClientNrptRule + } + + It 'Should not throw error' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $setTargetResourceParameters = $testNrptRule.Clone() + $setTargetResourceParameters.Ensure = 'Absent' + + { Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + Should -Invoke -CommandName Add-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Set-DnsClientNrptRule -Exactly -Times 0 -Scope Context + Should -Invoke -CommandName Remove-DnsClientNrptRule -Exactly -Times 0 -Scope Context + } + } +} + +Describe 'DSC_DnsClientNrptRule\Test-TargetResource' -Tag 'Test' { + BeforeAll { + $mockNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + $testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + + InModuleScope -ScriptBlock { + $script:testNrptRule = @{ + Name = 'Contoso Dns Policy' + Namespace = '.contoso.com' + NameServers = @('192.168.1.1') + Ensure = 'Present' + } + } + } + Context 'NRPT Rule does not exist but should' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + Test-TargetResource @testTargetResourceParameters | Should -BeFalse + } + + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + } + } + + Context 'NRPT Rule exists and should but has a different Namespace' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + $testTargetResourceParameters.Namespace = '.fabrikam.com' + + $result = Test-TargetResource @testTargetResourceParameters + + { $result } | Should -Not -Throw + $result | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 2 -Scope Context + } + } + + Context 'NRPT Rule exists and should but has a different NameServers' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + $testTargetResourceParameters.NameServers = @('192.168.0.1') + + $result = Test-TargetResource @testTargetResourceParameters + + { $result } | Should -Not -Throw + $result | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 2 -Scope Context + } + } + + Context 'NRPT Rule exists and should and all parameters match' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + } + + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + + $result = Test-TargetResource @testTargetResourceParameters + + { $result } | Should -Not -Throw + $result | Should -BeTrue + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 2 -Scope Context + } + } + + Context 'NRPT Rule exists but should not' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule -MockWith { $mockNrptRule } + } + + It 'Should return false' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + $testTargetResourceParameters.Ensure = 'Absent' + + $result = Test-TargetResource @testTargetResourceParameters + + { $result } | Should -Not -Throw + $result | Should -BeFalse + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + } + } + + Context 'NRPT Rule does not exist and should not' { + BeforeAll { + Mock -CommandName Get-DnsClientNrptRule + } + + It 'Should return true' { + InModuleScope -ScriptBlock { + Set-StrictMode -Version 1.0 + + $testTargetResourceParameters = $testNrptRule.Clone() + $testTargetResourceParameters.Ensure = 'Absent' + + $result = Test-TargetResource @testTargetResourceParameters + + { $result } | Should -Not -Throw + $result | Should -BeTrue + } + } + + It 'Should call expected Mocks' { + Should -Invoke -CommandName Get-DnsClientNrptRule -Exactly -Times 1 -Scope Context + } + } +}