diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b3a7f32..409f960f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## Unreleased +- DefaultGatewayAddress: + - Refactored to reduce code duplication. + - Fixed hash table style violations - fixes [Issue #429](https://github.com/PowerShell/NetworkingDsc/issues/429). + - Fixed general style violations. + ## 7.4.0.0 - Added Comment Based Help for `New-NotImplementedException` common diff --git a/DSCResources/MSFT_DefaultGatewayAddress/MSFT_DefaultGatewayAddress.psm1 b/DSCResources/MSFT_DefaultGatewayAddress/MSFT_DefaultGatewayAddress.psm1 index 4c8b3cfa..56ae253e 100644 --- a/DSCResources/MSFT_DefaultGatewayAddress/MSFT_DefaultGatewayAddress.psm1 +++ b/DSCResources/MSFT_DefaultGatewayAddress/MSFT_DefaultGatewayAddress.psm1 @@ -29,16 +29,16 @@ function Get-TargetResource ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $InterfaceAlias, [Parameter(Mandatory = $true)] [ValidateSet('IPv4', 'IPv6')] - [String] + [System.String] $AddressFamily, [Parameter()] - [String] + [System.String] $Address ) @@ -46,33 +46,36 @@ function Get-TargetResource $($script:localizedData.GettingDefaultGatewayAddressMessage) ) -join '' ) - # Use $AddressFamily to select the IPv4 or IPv6 destination prefix - $destinationPrefix = '0.0.0.0/0' - if ($AddressFamily -eq 'IPv6') - { - $destinationPrefix = '::/0' - } - # Get all the default routes - $defaultRoutes = Get-NetRoute -InterfaceAlias $InterfaceAlias -AddressFamily ` - $AddressFamily -ErrorAction Stop | ` - Where-Object { $_.DestinationPrefix -eq $destinationPrefix } + $destinationPrefix = Get-NetDefaultGatewayDestinationPrefix ` + -AddressFamily $AddressFamily + + $defaultRoutes = Get-NetDefaultRoute ` + -InterfaceAlias $InterfaceAlias ` + -AddressFamily $AddressFamily $returnValue = @{ AddressFamily = $AddressFamily InterfaceAlias = $InterfaceAlias } - # If there is a Default Gateway defined for this interface/address family add it - # to the return value. + + <# + If there is a Default Gateway defined for this interface/address family add it + to the return value. + #> if ($defaultRoutes) { - $returnValue += @{ Address = $defaultRoutes.NextHop } + $returnValue += @{ + Address = $defaultRoutes.NextHop + } } else { - $returnValue += @{ Address = $null } + $returnValue += @{ + Address = $null + } } - $returnValue + return $returnValue } <# @@ -95,16 +98,16 @@ function Set-TargetResource ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $InterfaceAlias, [Parameter(Mandatory = $true)] [ValidateSet('IPv4', 'IPv6')] - [String] + [System.String] $AddressFamily, [Parameter()] - [String] + [System.String] $Address ) @@ -112,21 +115,11 @@ function Set-TargetResource $($script:localizedData.ApplyingDefaultGatewayAddressMessage) ) -join '' ) - # Use $AddressFamily to select the IPv4 or IPv6 destination prefix - $destinationPrefix = '0.0.0.0/0' + $defaultRoutes = @(Get-NetDefaultRoute ` + -InterfaceAlias $InterfaceAlias ` + -AddressFamily $AddressFamily) - if ($AddressFamily -eq 'IPv6') - { - $destinationPrefix = '::/0' - } - - # Get all the default routes - $defaultRoutes = @(Get-NetRoute ` - -InterfaceAlias $InterfaceAlias ` - -AddressFamily $AddressFamily ` - -ErrorAction Stop).Where( { $_.DestinationPrefix -eq $destinationPrefix } ) - - # Remove any existing default route + # Remove any existing default routes foreach ($defaultRoute in $defaultRoutes) { Remove-NetRoute ` @@ -139,16 +132,18 @@ function Set-TargetResource if ($Address) { + $destinationPrefix = Get-NetDefaultGatewayDestinationPrefix ` + -AddressFamily $AddressFamily + # Set the correct Default Route - # Build parameter hash table - $parameters = @{ + $newNetRouteParameters = @{ DestinationPrefix = $destinationPrefix InterfaceAlias = $InterfaceAlias AddressFamily = $AddressFamily NextHop = $Address } - New-NetRoute @Parameters -ErrorAction Stop + New-NetRoute @newNetRouteParameters -ErrorAction Stop Write-Verbose -Message ( @("$($MyInvocation.MyCommand): " $($script:localizedData.DefaultGatewayAddressSetToDesiredStateMessage) @@ -183,21 +178,21 @@ function Test-TargetResource ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $InterfaceAlias, [Parameter(Mandatory = $true)] [ValidateSet('IPv4', 'IPv6')] - [String] + [System.String] $AddressFamily, [Parameter()] - [String] + [System.String] $Address ) # Flag to signal whether settings are correct - [Boolean] $desiredConfigurationMatch = $true + $desiredConfigurationMatch = $true Write-Verbose -Message ( @("$($MyInvocation.MyCommand): " $($script:localizedData.CheckingDefaultGatewayAddressMessage) @@ -205,36 +200,29 @@ function Test-TargetResource Assert-ResourceProperty @PSBoundParameters - # Use $AddressFamily to select the IPv4 or IPv6 destination prefix - $destinationPrefix = '0.0.0.0/0' - if ($AddressFamily -eq 'IPv6') - { - $destinationPrefix = '::/0' - } - - # Get all the default routes - $defaultRoutes = @(Get-NetRoute ` - -InterfaceAlias $InterfaceAlias ` - -AddressFamily $AddressFamily ` - -ErrorAction Stop).Where( { $_.DestinationPrefix -eq $destinationPrefix } ) + $defaultRoutes = @(Get-NetDefaultRoute ` + -InterfaceAlias $InterfaceAlias ` + -AddressFamily $AddressFamily) # Test if the Default Gateway passed is equal to the current default gateway if ($Address) { if ($defaultRoutes) { - if (-not $defaultRoutes.Where( { $_.NextHop -eq $Address } )) + if ($defaultRoutes.Where( { + $_.NextHop -eq $Address + } )) { Write-Verbose -Message ( @("$($MyInvocation.MyCommand): " - $($script:localizedData.DefaultGatewayNotMatchMessage) -f $Address, $defaultRoutes.NextHop + $($script:localizedData.DefaultGatewayCorrectMessage) ) -join '' ) - $desiredConfigurationMatch = $false } else { Write-Verbose -Message ( @("$($MyInvocation.MyCommand): " - $($script:localizedData.DefaultGatewayCorrectMessage) + $($script:localizedData.DefaultGatewayNotMatchMessage) -f $Address, $defaultRoutes.NextHop ) -join '' ) + $desiredConfigurationMatch = $false } } else @@ -259,7 +247,6 @@ function Test-TargetResource { Write-Verbose -Message ( @("$($MyInvocation.MyCommand): " $($script:localizedData.DefaultGatewayExistsAndShouldMessage) - 'Default Gateway does not exist which is correct.' ) -join '' ) } } @@ -288,16 +275,16 @@ function Assert-ResourceProperty ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] - [String] + [System.String] $InterfaceAlias, [Parameter()] [ValidateSet('IPv4', 'IPv6')] - [String] + [System.String] $AddressFamily = 'IPv4', [Parameter()] - [String] + [System.String] $Address ) @@ -316,7 +303,7 @@ function Assert-ResourceProperty -ArgumentName 'Address' } - $detectedAddressFamily = ([System.Net.IPAddress]$Address).AddressFamily.ToString() + $detectedAddressFamily = ([System.Net.IPAddress] $Address).AddressFamily.ToString() if (($detectedAddressFamily -eq [System.Net.Sockets.AddressFamily]::InterNetwork.ToString()) ` -and ($AddressFamily -ne 'IPv4')) @@ -336,4 +323,73 @@ function Assert-ResourceProperty } } # Assert-ResourceProperty +<# + .SYNOPSIS + Get the default gateway destination prefix for the IP address family. + + .PARAMETER AddressFamily + IP address family. +#> +function Get-NetDefaultGatewayDestinationPrefix +{ + [CmdletBinding()] + [OutputType([System.String])] + param + ( + [Parameter()] + [ValidateSet('IPv4', 'IPv6')] + [System.String] + $AddressFamily = 'IPv4' + ) + + if ($AddressFamily -eq 'IPv4') + { + $destinationPrefix = '0.0.0.0/0' + } + else + { + $destinationPrefix = '::/0' + } + + return $destinationPrefix +} # Get-NetDefaultGatewayDestinationPrefix + +<# + .SYNOPSIS + Get the default network routes assigned to the interface. + + .PARAMETER InterfaceAlias + Alias of the network interface for which the default gateway address is set. + + .PARAMETER AddressFamily + IP address family. +#> +function Get-NetDefaultRoute +{ + [CmdletBinding()] + [OutputType([System.String[]])] + param + ( + [Parameter(Mandatory = $true)] + [ValidateNotNullOrEmpty()] + [System.String] + $InterfaceAlias, + + [Parameter()] + [ValidateSet('IPv4', 'IPv6')] + [System.String] + $AddressFamily = 'IPv4' + ) + + $destinationPrefix = Get-NetDefaultGatewayDestinationPrefix ` + -AddressFamily $AddressFamily + + return @(Get-NetRoute ` + -InterfaceAlias $InterfaceAlias ` + -AddressFamily $AddressFamily ` + -ErrorAction Stop).Where({ + $_.DestinationPrefix -eq $destinationPrefix + }) +} # Get-NetDefaultRoute + Export-ModuleMember -function *-TargetResource diff --git a/Tests/Unit/MSFT_DefaultGatewayAddress.Tests.ps1 b/Tests/Unit/MSFT_DefaultGatewayAddress.Tests.ps1 index 5735ba24..6f15cc18 100644 --- a/Tests/Unit/MSFT_DefaultGatewayAddress.Tests.ps1 +++ b/Tests/Unit/MSFT_DefaultGatewayAddress.Tests.ps1 @@ -1,5 +1,5 @@ -$script:DSCModuleName = 'NetworkingDsc' -$script:DSCResourceName = 'MSFT_DefaultGatewayAddress' +$script:DSCModuleName = 'NetworkingDsc' +$script:DSCResourceName = 'MSFT_DefaultGatewayAddress' Import-Module -Name (Join-Path -Path (Join-Path -Path (Split-Path $PSScriptRoot -Parent) -ChildPath 'TestHelpers') -ChildPath 'CommonTestHelper.psm1') -Global @@ -23,24 +23,24 @@ $TestEnvironment = Initialize-TestEnvironment ` try { InModuleScope $script:DSCResourceName { + $getNetRouteIpv4_Mock = { + [PSCustomObject] @{ + NextHop = '192.168.0.1' + DestinationPrefix = '0.0.0.0/0' + InterfaceAlias = 'Ethernet' + InterfaceIndex = 1 + AddressFamily = 'IPv4' + } + } + Describe 'MSFT_DefaultGatewayAddress\Get-TargetResource' -Tag 'Get' { - Context 'Checking return with default gateway' { - #region Mocks - Mock Get-NetRoute -MockWith { - [PSCustomObject]@{ - NextHop = '192.168.0.1' - DestinationPrefix = '0.0.0.0/0' - InterfaceAlias = 'Ethernet' - InterfaceIndex = 1 - AddressFamily = 'IPv4' - } - } - #endregion + Context 'When interface has a default gateway set' { + Mock -CommandName Get-NetRoute -MockWith $getNetRouteIpv4_Mock It 'Should return current default gateway' { $getTargetResourceParameters = @{ InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } $result = Get-TargetResource @getTargetResourceParameters @@ -49,15 +49,13 @@ try } } - Context 'Checking return with no default gateway' { - #region Mocks - Mock Get-NetRoute -MockWith {} - #endregion + Context 'When interface has no default gateway set' { + Mock -CommandName Get-NetRoute -MockWith { } It 'Should return no default gateway' { $getTargetResourceParameters = @{ InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } $result = Get-TargetResource @getTargetResourceParameters @@ -69,28 +67,16 @@ try Describe 'MSFT_DefaultGatewayAddress\Set-TargetResource' -Tag 'Set' { BeforeEach { - #region Mocks - Mock Get-NetRoute -MockWith { - [PSCustomObject]@{ - NextHop = '192.168.0.1' - DestinationPrefix = '0.0.0.0/0' - InterfaceAlias = 'Ethernet' - InterfaceIndex = 1 - AddressFamily = 'IPv4' - } - } - - Mock Remove-NetRoute - - Mock New-NetRoute - #endregion + Mock -CommandName Get-NetRoute -MockWith $getNetRouteIpv4_Mock + Mock -CommandName Remove-NetRoute + Mock -CommandName New-NetRoute } - Context 'Invoking with no Default Gateway Address' { + Context 'When invoking with no Default Gateway Address' { It 'Should return $null' { $setTargetResourceParameters = @{ InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } { $result = Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw @@ -105,15 +91,17 @@ try } } - Context 'Invoking with valid Default Gateway Address' { + Context 'When invoking with valid Default Gateway Address' { It 'Should return $null' { $setTargetResourceParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } - { $result = Set-TargetResource @setTargetResourceParameters } | Should -Not -Throw + { + $result = Set-TargetResource @setTargetResourceParameters + } | Should -Not -Throw $result | Should -BeNullOrEmpty } @@ -128,29 +116,21 @@ try Describe 'MSFT_DefaultGatewayAddress\Test-TargetResource' -Tag 'Test' { BeforeEach { - #region Mocks - Mock Get-NetAdapter -MockWith { [PSObject]@{ Name = 'Ethernet' } } - #endregion - } - - Context 'Checking return with default gateway that matches currently set one' { - #region Mocks - Mock Get-NetRoute -MockWith { - [PSCustomObject]@{ - NextHop = '192.168.0.1' - DestinationPrefix = '0.0.0.0/0' - InterfaceAlias = 'Ethernet' - InterfaceIndex = 1 - AddressFamily = 'IPv4' + Mock -CommandName Get-NetAdapter -MockWith { + [PSObject] @{ + Name = 'Ethernet' } } - #endregion + } + + Context 'When checking return with default gateway that matches currently set one' { + Mock -CommandName Get-NetRoute -MockWith $getNetRouteIpv4_Mock It 'Should return true' { $testTargetResourceParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } Test-TargetResource @testTargetResourceParameters | Should -Be $true @@ -158,22 +138,12 @@ try } Context 'Checking return with no gateway but one is currently set' { - #region Mocks - Mock Get-NetRoute -MockWith { - [PSCustomObject]@{ - NextHop = '192.168.0.1' - DestinationPrefix = '0.0.0.0/0' - InterfaceAlias = 'Ethernet' - InterfaceIndex = 1 - AddressFamily = 'IPv4' - } - } - #endregion + Mock -CommandName Get-NetRoute -MockWith $getNetRouteIpv4_Mock It 'Should return false' { $testTargetResourceParameters = @{ InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } Test-TargetResource @testTargetResourceParameters | Should -Be $False @@ -181,15 +151,13 @@ try } Context 'Checking return with default gateway but none are currently set' { - #region Mocks - Mock Get-NetRoute -MockWith {} - #endregion + Mock -CommandName Get-NetRoute -MockWith { } It 'Should return false' { $testTargetResourceParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } Test-TargetResource @testTargetResourceParameters | Should -Be $False @@ -197,14 +165,12 @@ try } Context 'Checking return with no gateway and none are currently set' { - #region Mocks - Mock Get-NetRoute -MockWith {} - #endregion + Mock -CommandName Get-NetRoute -MockWith { } It 'Should return true' { $testTargetResourceParameters = @{ InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } Test-TargetResource @testTargetResourceParameters | Should -Be $true @@ -214,15 +180,19 @@ try Describe 'MSFT_DefaultGatewayAddress\Assert-ResourceProperty' { BeforeEach { - Mock Get-NetAdapter -MockWith { [PSObject]@{ Name = 'Ethernet' } } + Mock -CommandName Get-NetAdapter -MockWith { + [PSObject] @{ + Name = 'Ethernet' + } + } } - Context 'Invoking with bad interface alias' { + Context 'When invoking with bad interface alias' { It 'Should throw an InterfaceNotAvailable error' { $assertResourcePropertyParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'NotReal' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } $errorRecord = Get-InvalidOperationRecord ` @@ -232,12 +202,12 @@ try } } - Context 'Invoking with invalid IP Address' { + Context 'When invoking with invalid IP Address' { It 'Should throw an AddressFormatError error' { $assertResourcePropertyParameters = @{ - Address = 'NotReal' + Address = 'NotReal' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } $errorRecord = Get-InvalidArgumentRecord ` @@ -248,62 +218,116 @@ try } } - Context 'Invoking with IPv4 Address and family mismatch' { + Context 'When invoking with IPv4 Address and family mismatch' { It 'Should throw an AddressMismatchError error' { $assertResourcePropertyParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv6' + AddressFamily = 'IPv6' } $errorRecord = Get-InvalidArgumentRecord ` - -Message ($script:localizedData.AddressIPv4MismatchError -f $assertResourcePropertyParameters.Address,$assertResourcePropertyParameters.AddressFamily) ` + -Message ($script:localizedData.AddressIPv4MismatchError -f $assertResourcePropertyParameters.Address, $assertResourcePropertyParameters.AddressFamily) ` -ArgumentName 'AddressFamily' { Assert-ResourceProperty @assertResourcePropertyParameters } | Should -Throw $ErrorRecord } } - Context 'Invoking with IPv6 Address and family mismatch' { + Context 'When invoking with IPv6 Address and family mismatch' { It 'Should throw an AddressMismatchError error' { $assertResourcePropertyParameters = @{ - Address = 'fe80::' + Address = 'fe80::' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } $errorRecord = Get-InvalidArgumentRecord ` - -Message ($script:localizedData.AddressIPv6MismatchError -f $assertResourcePropertyParameters.Address,$assertResourcePropertyParameters.AddressFamily) ` + -Message ($script:localizedData.AddressIPv6MismatchError -f $assertResourcePropertyParameters.Address, $assertResourcePropertyParameters.AddressFamily) ` -ArgumentName 'AddressFamily' { Assert-ResourceProperty @assertResourcePropertyParameters } | Should -Throw $ErrorRecord } } - Context 'Invoking with valid IPv4 Address' { + Context 'When invoking with valid IPv4 Address' { It 'Should not throw an error' { $assertResourcePropertyParameters = @{ - Address = '192.168.0.1' + Address = '192.168.0.1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv4' + AddressFamily = 'IPv4' } { Assert-ResourceProperty @assertResourcePropertyParameters } | Should -Not -Throw } } - Context 'Invoking with valid IPv6 Address' { + Context 'When invoking with valid IPv6 Address' { It 'Should not throw an error' { $assertResourcePropertyParameters = @{ - Address = 'fe80:ab04:30F5:002b::1' + Address = 'fe80:ab04:30F5:002b::1' InterfaceAlias = 'Ethernet' - AddressFamily = 'IPv6' + AddressFamily = 'IPv6' } { Assert-ResourceProperty @assertResourcePropertyParameters } | Should -Not -Throw } } } + + Describe 'MSFT_DefaultGatewayAddress\Get-NetDefaultGatewayDestinationPrefix' { + Context 'When the AddressFamily is IPv4' { + It 'Should return current default gateway' { + Get-NetDefaultGatewayDestinationPrefix -AddressFamily 'IPv4' | Should -Be '0.0.0.0/0' + } + } + + Context 'When the AddressFamily is IPv6' { + It 'Should return current default gateway' { + Get-NetDefaultGatewayDestinationPrefix -AddressFamily 'IPv6' | Should -Be '::/0' + } + } + } + + Describe 'MSFT_DefaultGatewayAddress\Get-NetDefaultRoute' { + Context 'When interface has a default gateway set' { + Mock -CommandName Get-NetRoute -MockWith { + [PSCustomObject] @{ + NextHop = '192.168.0.1' + DestinationPrefix = '0.0.0.0/0' + InterfaceAlias = 'Ethernet' + InterfaceIndex = 1 + AddressFamily = 'IPv4' + } + } + + It 'Should return current default gateway' { + $GetNetDefaultRouteParameters = @{ + InterfaceAlias = 'Ethernet' + AddressFamily = 'IPv4' + } + + $result = Get-NetDefaultRoute @GetNetDefaultRouteParameters + + $result.NextHop | Should -Be '192.168.0.1' + } + } + + Context 'When interface has no default gateway set' { + Mock -CommandName Get-NetRoute -MockWith { } + + It 'Should return no default gateway' { + $GetNetDefaultRouteParameters = @{ + InterfaceAlias = 'Ethernet' + AddressFamily = 'IPv4' + } + + $result = Get-NetDefaultRoute @GetNetDefaultRouteParameters + + $result | Should -BeNullOrEmpty + } + } + } } #end InModuleScope $DSCResourceName } finally