PowerShell DSC 101: Using the Script Resource to Enable the Windows Firewall

imageLearning PowerShell Desired State Configuration

PowerShell DSC is one of my favorite topics to teach, because the technology is simply amazing. Usually I do not have enough time with a customer to teach all of the built-in resources. I would guess that the Script resource is one of the least understood. Today’s post outlines a simple example to enable the Windows Firewall. This sample will work on Windows Server 2008 R2 and above.

Automating Your Server Build Sheet

Last week I was on site with a customer doing a PS DSC POC (PowerShell Desired State Configuration Proof of Concept). We took their server build check sheet, identified DSC resources for each step, and then began converting their manual server config process into PowerShell DSC.

The customer was new to DSC and requested a sample of how they could use the built-in Script resource. One of the items on the build sheet was to make sure the Windows Firewall was turned on. This was the perfect opportunity for a Script resource example.

The Script Resource

When you cannot find a built-in DSC resource or community resource to do what you need you have two options for custom resource code:

  1. Built-In Script Resource – if the code is relatively simple, maybe just a couple lines
  2. Custom Resource – if the code requires complexities like helper functions, extensive variable use, etc.

The primary decision factor between these two is the level of effort and complexity required. If you can do it in a couple lines of code, then try using a Script resource first. If the code is more involved, then write a custom resource. Obviously a script resource is much less effort if you can get by with it.

In the case of the firewall example, there is a community resource xDSCFirewall that might suffice, but it does not work on Windows Server 2008 R2.

Script Resource Firewall Example

Here is an elegantly simple use of the Script resource. We could make it more complex in many ways, but I prefer to start out with a simple use case first. The code is its own documentation. Study it carefully.

 Configuration FirewallScriptResource            
{            
    Import-DscResource -ModuleName PSDesiredStateConfiguration            
    Node localhost            
    {            
        Script EnableFirewall            
        {            
            # Must return a hashtable with at least one key            
            # named 'Result' of type String            
            GetScript = {            
                Return @{            
                    Result = [string]$(netsh advfirewall show allprofiles)            
                }            
            }            
            
            # Must return a boolean: $true or $false            
            TestScript = {            
                If ((netsh advfirewall show allprofiles) -like "State*off*") {            
                    Write-Verbose "One or more firewall profiles are off"            
                    Return $false            
                } Else {            
                    Write-Verbose "All firewall profiles are on"            
                    Return $true            
                }            
            }            
            
            # Returns nothing            
            SetScript = {            
                Write-Verbose "Setting all firewall profiles to on"            
                netsh advfirewall set allprofiles state on            
            }            
        }            
    }            
}            
            
FirewallScriptResource            
            
Start-DscConfiguration -Path .\FirewallScriptResource -Wait -Verbose            
            
Get-DscConfiguration            

Notice the Write-Verbose statements. These are important for logging and output when the resource runs.

Notice that the GetScript, TestScript, and SetScript do not use a variable (except $true and $false). You could use custom variables in this code, for example, to reference parameters. See Example 2 of the Script resource documentation for how to use the $using: prefix with variables in a Script resource.

Take it to the next level.

There are many directions you could take this example:

  • Add a parameter for Enable vs. Disable.
  • Add a parameter for a specific firewall profile.
  • Filter the output of NETSH to only show the profile status portion (netsh advfirewall show allprofiles | Where-Object {$_ -like '*Profile*' -or $_ -like 'State*'})
  • Put the script resource into a composite resource to hide the Get/Test/Set code and keep your config looking clean.

Your Turn

Now it is your turn. Take this sample and implement your own script resources. Leave a comment below telling what you accomplished.

Best wishes on your adventure learning DSC!