Creating a Custom DSC Resource to Configure Jumbo Frames on Network Cards

Recently while working on configuring a new server with DSC (Desired State Configuration), I discovered that there wasn't a DSC resource for configuring the jumbo frames setting on network cards so I decided to write my own.

This blog article steps you through the process of creating a custom DSC resource, specifically one that is used to configure the jumbo frames setting on network cards. The specific settings for jumbo frames can vary depending on your network card manufacturer and the specific driver. I believe that I've narrowed down the settings so this resource should work on all network cards/drivers that support jumbo frames. I've seen some drivers that don't support jumbo frames in the past, but I'm yet to find one to test this resource on so I can add additional code to check to see if jumbo frames is even supported.

Use this DSC resource at your own risk.

The workstation used in this scenario is running Windows 8.1 and the server is running Windows Server 2012 R2 and they are both a member of the same domain. Both are running PowerShell version 4 which ships in the box with both of those operating systems.

First, download the xDscResourceDesigner PowerShell Module from the Microsoft Script Repository and while you're at it, why not use PowerShell to perform the actual download:

1Invoke-WebRequest -Uri 'https://gallery.technet.microsoft.com/scriptcenter/xDscResourceDesigne-Module-22eddb29/file/120244/1/xDSCResourceDesigner_1.1.1.zip' -OutFile 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -Verbose

dsc-resource1.jpg

Since the zip file was downloaded from the Internet, you'll need to unblock it:

1Unblock-File -Path 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -Verbose

dsc-resource2.jpg

As specified in the instructions, extract the contents of the downloaded file to a folder under $env:ProgramFiles\WindowsPowerShell\Modules.

Since the machine I'm using is running Windows 8.1 with PowerShell version 4 installed, I'll use a function I created a while back to accomplish the task of extracting the contents of the zip file to the specified folder:

1Unzip-File -File 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -Destination "$env:ProgramFiles\WindowsPowershell\Modules" -Verbose

dsc-resource3.jpg

My Unzip-File function can be downloaded from the Microsoft Script Repository.

If you happen to be running the Windows Management Framework 5.0 Preview September 2014 version, you can use the native Extract-Archive cmdlet instead:

1Expand-Archive -Path 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -DestinationPath "$env:ProgramFiles\WindowsPowershell\Modules" -Verbose

dsc-resource4.jpg

Now to create what I like to call the skeleton of your DSC resource:

1$InterfaceAlias = New-xDscResourceProperty Name InterfaceAlias Type String Attribute Key
2$Ensure = New-xDscResourceProperty Name Ensure Type String Attribute Write ValidateSet 'Absent', 'Present'
3New-xDscResource Name cJumboFrames -Property $InterfaceAlias, $Ensure -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames"

If you receive a strange error like this one:

dsc-resource5.jpg

Check the execution policy on the machine you're working on. Any setting other than "Restricted" should work. My recommendation is "RemoteSigned":

1Get-ExecutionPolicy
2Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force
3Get-ExecutionPolicy

dsc-resource6.jpg

Let's try that again now that the execution policy has been set to remote signed:

1$InterfaceAlias = New-xDscResourceProperty Name InterfaceAlias Type String Attribute Key
2$Ensure = New-xDscResourceProperty Name Ensure Type String Attribute Write ValidateSet 'Absent', 'Present'
3New-xDscResource Name cJumboFrames -Property $InterfaceAlias, $Ensure -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames"

dsc-resource7.jpg

Notice in the previous command, I added a prefix of "c" to the name of the JumboFrames DSC resource that I'm creating. That stands for "community".

Creating the "skeleton" could also be accomplished with a PowerShell one-liner. This time I'll also add the Verbose parameter so you can see the details of what's happening:

1New-xDscResource Name cJumboFrames -Property (
2    New-xDscResourceProperty Name InterfaceAlias Type String Attribute Key), (
3    New-xDscResourceProperty Name Ensure Type String Attribute Write ValidateSet 'Absent', 'Present'
4) -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames" -Verbose

dsc-resource8.jpg

That creates the directory structure, a PowerShell script module (psm1 file):

 1function Get-TargetResource
 2{
 3    [CmdletBinding()]
 4    [OutputType([System.Collections.Hashtable])]
 5    param
 6    (
 7        [parameter(Mandatory = $true)]
 8        [System.String]
 9        $InterfaceAlias
10    )
11
12    #Write-Verbose "Use this cmdlet to deliver information about command processing."
13
14    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
15
16
17    <#
18    $returnValue = @{
19        InterfaceAlias = [System.String]
20        Ensure = [System.String]
21    }
22
23    $returnValue
24    #>
25}
26
27
28function Set-TargetResource
29{
30    [CmdletBinding()]
31    param
32    (
33        [parameter(Mandatory = $true)]
34        [System.String]
35        $InterfaceAlias,
36
37        [ValidateSet("Absent","Present")]
38        [System.String]
39        $Ensure
40    )
41
42    #Write-Verbose "Use this cmdlet to deliver information about command processing."
43
44    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
45
46    #Include this line if the resource requires a system reboot.
47    #$global:DSCMachineStatus = 1
48
49
50}
51
52
53function Test-TargetResource
54{
55    [CmdletBinding()]
56    [OutputType([System.Boolean])]
57    param
58    (
59        [parameter(Mandatory = $true)]
60        [System.String]
61        $InterfaceAlias,
62
63        [ValidateSet("Absent","Present")]
64        [System.String]
65        $Ensure
66    )
67
68    #Write-Verbose "Use this cmdlet to deliver information about command processing."
69
70    #Write-Debug "Use this cmdlet to write debug information while troubleshooting."
71
72
73    <#
74    $result = [System.Boolean]
75
76    $result
77    #>
78}
79
80
81Export-ModuleMember -Function *-TargetResource

