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.
Consider this DSC resource to be beta and use it at your own risk <period>.
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:
1 | Invoke-WebRequest -Uri 'http://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 |
Since the zip file was downloaded from the Internet, you’ll need to unblock it:
1 | Unblock-File -Path 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -Verbose |
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:
1 | Unzip-File -File 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -Destination "$env:ProgramFiles\WindowsPowershell\Modules" -Verbose |
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:
1 | Expand-Archive -Path 'C:\tmp\xDSCResourceDesigner_1.1.1.zip' -DestinationPath "$env:ProgramFiles\WindowsPowershell\Modules" -Verbose |
Now to create what I like to call the skeleton of your DSC resource:
1 2 3 | $InterfaceAlias = New-xDscResourceProperty –Name InterfaceAlias –Type String –Attribute Key $Ensure = New-xDscResourceProperty –Name Ensure –Type String –Attribute Write –ValidateSet 'Absent', 'Present' New-xDscResource –Name cJumboFrames -Property $InterfaceAlias, $Ensure -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames" |
If you receive a strange error like this one:
Check the execution policy on the machine you’re working on. Any setting other than “Restricted” should work. My recommendation is “RemoteSigned”:
1 2 3 | Get-ExecutionPolicy Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force Get-ExecutionPolicy |
Let’s try that again now that the execution policy has been set to remote signed:
1 2 3 | $InterfaceAlias = New-xDscResourceProperty –Name InterfaceAlias –Type String –Attribute Key $Ensure = New-xDscResourceProperty –Name Ensure –Type String –Attribute Write –ValidateSet 'Absent', 'Present' New-xDscResource –Name cJumboFrames -Property $InterfaceAlias, $Ensure -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames" |
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:
1 2 3 4 | New-xDscResource –Name cJumboFrames -Property ( New-xDscResourceProperty –Name InterfaceAlias –Type String –Attribute Key), ( New-xDscResourceProperty –Name Ensure –Type String –Attribute Write –ValidateSet 'Absent', 'Present' ) -Path "$env:ProgramFiles\WindowsPowershell\Modules\cJumboFrames" -Verbose |
That creates the directory structure, a PowerShell script module (psm1 file):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | function Get-TargetResource { [CmdletBinding()] [OutputType([System.Collections.Hashtable])] param ( [parameter(Mandatory = $true)] [System.String] $InterfaceAlias ) #Write-Verbose "Use this cmdlet to deliver information about command processing." #Write-Debug "Use this cmdlet to write debug information while troubleshooting." <# $returnValue = @{ InterfaceAlias = [System.String] Ensure = [System.String] } $returnValue #> } function Set-TargetResource { [CmdletBinding()] param ( [parameter(Mandatory = $true)] [System.String] $InterfaceAlias, [ValidateSet("Absent","Present")] [System.String] $Ensure ) #Write-Verbose "Use this cmdlet to deliver information about command processing." #Write-Debug "Use this cmdlet to write debug information while troubleshooting." #Include this line if the resource requires a system reboot. #$global:DSCMachineStatus = 1 } function Test-TargetResource { [CmdletBinding()] [OutputType([System.Boolean])] param ( [parameter(Mandatory = $true)] [System.String] $InterfaceAlias, [ValidateSet("Absent","Present")] [System.String] $Ensure ) #Write-Verbose "Use this cmdlet to deliver information about command processing." #Write-Debug "Use this cmdlet to write debug information while troubleshooting." <# $result = [System.Boolean] $result #> } Export-ModuleMember -Function *-TargetResource |
And a mof schema file:
1 2 3 4 5 6 | [ClassVersion("1.0.0.0"), FriendlyName("cJumboFrames")] class cJumboFrames : OMI_BaseResource { [Key] String InterfaceAlias; [Write, ValueMap{"Absent","Present"}, Values{"Absent","Present"}] String Ensure; }; |
Create a module manifest for the PowerShell module that was created in the previous step:
1 | New-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 |
You’ll end up with this module manifest (psd1 file):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 | # # Module manifest for module 'cJumboFrames' # # Generated by: Mike F Robbins # # Generated on: 10/1/2014 # @{ # Script module or binary module file associated with this manifest. RootModule = 'cJumboFrames' # Version number of this module. ModuleVersion = '1.0' # ID used to uniquely identify this module GUID = '866d8b02-a207-4d3c-add3-70acd4df41a2' # Author of this module Author = 'Mike F Robbins' # Company or vendor of this module CompanyName = 'mikefrobbins.com' # Copyright statement for this module Copyright = '(c) 2014 Mike F Robbins. All rights reserved.' # Description of the functionality provided by this module Description = 'Module with DSC Resource for Jumbo Frames' # Minimum version of the Windows PowerShell engine required by this module PowerShellVersion = '4.0' # Name of the Windows PowerShell host required by this module # PowerShellHostName = '' # Minimum version of the Windows PowerShell host required by this module # PowerShellHostVersion = '' # Minimum version of Microsoft .NET Framework required by this module # DotNetFrameworkVersion = '' # Minimum version of the common language runtime (CLR) required by this module # CLRVersion = '' # Processor architecture (None, X86, Amd64) required by this module # ProcessorArchitecture = '' # Modules that must be imported into the global environment prior to importing this module # RequiredModules = @() # Assemblies that must be loaded prior to importing this module # RequiredAssemblies = @() # Script files (.ps1) that are run in the caller's environment prior to importing this module. # ScriptsToProcess = @() # Type files (.ps1xml) to be loaded when importing this module # TypesToProcess = @() # Format files (.ps1xml) to be loaded when importing this module # FormatsToProcess = @() # Modules to import as nested modules of the module specified in RootModule/ModuleToProcess # NestedModules = @() # Functions to export from this module FunctionsToExport = '*.TargetResource' # Cmdlets to export from this module CmdletsToExport = '*' # Variables to export from this module VariablesToExport = '*' # Aliases to export from this module AliasesToExport = '*' # List of all modules packaged with this module # ModuleList = @() # List of all files packaged with this module # FileList = @() # Private data to pass to the module specified in RootModule/ModuleToProcess # PrivateData = '' # HelpInfo URI of this module # HelpInfoURI = '' # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix. # DefaultCommandPrefix = '' } |
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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | #region Get Jumbo Frames Setting function Get-TargetResource { [CmdletBinding()] [OutputType([Hashtable])] param ( [Parameter(Mandatory)] [String]$InterfaceAlias ) $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias | Where-Object RegistryKeyword -eq '*JumboPacket' Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.' [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500 $returnValue = @{ InterfaceAlias = $InterfaceAlias Ensure = switch ($CurrentSettings.RegistryValue) { $JumboPacket {'Present'} $NormalPacket {'Absent'} } } $returnValue } #endregion #region Set Jumbo Frames Setting function Set-TargetResource { [CmdletBinding()] param ( [Parameter(Mandatory)] [String]$InterfaceAlias, [Parameter(Mandatory)] [ValidateSet('Absent','Present')] [String]$Ensure ) $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias | Where-Object RegistryKeyword -eq '*JumboPacket' Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.' [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500 switch ($Ensure) { 'Absent' {[int]$DesiredSetting = $NormalPacket} 'Present' {[int]$DesiredSetting = $JumboPacket} } if ($CurrentSettings.RegistryValue -ne $DesiredSetting -and $CurrentSettings.RegistryValue -ne $null) { Set-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias -RegistryKeyword '*JumboPacket' -RegistryValue $DesiredSetting -PassThru } } #endregion #region Test Jumbo Frames Setting function Test-TargetResource { [CmdletBinding()] [OutputType([Boolean])] param ( [Parameter(Mandatory)] [String]$InterfaceAlias, [Parameter(Mandatory)] [ValidateSet('Absent','Present')] [String]$Ensure ) $CurrentSettings = Get-NetAdapterAdvancedProperty -InterfaceAlias $InterfaceAlias | Where-Object RegistryKeyword -eq '*JumboPacket' Write-Verbose -Message 'Determining if the NIC manufacturer uses 1500 or 1514 for the default packet size setting.' [int]$NormalPacket = [int]$CurrentSettings.DefaultRegistryValue [int]$JumboPacket = [int]$CurrentSettings.DefaultRegistryValue + 7500 switch ($Ensure) { 'Absent' {[int]$DesiredSetting = $NormalPacket} 'Present' {[int]$DesiredSetting = $JumboPacket} } if ($CurrentSettings.RegistryValue -ne $DesiredSetting -and $CurrentSettings.RegistryValue -ne $null) { Write-Verbose -Message "Jumbo Frames setting is Non-Compliant! Value should be $DesiredSetting - Detected value is: $($CurrentSettings.RegistryValue)." [Boolean]$result = $false } elseif ($CurrentSettings.RegistryValue -eq $DesiredSetting) { Write-Verbose -Message 'Jumbo Frames setting matches the desired state.' [Boolean]$result = $true } $result } #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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | configuration TestJumboFrames { param ( [Parameter(Mandatory)] [string[]]$ComputerName ) Import-DscResource -ModuleName cJumboFrames node $ComputerName { cJumboFrames iSCSINIC { InterfaceAlias = 'Ethernet 2' Ensure = 'Present' } } } |
Run the configuration, specifying SQL02 as the computer name. This creates a mof configuration file that is specific to the SQL02 test server.
1 | TestJumboFrames -ComputerName SQL02 |
Before applying the configuration, let’s check the current jumbo frames setting on SQL02:
1 2 3 4 | Invoke-Command -ComputerName SQL02 { Get-NetAdapterAdvancedProperty -InterfaceAlias 'Ethernet 2' | Where-Object RegistryKeyword -eq '*JumboPacket' } |
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:
1 | Start-DscConfiguration -ComputerName SQL02 -Path .\TestJumboFrames -Wait -Verbose |
Check the jumbo frames settings again now that the configuration has been applied:
1 2 3 4 | Invoke-Command -ComputerName SQL02 { Get-NetAdapterAdvancedProperty -InterfaceAlias 'Ethernet 2' | Where-Object RegistryKeyword -eq '*JumboPacket' } |
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:
1 2 3 4 | Invoke-Command -ComputerName SQL01 { Get-NetAdapterAdvancedProperty -InterfaceAlias 'NIC1' | Where-Object RegistryKeyword -eq '*JumboPacket' } |
Any thoughts or feedback for improvements on this resource or the process of creating a DSC resource would be appreciated.
Want to learn more about creating DSC resources? There’s a section on that topic in the DSC book which can be downloaded from the free eBook section on PowerShell.org.
Looking for DSC resources? While there are several that ship with PowerShell version 4, the PowerShell team has released 7 different waves of DSC resources. You can also find community created DSC resources on PowerShell.org’s GitHub.
Have questions about DSC that aren’t related to this blog post? I recommend posting them in the DSC forum on PowerShell.org.
µ
Thanks for this great post. Due to the very well presented information I was able to write my first DSC resource within minutes. I’ve create a pull request for the PowerShell.org DSC GitHub repository today to hopefully get my first resource cNetAdapterName published.
Best,
Daniel