PowerShell Version 2 Compatible Function to Determine Windows Firewall State
I recently had a need to perform some security auditing on an environment that still has some servers running PowerShell version 2 (PowerShell version 2 is deprecated). One of the things I needed to determine was whether or not the Windows firewall was enabled on each of the servers in the environment. Luckily, all of the servers at least had PowerShell remoting enabled.
1#Requires -Version 2.0
2function Get-MrNetFirewallState {
3
4<#
5.SYNOPSIS
6 Displays the per-profile state of the Windows Firewall.
7
8.DESCRIPTION
9 The Get-MrNetFirewallState function displays the current firewall state for the Domain, Private, and Public profiles.
10
11.PARAMETER ComputerName
12 The name of the computer(s) to retrieve the firewall state for.
13
14.PARAMETER Credential
15 Specifies a user account that has permission to perform this action. The default is the current user.
16
17.EXAMPLE
18 Get-MrNetFirewallState
19
20.EXAMPLE
21 Get-MrNetFirewallState -ComputerName Server01, Server02
22
23.EXAMPLE
24 Get-MrNetFirewallState -ComputerName Server01, Server02 -Credential (Get-Credential)
25
26.INPUTS
27 None
28
29.OUTPUTS
30 PSCustomObject
31
32.NOTES
33 Author: Mike F Robbins
34 Website: http://mikefrobbins.com
35 Twitter: @mikefrobbins
36#>
37
38 [CmdletBinding()]
39 param (
40 [ValidateNotNullOrEmpty()]
41 [string[]]$ComputerName = $env:COMPUTERNAME,
42
43 [System.Management.Automation.Credential()]$Credential = [System.Management.Automation.PSCredential]::Empty
44 )
45
46 $ScriptBlock =
47@'
48 $Results = netsh.exe advfirewall show allprofiles | Select-String -SimpleMatch Profile, State
49
50 for ($i = 0; $i -lt 6; $i += 2) {
51 New-Object PSObject -Property @{
52 ComputerName = $env:COMPUTERNAME
53 Name = ($Results[$i] | Select-String -SimpleMatch 'Profile Settings') -replace '^*.Profile Settings:'
54 Enabled = if ($Results[$i+1] -match 'ON') {
55 $true
56 }
57 else {
58 $false
59 }
60 }
61 }
62'@
63
64 $Params = @{
65 Scriptblock = [Scriptblock]::Create($ScriptBlock)
66 }
67
68 if ($ComputerName -ne $env:COMPUTERNAME) {
69
70 $Params.ComputerName = $ComputerName
71 $Params.ErrorAction = 'SilentlyContinue'
72 $Params.ErrorVariable = 'Problem'
73
74 if ($PSBoundParameters.Credential) {
75 $Params.Credential = $Credential
76 }
77
78 Invoke-Command @Params | Select-Object -Property ComputerName, Name, Enabled
79
80 foreach ($p in $Problem) {
81 if ($p.FullyQualifiedErrorId -match 'AccessDenied|LogonFailure') {
82 Write-Warning -Message "Access Denied when trying to connect to $($p.TargetObject)"
83 }
84 elseif ($p.FullyQualifiedErrorId -match 'NetworkPathNotFound') {
85 Write-Warning -Message "Unable to connect to $($p.targetobject)"
86 }
87 else {
88 Write-Warning -Message "An unexpected error has occurred when trying to connect to $($p.targetobject)"
89 }
90 }
91
92 }
93 else {
94 $Params.ScriptBlock.Invoke()
95 }
96
97}
The PowerShell function shown in the previous code example is a wrapper for the Netsh.exe
command.
The commands that are going to be executed are stored in a here-string and then converted to a
script block within the parameters hash table. It uses Invoke-Command
to execute Netsh
on the
remote servers and them uses Select-String
to parse down the data to only the lines that are
necessary. The results are turned into a usable custom object in a For
loop that uses
Select-String
again to parse out some of the unnecessary information from each of the remaining
lines. If the credential parameter is specified, it's also added to the parameters hash table.
Splatting is used with Invoke-Command
.
Custom error handling has been added to allow the function to take advantage of running against
multiple computers at the same time via Invoke-Command
while providing the user with feedback when
errors occur such as being unable to connect to the remote computer.
I found that two different errors (access denied and logon failure) can be returned which both mean
access denied. During the last few months, I've performed a technical technical review on the
"Windows Server 2016 Automation with PowerShell Cookbook". Based on reviewing
Thomas Lee's PowerShell code, I learned that the Match
operator
can be used similarly to the Like
operator except without the need to specify wildcard characters.
I had previously only used it when I needed to specify a regular expression.
If you're going to use the GroupBy
parameter of Format-Table
, you have to sort by that property
first.
1Get-MrNetFirewallState -ComputerName FS1, FS2, SRV1, SRV2 |
2Sort-Object -Property ComputerName |
3Format-Table -GroupBy ComputerName
If the function is run against the local computer, the script block is simply invoked. While this doesn't cover all scenarios where the local computer could be specified, it's a great option for testing against a local computer where PowerShell remoting isn't enabled.
1Get-MrNetFirewallState
This task is much easier to accomplish with newer versions of PowerShell using the
Get-NetFirewallProfile
cmdlet which was introduced in PowerShell version 3.0.
1Get-NetFirewallProfile -CimSession fs1, fs2, srv1, srv2 |
2Sort-Object -Property PSComputerName |
3Format-Table -Property PSComputerName, Name, Enabled -GroupBy PSComputerName
Here's a bonus tip: Even though commands such as Get-NetFirewallProfile
don't have a
ComputerName
parameter, a computer name can be specified with the CimSession
parameter without
needing to first create a CIM session. A CIM session will automatically be created behind the scenes
using the WSMan protocol and then it will be automatically removed once the command completes (a
special thanks to Richard Siddaway for clarifying this for me a few
weeks ago).
The Get-MrNetFirewallState
function shown in this blog article can be downloaded from
my PowerShell repository on GitHub.
µ