And a mof schema file:

1[ClassVersion("1.0.0.0"), FriendlyName("cJumboFrames")]
2class cJumboFrames : OMI_BaseResource
3{
4    [Key] String InterfaceAlias;
5    [Write, ValueMap{"Absent","Present"}, Values{"Absent","Present"}] String Ensure;
6};

Create a module manifest for the PowerShell module that was created in the previous step:

1New-ModuleManifest -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames\cJumboFrames.psd1" -Author 'Mike F Robbins' -CompanyName 'mikefrobbins.com' -RootModule 'cJumboFrames' -Description 'Module with DSC Resource for Jumbo Frames' -PowerShellVersion 4.0 -FunctionsToExport '*.TargetResource' -Verbose

dsc-resource9.jpg

You'll end up with this module manifest (psd1 file):

 1#
 2# Module manifest for module 'cJumboFrames'
 3#
 4# Generated by: Mike F Robbins
 5#
 6# Generated on: 10/1/2014
 7#
 8
 9@{
10
11# Script module or binary module file associated with this manifest.
12RootModule = 'cJumboFrames'
13
14# Version number of this module.
15ModuleVersion = '1.0'
16
17# ID used to uniquely identify this module
18GUID = '866d8b02-a207-4d3c-add3-70acd4df41a2'
19
20# Author of this module
21Author = 'Mike F Robbins'
22
23# Company or vendor of this module
24CompanyName = 'mikefrobbins.com'
25
26# Copyright statement for this module
27Copyright = '(c) 2014 Mike F Robbins. All rights reserved.'
28
29# Description of the functionality provided by this module
30Description = 'Module with DSC Resource for Jumbo Frames'
31
32# Minimum version of the Windows PowerShell engine required by this module
33PowerShellVersion = '4.0'
34
35# Name of the Windows PowerShell host required by this module
36# PowerShellHostName = ''
37
38# Minimum version of the Windows PowerShell host required by this module
39# PowerShellHostVersion = ''
40
41# Minimum version of Microsoft .NET Framework required by this module
42# DotNetFrameworkVersion = ''
43
44# Minimum version of the common language runtime (CLR) required by this module
45# CLRVersion = ''
46
47# Processor architecture (None, X86, Amd64) required by this module
48# ProcessorArchitecture = ''
49
50# Modules that must be imported into the global environment prior to importing this module
51# RequiredModules = @()
52
53# Assemblies that must be loaded prior to importing this module
54# RequiredAssemblies = @()
55
56# Script files (.ps1) that are run in the caller's environment prior to importing this module.
57# ScriptsToProcess = @()
58
59# Type files (.ps1xml) to be loaded when importing this module
60# TypesToProcess = @()
61
62# Format files (.ps1xml) to be loaded when importing this module
63# FormatsToProcess = @()
64
65# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
66# NestedModules = @()
67
68# Functions to export from this module
69FunctionsToExport = '*.TargetResource'
70
71# Cmdlets to export from this module
72CmdletsToExport = '*'
73
74# Variables to export from this module
75VariablesToExport = '*'
76
77# Aliases to export from this module
78AliasesToExport = '*'
79
80# List of all modules packaged with this module
81# ModuleList = @()
82
83# List of all files packaged with this module
84# FileList = @()
85
86# Private data to pass to the module specified in RootModule/ModuleToProcess
87# PrivateData = ''
88
89# HelpInfo URI of this module
90# HelpInfoURI = ''
91
92# Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
93# DefaultCommandPrefix = ''
94
95}

