Configure the firewall profile with DSC (Part 2)

The 2nd part deals with the classic way of creating custom DSC resources.
To help demo that, there’s actually an xDSCResourceDesginer module available in the PowerShell Gallery (a.k.a. PSGallery).

Here’s what I run if it’s not installed

# 1. Get the module and load it
Find-Module -Name xDSCResourceDesigner -Repository PsGallery -Verbose
Install-Module -Name xDSCResourceDesigner -Repository PsGallery -Verbose
Import-Module -Name xDSCResourceDesigner -Force -Verbose

There are only a few steps required to get started

# 2. Create the resource
$resource = @{
    Name = 'cFirewallProfile';
    Property  = (New-xDscResourceProperty -Name 'Name' -Type 'String' -Attribute = 'Key' -ValidateSet 'Domain','Public','Private'),
                (New-xDscResourceProperty -Name "Enabled" -Type "String" -Attribute Required -ValidateSet 'True','False','NotConfigured'),
                (New-xDscResourceProperty -Name DefaultInboundAction -Type "String" -Attribute Required -ValidateSet 'Allow','Block','NotConfigured'),
                (New-xDscResourceProperty -Name DefaultOutboundAction -Type "String" -Attribute Required -ValidateSet 'Allow','Block','NotConfigured')
    Path = 'C:\Program Files\WindowsPowerShell\Modules\cFirewallProfile';
    ClassVersion = '1.0' ;
    FriendlyName = 'cFirewallProfile' ;
    Force = $true ;
}
New-xDscResource @resource

# 3. Create its manifest
$Manifest = @{
    Path = 'C:\Program Files\WindowsPowerShell\Modules\cFirewallProfile\cFirewallProfile.psd1'
    Guid = ([guid]::NewGuid().Guid) ;
    Author  = 'Emin Atac' ;
    CompanyName  = 'Emin Atac'
    Copyright = 'Free to use'
    ModuleVersion = '1.0.0'
    PowerShellVersion = '4.0'
    FunctionsToExport = 'Get-TargetResource','Test-TargetResource','Set-TargetResource'
}
New-ModuleManifest @Manifest -Verbose

# 4. Ready to edit the resource
psedit 'C:\Program Files\WindowsPowerShell\Modules\cFirewallProfile\DSCResources\cFirewallProfile\cFirewallProfile.psm1'

All the parameters of the 3 functions have been populated automatically thanks to the New-xDscResource and New-xDscResourceProperty cmdlets and we only have to focus and create the body of these functions. Nice isn’t it?

Here’s what to paste inside the cFirewallProfile.psm1 file.

Function Get-TargetResource {
[CmdletBinding()]
[OutputType([Hashtable])]
Param (
[parameter(Mandatory)]
[ValidateSet('Domain','Public','Private')]
[String]$Name,
[parameter(Mandatory)]
[ValidateSet('True','False','NotConfigured')]
[String]$Enabled,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultInboundAction,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultOutboundAction
)
$p = Get-NetFirewallProfile -Name $Name
@{
Name = $p.Name ;
Enabled = $p.Enabled ;
DefaultInboundAction = $p.DefaultInboundAction ;
DefaultOutboundAction = $p.DefaultOutboundAction ;
}
}
Function Set-TargetResource {
[CmdletBinding()]
Param (
[parameter(Mandatory)]
[ValidateSet('Domain','Public','Private')]
[String]$Name,
[parameter(Mandatory)]
[ValidateSet('True','False','NotConfigured')]
[String]$Enabled,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultInboundAction,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultOutboundAction
)
Write-Verbose "Configuring Firewall Profile $($Name) to $($Enabled)"
Write-Verbose "Setting Firewall Profile $($Name) DefaultInboundAction to $($DefaultInboundAction)"
Write-Verbose "Setting Firewall Profile $($Name) DefaultOutboundAction to $($DefaultOutboundAction)"
Set-NetFirewallProfile @PSBoundParameters
}
Function Test-TargetResource {
[CmdletBinding()]
[OutputType([System.Boolean])]
Param (
[parameter(Mandatory)]
[ValidateSet('Domain','Public','Private')]
[String]$Name,
[parameter(Mandatory)]
[ValidateSet('True','False','NotConfigured')]
[String]$Enabled,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultInboundAction,
[parameter(Mandatory)]
[ValidateSet('Allow','Block','NotConfigured')]
[String]$DefaultOutboundAction
)
$current = Get-TargetResource @PSBoundParameters
$result = $true
if ($current.Enabled -ne $Enabled) {
$result = $false
}
if ($current.DefaultInboundAction -ne $DefaultInboundAction) {
$result = $false
}
if ($current.DefaultOutboundAction -ne $DefaultOutboundAction) {
$result = $false
}
$result
}
Export-ModuleMember -Function *-TargetResource

Now, I can use the above custom DSC resource to configure the firewall profiles:

Configuration TestFirewallProfileConfig {

    Param (
        [string[]]$NodeName = 'localhost'
    )

    Import-DscResource -Name * -ModuleName 'cFirewallProfile';

    Node $NodeName
    {
        Foreach ($fw in @('Domain','Public','Private'))
        {
            cFirewallProfile "$($fw)"
            {
                Name = "$($fw)"
                Enabled = 'True'
                DefaultInboundAction = 'Block' ;
                DefaultOutboundAction = 'Allow' ;
            }
        }
    }
}

The last step consists in compiling the configuration into a MOF file and applying it like this:

if (-not(test-path -Path C:\DSC -PathType Container)){
    mkdir C:\DSC
}
# Compile into MOF file
TestFirewallProfileConfig -OutputPath C:\DSC 

# Apply
Start-DscConfiguration -Path C:\DSC -ComputerName localhost -Verbose -Force -Wait

To be able to test it, I’ll set the exact opposite way I want it to be. Don’t do that on a production server.

Set-NetFirewallProfile -All -DefaultInboundAction Allow -DefaultOutboundAction Block  -Enabled false

WF.off

When I apply the configuration, we can see all the 3 profiles being configured:
WF-first-config

If I ask whether the system is in its desired state with the Test-DscConfiguration cmdlet, I get:
WF-test-config-01
If I refresh the wf.msc MMC snap-in I’ve actually restored back the defaults thanks to my DSC configuration.
WF-back-to-defaults

Let’s say I only mess up the Domain profile.
WF-test-config-modified

When I (re)apply the configuration, there’s only one profile that is being reconfigured before the Test-DscConfiguration cmdlet tells me it’s compliant again 😀

WF-test-config-02

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.