Tests/Unit/MSFT_xFirewall.Tests.ps1
$DSCResourceName = 'MSFT_xFirewall' $DSCModuleName = 'xNetworking' $Splat = @{ Path = $PSScriptRoot ChildPath = "..\..\DSCResources\$DSCResourceName\$DSCResourceName.psm1" Resolve = $true ErrorAction = 'Stop' } $DSCResourceModuleFile = Get-Item -Path (Join-Path @Splat) $moduleRoot = "${env:ProgramFiles}\WindowsPowerShell\Modules\$DSCModuleName" if(-not (Test-Path -Path $moduleRoot)) { $null = New-Item -Path $moduleRoot -ItemType Directory } else { # Copy the existing folder out to the temp directory to hold until the end of the run # Delete the folder to remove the old files. $tempLocation = Join-Path -Path $env:Temp -ChildPath $DSCModuleName Copy-Item -Path $moduleRoot -Destination $tempLocation -Recurse -Force Remove-Item -Path $moduleRoot -Recurse -Force $null = New-Item -Path $moduleRoot -ItemType Directory } Copy-Item -Path $PSScriptRoot\..\..\* -Destination $moduleRoot -Recurse -Force -Exclude '.git' if (Get-Module -Name $DSCResourceName) { Remove-Module -Name $DSCResourceName } Import-Module -Name $DSCResourceModuleFile.FullName -Force InModuleScope $DSCResourceName { ###################################################################################### Describe 'Get-TargetResource' { Context 'Absent should return correctly' { Mock Get-NetFirewallRule It 'Should return absent' { $result = Get-TargetResource -Name 'FirewallRule' $result.Name | Should Be 'FirewallRule' $result.Ensure | Should Be 'Absent' } } Context 'Present should return correctly' { $rule = Get-NetFirewallRule | Sort-Object Name | Where-Object {$_.DisplayGroup -ne $null} | Select-Object -first 1 $ruleProperties = Get-FirewallRuleProperty $rule $result = Get-TargetResource -Name $rule.Name It 'should have the correct DisplayName and type' { $result.DisplayName | Should Be $rule.DisplayName $result.DisplayName.GetType() | Should Be $rule.DisplayName.GetType() } It 'Should have the correct Group and type' { $result.Group | Should Be $rule.Group $result.Group.GetType() | Should Be $rule.Group.GetType() } It 'Should have the correct DisplayGroup and type' { $result.DisplayGroup | Should Be $rule.DisplayGroup $result.DisplayGroup.GetType() | Should Be $rule.DisplayGroup.GetType() } It 'Should have the correct Profile' { $result.Profile[0] | Should Be ($rule.Profile.ToString() -replace(' ', '') -split(','))[0] } It 'Should have the correct Direction and type' { $result.Direction | Should Be $rule.Direction $result.Direction.GetType() | Should Be $rule.Direction.GetType() } It 'Should have the correct Description and type' { $result.Description | Should Be $rule.Description $result.Description.GetType() | Should Be $rule.Description.GetType() } It 'Should have the correct RemotePort and type' { $result.RemotePort | Should Be $ruleProperties.PortFilters.RemotePort } It 'Should have the correct Action' { $result.Action | Should Be $rule.Action } It 'Should have the correct LocalPort and type' { $result.LocalPort | Should Be $ruleProperties.PortFilters.LocalPort } It 'Should have the correct Protocol and type' { $result.Protocol | Should Be $ruleProperties.PortFilters.Protocol } It 'Should have the correct ApplicationPath and type' { $result.ApplicationPath | Should Be $ruleProperties.ApplicationFilters.Program } It 'Should have the correct Service and type' { $result.Service | Should Be $ruleProperties.ServiceFilters.Service } } } ###################################################################################### Describe 'Test-TargetResource' { $rule = Get-NetFirewallRule | ` Where-Object {$_.DisplayName -ne $null} | ` Select-Object -first 1 Context 'Ensure is Absent and the Firewall is not Present' { Mock Get-FirewallRule It 'should return $true' { $result = Test-TargetResource -Name 'FirewallRule' -Ensure 'Absent' $result | Should Be $true } } Context 'Ensure is Absent and the Firewall is Present' { Mock Test-RuleProperties It 'should return $false' { $result = Test-TargetResource -Name $rule.Name -Ensure 'Absent' $result | Should Be $false } } Context 'Ensure is Present and the Firewall is Present and properties match' { Mock Test-RuleProperties -MockWith { return $true } It 'should return $true' { $result = Test-TargetResource -Name $rule.Name $result | Should Be $true } } Context 'Ensure is Present and the Firewall is Present and properties are different' { Mock Test-RuleProperties -MockWith { return $false } It 'should return $false' { $result = Test-TargetResource -Name $rule.Name $result | Should Be $false } } Context 'Ensure is Present and the Firewall is Absent' { It 'should return $false' { $result = Test-TargetResource -Name $rule.Name $result | Should Be $false } } } ###################################################################################### Describe 'Set-TargetResource' { $rule = Get-NetFirewallRule | Where-Object {$_.DisplayName -ne $null} | Select-Object -First 1 Context 'Ensure is Absent and Firewall Exist' { It "should call expected mocks on firewall rule $($rule.Name)" { Mock Remove-NetFirewallRule $result = Set-TargetResource -Name $rule.Name -Ensure 'Absent' Assert-MockCalled Remove-NetFirewallRule -Exactly 1 } } Context 'Ensure is Absent and the Firewall Does Not Exist' { It "should call expected mocks on firewall rule $($rule.Name)" { Mock Get-FirewallRule Mock Remove-NetFirewallRule $result = Set-TargetResource -Name $rule.Name -Ensure 'Absent' Assert-MockCalled Remove-NetFirewallRule -Exactly 0 } } Context 'Ensure is Present and the Firewall Does Not Exist' { It "should call expected mocks on firewall rule $($rule.Name)" { Mock Get-FirewallRule Mock New-NetFirewallRule $result = Set-TargetResource -Name $rule.Name -Ensure 'Present' Assert-MockCalled New-NetFirewallRule -Exactly 1 Assert-MockCalled Get-FirewallRule -Exactly 1 } } Context 'Ensure is Present and the Firewall Does Exist but is different' { It "should call expected mocks on firewall rule $($rule.Name)" { Mock Set-NetFirewallRule Mock Test-RuleProperties {return $false} $result = Set-TargetResource -Name $rule.Name -Ensure 'Present' Assert-MockCalled Set-NetFirewallRule -Exactly 1 Assert-MockCalled Test-RuleProperties -Exactly 1 } } Context 'Ensure is Present and the Firewall Does Exist and is the same' { It "should call expected mocks on firewall rule $($rule.Name)" { Mock Set-NetFirewallRule Mock Test-RuleProperties {return $true} $result = Set-TargetResource -Name $rule.Name -Ensure 'Present' Assert-MockCalled Set-NetFirewallRule -Exactly 0 Assert-MockCalled Test-RuleProperties -Exactly 1 } } } ###################################################################################### Describe 'Test-RuleProperties' { $rule = Get-NetFirewallRule | Where-Object {$_.DisplayName -ne $null} | Select-Object -First 1 $FirewallRule = Get-FirewallRule -Name $rule.name $Properties = Get-FirewallRuleProperty -FirewallRule $FirewallRule # Make an object that can be splatted onto the function $Splat = @{ Name = $FirewallRule.Name DisplayGroup = $FirewallRule.DisplayGroup Enabled = $FirewallRule.Enabled Profile = $FirewallRule.Profile.ToString() -replace(' ', '') -split(',') Direction = $FirewallRule.Direction Action = $FirewallRule.Action RemotePort = $Properties.PortFilters.RemotePort LocalPort = $Properties.PortFilters.LocalPort Protocol = $Properties.PortFilters.Protocol Description = $FirewallRule.Description ApplicationPath = $Properties.ApplicationFilters.Program Service = $Properties.ServiceFilters.Service } # To speed up all these tests create Mocks so that these functions are not repeatedly called Mock Get-FirewallRule -MockWith { $FirewallRule } Mock Get-FirewallRuleProperty -MockWith { $Properties } Context 'testing with a rule with no property differences' { $CompareRule = $Splat.Clone() It 'should return True' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $True } } Context 'testing with a rule with a different name' { $CompareRule = $Splat.Clone() $CompareRule.Name = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different enabled' { $CompareRule = $Splat.Clone() $CompareRule.Enabled = if( $CompareRule.Enabled -eq 'True' ) {'False'} Else {'True'} It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different action' { $CompareRule = $Splat.Clone() $CompareRule.Action = if ($CompareRule.Action -eq 'Allow') {'Block'} else {'Allow'} It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different profile' { $CompareRule = $Splat.Clone() $CompareRule.Profile = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different direction' { $CompareRule = $Splat.Clone() $CompareRule.Direction = if ($CompareRule.Direction -eq 'Inbound') {'Outbound'} else {'Inbound'} It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different remote port' { $CompareRule = $Splat.Clone() $CompareRule.RemotePort = 1 It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different local port' { $CompareRule = $Splat.Clone() $CompareRule.LocalPort = 1 It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different protocol' { $CompareRule = $Splat.Clone() $CompareRule.Protocol = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different description' { $CompareRule = $Splat.Clone() $CompareRule.Description = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different application path' { $CompareRule = $Splat.Clone() $CompareRule.ApplicationPath = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } Context 'testing with a rule with a different description' { $CompareRule = $Splat.Clone() $CompareRule.Service = 'Different' It 'should return False' { $Result = Test-RuleProperties -FirewallRule $FirewallRule @CompareRule $Result | Should be $False } } } ###################################################################################### Describe ' Get-FirewallRule' { $rule = Get-NetFirewallRule | Select-Object -First 1 $rules = Get-NetFirewallRule | Select-Object -First 2 Context 'testing with firewall that exists' { It 'should return a firewall rule when name is passed' { $Result = Get-FirewallRule -Name $rule.Name $Result | Should Not BeNullOrEmpty } } Context 'testing with firewall that does not exist' { It 'should not return anything' { $Result = Get-FirewallRule -Name 'Does not exist' $Result | Should BeNullOrEmpty } } Context 'testing with firewall that somehow occurs more than once' { Mock Get-NetFirewallRule -MockWith { $rules } $errorId = 'RuleNotUnique' $errorCategory = [System.Management.Automation.ErrorCategory]::InvalidOperation $errorMessage = $($LocalizedData.RuleNotUniqueError) -f 2,$rule.Name $exception = New-Object -TypeName System.InvalidOperationException ` -ArgumentList $errorMessage $errorRecord = New-Object -TypeName System.Management.Automation.ErrorRecord ` -ArgumentList $exception, $errorId, $errorCategory, $null It 'should throw RuleNotUnique exception' { { $Result = Get-FirewallRule -Name $rule.Name } | Should Throw $errorRecord } } } ###################################################################################### Describe 'Get-FirewallRuleProperty' { $rule = Get-NetFirewallRule | Where-Object {$_.DisplayName -ne $null} | Select-Object -First 1 Context 'All Properties' { $result = Get-FirewallRuleProperty -FirewallRule $rule It 'Should return the right address filter' { $expected = Get-NetFirewallAddressFilter -AssociatedNetFirewallRule $rule $($result.AddressFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right application filter' { $expected = Get-NetFirewallApplicationFilter -AssociatedNetFirewallRule $rule $($result.ApplicationFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right interface filter' { $expected = Get-NetFirewallInterfaceFilter -AssociatedNetFirewallRule $rule $($result.InterfaceFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right interface type filter' { $expected = Get-NetFirewallInterfaceTypeFilter -AssociatedNetFirewallRule $rule $($result.InterfaceTypeFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right port filter' { $expected = Get-NetFirewallPortFilter -AssociatedNetFirewallRule $rule $($result.PortFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right Profile' { $expected = Get-NetFirewallProfile -AssociatedNetFirewallRule $rule $($result.Profile | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right Profile' { $expected = Get-NetFirewallProfile -AssociatedNetFirewallRule $rule $($result.Profile | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right Security Filters' { $expected = Get-NetFirewallSecurityFilter -AssociatedNetFirewallRule $rule $($result.SecurityFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } It 'Should return the right Service Filters' { $expected = Get-NetFirewallServiceFilter -AssociatedNetFirewallRule $rule $($result.ServiceFilters | Out-String -Stream) | Should Be $($expected | Out-String -Stream) } } } ###################################################################################### } # Clean up after the test completes. Remove-Item -Path $moduleRoot -Recurse -Force # Restore previous versions, if it exists. if ($tempLocation) { $null = New-Item -Path $moduleRoot -ItemType Directory $script:Destination = "${env:ProgramFiles}\WindowsPowerShell\Modules" Copy-Item -Path $tempLocation -Destination $script:Destination -Recurse -Force Remove-Item -Path $tempLocation -Recurse -Force } |