Make the necessary changes to the script module (psm1 file) to get, set, and test for the value of the jumbo frames settings on the specified network card:

 1#region Get Jumbo Frames Setting
 2function Get-TargetResource {
 3    [CmdletBinding()]
 4    [OutputType([Hashtable])]
 5    param (
 6        [Parameter(Mandatory)]
 7        [String]$InterfaceAlias
 8    )
 9
10    $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias |
11                       Where-Object RegistryKeyword -eq '*JumboPacket'
12
13    Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.'
14    [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue
15    [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500
16
17    $returnValue = @{
18        InterfaceAlias = $InterfaceAlias
19        Ensure = switch ($CurrentSettings.RegistryValue) {
20            $JumboPacket {'Present'}
21            $NormalPacket {'Absent'}
22        }
23    }
24
25    $returnValue
26}
27#endregion
28
29#region Set Jumbo Frames Setting
30function Set-TargetResource {
31    [CmdletBinding()]
32    param (
33        [Parameter(Mandatory)]
34        [String]$InterfaceAlias,
35
36        [Parameter(Mandatory)]
37        [ValidateSet('Absent','Present')]
38        [String]$Ensure
39    )
40
41    $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias |
42                       Where-Object RegistryKeyword -eq '*JumboPacket'
43
44    Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.'
45    [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue
46    [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500
47
48    switch ($Ensure) {
49        'Absent' {[int]$DesiredSetting = $NormalPacket}
50        'Present' {[int]$DesiredSetting = $JumboPacket}
51    }
52
53    if ($CurrentSettings.RegistryValue -ne $DesiredSetting -and $CurrentSettings.RegistryValue -ne $null) {
54        Set-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias -RegistryKeyword '*JumboPacket' -RegistryValue $DesiredSetting -PassThru
55    }
56
57}
58#endregion
59
60#region Test Jumbo Frames Setting
61function Test-TargetResource {
62    [CmdletBinding()]
63    [OutputType([Boolean])]
64    param (
65        [Parameter(Mandatory)]
66        [String]$InterfaceAlias,
67
68        [Parameter(Mandatory)]
69        [ValidateSet('Absent','Present')]
70        [String]$Ensure
71    )
72
73    $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias |
74                       Where-Object RegistryKeyword -eq '*JumboPacket'
75
76    Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.'
77    [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue
78    [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500
79
80    switch ($Ensure) {
81        'Absent' {[int]$DesiredSetting = $NormalPacket}
82        'Present' {[int]$DesiredSetting = $JumboPacket}
83    }
84
85    if ($CurrentSettings.RegistryValue -ne $DesiredSetting -and $CurrentSettings.RegistryValue -ne $null) {
86        Write-Verbose -Message "Jumbo Frames setting is Non-Compliant! Value should be $DesiredSetting - Detected value is: $($CurrentSettings.RegistryValue)."
87        [Boolean]$result = $false
88    }
89    elseif ($CurrentSettings.RegistryValue -eq $DesiredSetting) {
90        Write-Verbose -Message 'Jumbo Frames setting matches the desired state.'
91        [Boolean]$result = $true
92    }
93
94    $result
95}
96#endregion

The cJumboFrames resource needs to also exist on any servers where a DSC configuration will be applied that replies on this resource. There are several tutorials on the web for distributing a resource so I won't duplicate that content here. I've simply copied the cJumboFrames folder from the Windows 8.1 workstation I've been developing it on to the same location on the SQL02 server where I plan to apply a configuration that will use it.

Create a DSC configuration to test the custom cJumboFrames DSC resource:

 1configuration TestJumboFrames {
 2
 3    param (
 4        [Parameter(Mandatory)]
 5        [string[]]$ComputerName
 6    )
 7
 8    Import-DscResource -ModuleName cJumboFrames
 9
10    node $ComputerName {
11        cJumboFrames iSCSINIC {
12            InterfaceAlias = 'Ethernet 2'
13            Ensure = 'Present'
14        }
15    }
16}

Run the configuration, specifying SQL02 as the computer name. This creates a mof configuration file that is specific to the SQL02 test server.

1TestJumboFrames -ComputerName SQL02

dsc-resource10.jpg

Before applying the configuration, let's check the current jumbo frames setting on SQL02:

1Invoke-Command -ComputerName SQL02 {
2    Get-NetAdapterAdvancedProperty -InterfaceAlias 'Ethernet 2' |
3    Where-Object RegistryKeyword -eq '*JumboPacket'
4}

dsc-resource11.jpg

As shown in the previous results, we can see that the network card is set to a standard packet size of 1514 bytes.

Now to apply the DSC configuration that we previously created to SQL02:

1Start-DscConfiguration -ComputerName SQL02 -Path .\TestJumboFrames -Wait -Verbose

dsc-resource12.jpg

Check the jumbo frames settings again now that the configuration has been applied:

1Invoke-Command -ComputerName SQL02 {
2    Get-NetAdapterAdvancedProperty -InterfaceAlias 'Ethernet 2' |
3    Where-Object RegistryKeyword -eq '*JumboPacket'
4}

dsc-resource13.jpg

You can see that jumbo frames have been enabled for that network card and the maximum packet size is now set to 9014 bytes.

I also want to show you the jumbo frames settings from another Windows Server 2012 R2 machine that has a network card produced by a different manufacturer. This should help you to understand why I wrote the code in the script module the way I did:

1Invoke-Command -ComputerName SQL01 {
2    Get-NetAdapterAdvancedProperty -InterfaceAlias 'NIC1' |
3    Where-Object RegistryKeyword -eq '*JumboPacket'
4}

dsc-resource14.jpg

µ