diff --git a/lib/ansible/modules/windows/win_netbios.ps1 b/lib/ansible/modules/windows/win_netbios.ps1
new file mode 100644
index 00000000000..0179a40260c
--- /dev/null
+++ b/lib/ansible/modules/windows/win_netbios.ps1
@@ -0,0 +1,72 @@
+#!powershell
+
+# Copyright: (c) 2019, Thomas Moore (@tmmruk) <hi@tmmr.uk>
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+
+$spec = @{
+    options = @{
+        state = @{ type = "str"; choices = "enabled", "disabled", "default"; required = $true }
+        adapter_names = @{ type = "list"; required = $false }
+    }
+    supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+$module.Result.reboot_required = $false
+
+$state = $module.Params.state
+$adapter_names = $module.Params.adapter_names
+
+switch ( $state )
+{
+    'default'{ $netbiosoption = 0 }
+    enabled { $netbiosoption = 1 }
+    disabled { $netbiosoption = 2 }
+}
+
+if(-not $adapter_names)
+{
+    # Target all network adapters on the system
+    $get_params = @{
+        ClassName = 'Win32_NetworkAdapterConfiguration'
+        Filter = 'IPEnabled=true'
+        Property = @('MacAddress', 'TcpipNetbiosOptions')
+    }
+    $target_adapters_config = Get-CimInstance @get_params
+}
+else
+{
+    $get_params = @{
+        Class = 'Win32_NetworkAdapter'
+        Filter = ($adapter_names | ForEach-Object -Process { "NetConnectionId='$_'" }) -join " OR "
+        KeyOnly = $true
+    }
+    $target_adapters_config = Get-CimInstance @get_params | Get-CimAssociatedInstance -ResultClass 'Win32_NetworkAdapterConfiguration'
+    if(($target_adapters_config | Measure-Object).Count -ne $adapter_names.Count)
+    {
+        $module.FailJson("Not all of the target adapter names could be found on the system. No configuration changes have been made. $adapter_names")
+    }
+}
+
+foreach($adapter in $target_adapters_config)
+{
+    if($adapter.TcpipNetbiosOptions -ne $netbiosoption)
+    {
+        if(-not $module.CheckMode)
+        {
+            $result = Invoke-CimMethod -InputObject $adapter -MethodName SetTcpipNetbios -Arguments @{TcpipNetbiosOptions=$netbiosoption}
+            switch ( $result.ReturnValue )
+            {
+                0 { <# Success no reboot required #> }
+                1 { $module.Result.reboot_required = $true }
+                100 { $module.Warn("DHCP not enabled on adapter $($adapter.MacAddress). Unable to set default. Try using disabled or enabled options instead.") }
+                default { $module.FailJson("An error occurred while setting TcpipNetbios options on adapter $($adapter.MacAddress). Return code $($result.ReturnValue).") }
+            }
+        }
+        $module.Result.changed = $true
+    }
+}
+
+$module.ExitJson()
diff --git a/lib/ansible/modules/windows/win_netbios.py b/lib/ansible/modules/windows/win_netbios.py
new file mode 100644
index 00000000000..a3bd0dfac00
--- /dev/null
+++ b/lib/ansible/modules/windows/win_netbios.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Thomas Moore (@tmmruk)
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+# this is a windows documentation stub.  actual code lives in the .ps1
+# file of the same name
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+                    'status': ['preview'],
+                    'supported_by': 'community'}
+
+DOCUMENTATION = r'''
+---
+module: win_netbios
+version_added: '2.9'
+short_description: Manage NetBIOS over TCP/IP settings on Windows.
+description:
+  - Enables or disables NetBIOS on Windows network adapters.
+  - Can be used to protect a system against NBT-NS poisoning and avoid NBNS broadcast storms.
+  - Settings can be applied system wide or per adapter.
+options:
+  state:
+    description:
+      - Whether NetBIOS should be enabled, disabled, or default (use setting from DHCP server or if static IP address is assigned enable NetBIOS).
+    choices:
+      - enabled
+      - disabled
+      - default
+    required: yes
+    type: str
+  adapter_names:
+    description:
+      - List of adapter names for which to manage NetBIOS settings. If this option is omitted then configuration is applied to all adapters on the system.
+      - The adapter name used is the connection caption in the Network Control Panel or via C(Get-NetAdapter), eg C(Ethernet 2).
+    type: list
+    required: no
+
+author:
+  - Thomas Moore (@tmmruk)
+notes:
+  - Changing NetBIOS settings does not usually require a reboot and will take effect immediately.
+  - UDP port 137/138/139 will no longer be listening once NetBIOS is disabled.
+'''
+
+EXAMPLES = r'''
+- name: Disable NetBIOS system wide
+  win_netbios:
+    state: disabled
+
+- name: Disable NetBIOS on Ethernet2
+  win_netbios:
+    state: disabled
+    adapter_names:
+      - Ethernet2
+
+- name: Enable NetBIOS on Public and Backup adapters
+  win_netbios:
+    state: enabled
+    adapter_names:
+      - Public
+      - Backup
+
+- name: Set NetBIOS to system default on all adapters
+  win_netbios:
+    state: default
+
+'''
+
+RETURN = r'''
+reboot_required:
+    description: Boolean value stating whether a system reboot is required.
+    returned: always
+    type: bool
+    sample: true
+'''
diff --git a/test/integration/targets/win_netbios/aliases b/test/integration/targets/win_netbios/aliases
new file mode 100644
index 00000000000..4c08975b17d
--- /dev/null
+++ b/test/integration/targets/win_netbios/aliases
@@ -0,0 +1 @@
+shippable/windows/group6
diff --git a/test/integration/targets/win_netbios/library/win_device.ps1 b/test/integration/targets/win_netbios/library/win_device.ps1
new file mode 100644
index 00000000000..2b69bdbf6d4
--- /dev/null
+++ b/test/integration/targets/win_netbios/library/win_device.ps1
@@ -0,0 +1,541 @@
+#!powershell
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$spec = @{
+    options = @{
+        hardware_id = @{ type = "str" }
+        name = @{ type = "str" }
+        path = @{ type = "path" }
+        state = @{ type = "str"; choices = @("absent", "present"); default = "present" }
+    }
+    required_if = @(
+        @("state", "present", @("path", "hardware_id"), $true),
+        @("state", "absent", @(,"name"))
+    )
+    supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$hardware_id = $module.Params.hardware_id
+$name = $module.Params.name
+$path = $module.Params.path
+$state = $module.Params.state
+
+$module.Result.reboot_required = $false
+
+Add-CSharpType -References @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.ComponentModel;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ansible.Device
+{
+    public class NativeHelpers
+    {
+        [StructLayout(LayoutKind.Sequential)]
+        public class SP_DEVINFO_DATA
+        {
+            public UInt32 cbSize;
+            public Guid ClassGuid;
+            public UInt32 DevInst;
+            public IntPtr Reserved;
+
+            public SP_DEVINFO_DATA()
+            {
+                this.cbSize = (UInt32)Marshal.SizeOf(this);
+                this.ClassGuid = Guid.Empty;
+            }
+        }
+
+        [Flags]
+        public enum DeviceInfoCreationFlags : uint
+        {
+            DICD_GENERATE_ID = 0x00000001,
+            DICD_INHERIT_CLASSDRVS = 0x00000002,
+        }
+
+        public enum DeviceProperty : uint
+        {
+            SPDRP_DEVICEDESC = 0x0000000,
+            SPDRP_HARDWAREID = 0x0000001,
+            SPDRP_COMPATIBLEIDS = 0x0000002,
+            SPDRP_UNUSED0 = 0x0000003,
+            SPDRP_SERVICE = 0x0000004,
+            SPDRP_UNUSED1 = 0x0000005,
+            SPDRP_UNUSED2 = 0x0000006,
+            SPDRP_CLASS = 0x0000007,  // Read only - tied to ClassGUID
+            SPDRP_CLASSGUID = 0x0000008,
+            SPDRP_DRIVER = 0x0000009,
+            SPDRP_CONFIGFLAGS = 0x000000a,
+            SPDRP_MFG = 0x000000b,
+            SPDRP_FRIENDLYNAME = 0x000000c,
+            SPDRP_LOCATION_INFORMATION = 0x000000d,
+            SPDRP_PHYSICAL_DEVICE_OBJECT_NAME = 0x000000e,  // Read only
+            SPDRP_CAPABILITIES = 0x000000f,  // Read only
+            SPDRP_UI_NUMBER = 0x0000010,  // Read only
+            SPDRP_UPPERFILTERS = 0x0000011,
+            SPDRP_LOWERFILTERS = 0x0000012,
+            SPDRP_BUSTYPEGUID = 0x0000013,  // Read only
+            SPDRP_LEGACYBUSTYPE = 0x0000014,  // Read only
+            SPDRP_BUSNUMBER = 0x0000015,  // Read only
+            SPDRP_ENUMERATOR_NAME = 0x0000016,  // Read only
+            SPDRP_SECURITY = 0x0000017,
+            SPDRP_SECURITY_SDS = 0x0000018,
+            SPDRP_DEVTYPE = 0x0000019,
+            SPDRP_EXCLUSIVE = 0x000001a,
+            SPDRP_CHARACTERISTICS = 0x000001b,
+            SPDRP_ADDRESS = 0x000001c,  // Read only
+            SPDRP_UI_NUMBER_DESC_FORMAT = 0x000001d,
+            SPDRP_DEVICE_POWER_DATA = 0x000001e,  // Read only
+            SPDRP_REMOVAL_POLICY = 0x000001f,  // Read only
+            SPDRP_REMOVAL_POLICY_HW_DEFAULT = 0x0000020,  // Read only
+            SPDRP_REMOVAL_POLICY_OVERRIDE = 0x0000021,
+            SPDRP_INSTALL_STATE = 0x0000022,  // Read only
+            SPDRP_LOCATION_PATHS = 0x0000023,  // Read only
+            SPDRP_BASE_CONTAINERID = 0x0000024,  // Read only
+        }
+
+        // https://docs.microsoft.com/en-us/previous-versions/ff549793%28v%3dvs.85%29
+        public enum DifCodes : uint
+        {
+            DIF_SELECTDIVE = 0x00000001,
+            DIF_INSTALLDEVICE = 0x00000002,
+            DIF_ASSIGNRESOURCES = 0x00000003,
+            DIF_PROPERTIES = 0x00000004,
+            DIF_REMOVE = 0x00000005,
+            DIF_FIRSTTIMESETUP = 0x00000006,
+            DIF_FOUNDDEVICE = 0x00000007,
+            DIF_SELECTCLASSDRIVERS = 0x00000008,
+            DIF_VALIDATECLASSDRIVERS = 0x00000009,
+            DIF_INSTALLCLASSDRIVERS = 0x0000000a,
+            DIF_CALCDISKSPACE = 0x0000000b,
+            DIF_DESTROYPRIVATEDATA = 0x0000000c,
+            DIF_VALIDATEDRIVER = 0x0000000d,
+            DIF_DETECT = 0x0000000f,
+            DIF_INSTALLWIZARD = 0x00000010,
+            DIF_DESTROYWIZARDDATA = 0x00000011,
+            DIF_PROPERTYCHANGE = 0x00000012,
+            DIF_ENABLECLASS = 0x00000013,
+            DIF_DETECTVERIFY = 0x00000014,
+            DIF_INSTALLDEVICEFILES = 0x00000015,
+            DIF_UNREMOVE = 0x00000016,
+            DIF_SELECTBESTCOMPATDRV = 0x00000017,
+            DIF_ALLOW_INSTALL = 0x00000018,
+            DIF_REGISTERDEVICE = 0x00000019,
+            DIF_NEWDEVICEWIZARD_PRESELECT = 0x0000001a,
+            DIF_NEWDEVICEWIZARD_SELECT = 0x0000001b,
+            DIF_NEWDEVICEWIZARD_PREANALYZE = 0x0000001c,
+            DIF_NEWDEVICEWIZARD_POSTANALYZE = 0x0000001d,
+            DIF_NEWDEVICEWIZARD_FINISHINSTALL = 0x0000001e,
+            DIF_UNUSED1 = 0x0000001e,
+            DIF_INSTALLINTERFACES = 0x00000020,
+            DIF_DETECTCANCEL = 0x00000021,
+            DIF_REGISTER_COINSTALLERS = 0x00000022,
+            DIF_ADDPROPERTYPAGE_ADVANCED = 0x00000023,
+            DIF_ADDPROPERTYPAGE_BASIC = 0x00000024,
+            DIF_RESERVED1 = 0x00000025,
+            DIF_TROUBLESHOOTER = 0x00000026,
+            DIF_POWERMESSAGEWAKE = 0x00000027,
+            DIF_ADDREMOTEPROPERTYPAGE_ADVANCED = 0x00000028,
+            DIF_UPDATEDRIVER_UI = 0x00000029,
+            DIF_FINISHINSTALL_ACTION = 0x0000002a,
+        }
+
+        [Flags]
+        public enum GetClassFlags : uint
+        {
+            DIGCF_DEFAULT = 0x00000001,
+            DIGCF_PRESENT = 0x00000002,
+            DIGCF_ALLCLASSES = 0x00000004,
+            DIGCF_PROFILE = 0x00000008,
+            DIGCF_DEVICEINTERFACE = 0x00000010,
+        }
+
+        [Flags]
+        public enum InstallFlags : uint
+        {
+            INSTALLFLAG_FORCE = 0x00000001,
+            INSTALLFLAG_READONLY = 0x00000002,
+            INSTALLFLAG_NONINTERACTIVE = 0x00000004,
+            INSTALLFLAG_BITS = 0x00000007,
+        }
+    }
+
+    public class NativeMethods
+    {
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiCallClassInstaller(
+            NativeHelpers.DifCodes InstallFunction,
+            SafeDeviceInfoSet DeviceInfoSet,
+            NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern SafeDeviceInfoSet SetupDiCreateDeviceInfoList(
+            Guid ClassGuid,
+            IntPtr hwndParent);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiCreateDeviceInfoW(
+            SafeDeviceInfoSet DeviceInfoSet,
+            [MarshalAs(UnmanagedType.LPWStr)] string DeviceName,
+            Guid ClassGuid,
+            [MarshalAs(UnmanagedType.LPWStr)] string DeviceDescription,
+            IntPtr hwndParent,
+            NativeHelpers.DeviceInfoCreationFlags CreationFlags,
+            NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiDestroyDeviceInfoList(
+            IntPtr DeviceInfoSet);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiEnumDeviceInfo(
+            SafeDeviceInfoSet DeviceInfoSet,
+            UInt32 MemberIndex,
+            NativeHelpers.SP_DEVINFO_DATA DeviceInfoData);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern SafeDeviceInfoSet SetupDiGetClassDevsW(
+            Guid ClassGuid,
+            [MarshalAs(UnmanagedType.LPWStr)] string Enumerator,
+            IntPtr hwndParent,
+            NativeHelpers.GetClassFlags Flags);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiGetDeviceRegistryPropertyW(
+            SafeDeviceInfoSet DeviceInfoSet,
+            NativeHelpers.SP_DEVINFO_DATA DeviceInfoData,
+            NativeHelpers.DeviceProperty Property,
+            out UInt32 PropertyRegDataType,
+            SafeMemoryBuffer PropertyBuffer,
+            UInt32 PropertyBufferSize,
+            ref UInt32 RequiredSize);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiGetINFClassW(
+            [MarshalAs(UnmanagedType.LPWStr)] string InfName,
+            ref Guid ClassGuid,
+            [MarshalAs(UnmanagedType.LPWStr)] StringBuilder ClassName,
+            UInt32 ClassNameSize,
+            ref UInt32 RequiredSize);
+
+        [DllImport("Setupapi.dll", SetLastError = true)]
+        public static extern bool SetupDiSetDeviceRegistryPropertyW(
+            SafeDeviceInfoSet DeviceInfoSet,
+            NativeHelpers.SP_DEVINFO_DATA DeviceInfoData,
+            NativeHelpers.DeviceProperty Property,
+            SafeMemoryBuffer PropertyBuffer,
+            UInt32 PropertyBufferSize);
+
+        [DllImport("Newdev.dll", SetLastError = true)]
+        public static extern bool UpdateDriverForPlugAndPlayDevicesW(
+            IntPtr hwndParent,
+            [MarshalAs(UnmanagedType.LPWStr)] string HardwareId,
+            [MarshalAs(UnmanagedType.LPWStr)] string FullInfPath,
+            NativeHelpers.InstallFlags InstallFlags,
+            ref bool bRebootRequired);
+    }
+
+    public class SafeDeviceInfoSet : SafeHandleZeroOrMinusOneIsInvalid
+    {
+        public SafeDeviceInfoSet() : base(true) { }
+
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        protected override bool ReleaseHandle()
+        {
+            return NativeMethods.SetupDiDestroyDeviceInfoList(handle);
+        }
+    }
+
+    public class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+    {
+        public int Length = 0;
+
+        public SafeMemoryBuffer() : base(true) { }
+
+        public SafeMemoryBuffer(int cb) : base(true)
+        {
+            Length = cb;
+            base.SetHandle(Marshal.AllocHGlobal(cb));
+        }
+
+        public SafeMemoryBuffer(string sz) : base(true)
+        {
+            Length = sz.Length * sizeof(char);
+            base.SetHandle(Marshal.StringToHGlobalUni(sz));
+        }
+
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        protected override bool ReleaseHandle()
+        {
+            Marshal.FreeHGlobal(handle);
+            return true;
+        }
+    }
+
+    public class DeviceUtil
+    {
+        public static string GetDeviceFriendlyName(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo)
+        {
+            string friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_FRIENDLYNAME);
+
+            // Older Windows versions may not have a friendly name set. This seems to be the case when the device has
+            // a unique description so we fallback to that value.
+            if (null == friendlyName)
+                friendlyName = GetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_DEVICEDESC);
+
+            return friendlyName;
+        }
+
+        public static void SetDeviceHardwareId(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+            string hardwareId)
+        {
+            SetDeviceStringProp(devInfoSet, devInfo, NativeHelpers.DeviceProperty.SPDRP_HARDWAREID, hardwareId);
+        }
+
+        private static string GetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+            NativeHelpers.DeviceProperty property)
+        {
+            using (SafeMemoryBuffer memBuf = GetDeviceProperty(devInfoSet, devInfo, property))
+            {
+                if (memBuf.IsInvalid)  // Property does not exist so just return null.
+                    return null;
+
+                return Marshal.PtrToStringUni(memBuf.DangerousGetHandle());
+            }
+        }
+
+        private static SafeMemoryBuffer GetDeviceProperty(SafeDeviceInfoSet devInfoSet,
+            NativeHelpers.SP_DEVINFO_DATA devInfo, NativeHelpers.DeviceProperty property)
+        {
+            UInt32 requiredSize = 0;
+            UInt32 regDataType = 0;
+            if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property,
+                out regDataType, new SafeMemoryBuffer(0), 0, ref requiredSize))
+            {
+                int errCode = Marshal.GetLastWin32Error();
+                if (errCode == 0x0000000D)  // ERROR_INVALID_DATA
+                    return new SafeMemoryBuffer();  // The FRIENDLYNAME property does not exist
+                else if (errCode != 0x0000007A)  // ERROR_INSUFFICIENT_BUFFER
+                    throw new Win32Exception(errCode);
+            }
+
+            SafeMemoryBuffer memBuf = new SafeMemoryBuffer((int)requiredSize);
+            if (!NativeMethods.SetupDiGetDeviceRegistryPropertyW(devInfoSet, devInfo, property,
+                out regDataType, memBuf, requiredSize, ref requiredSize))
+            {
+                int errCode = Marshal.GetLastWin32Error();
+                memBuf.Dispose();
+
+                throw new Win32Exception(errCode);
+            }
+
+            return memBuf;
+        }
+
+        private static void SetDeviceStringProp(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+            NativeHelpers.DeviceProperty property, string value)
+        {
+            using (SafeMemoryBuffer buffer = new SafeMemoryBuffer(value))
+                SetDeviceProperty(devInfoSet, devInfo, property, buffer);
+        }
+
+        private static void SetDeviceProperty(SafeDeviceInfoSet devInfoSet, NativeHelpers.SP_DEVINFO_DATA devInfo,
+            NativeHelpers.DeviceProperty property, SafeMemoryBuffer buffer)
+        {
+            if (!NativeMethods.SetupDiSetDeviceRegistryPropertyW(devInfoSet, devInfo, property, buffer,
+                (UInt32)buffer.Length))
+            {
+                throw new Win32Exception(Marshal.GetLastWin32Error());
+            }
+        }
+    }
+}
+'@
+
+Function Get-Win32ErrorMessage {
+    Param ([System.Int32]$ErrorCode)
+
+    $exp = New-Object -TypeName System.ComponentModel.Win32Exception -ArgumentList $ErrorCode
+    return ("{0} (Win32 ErrorCode {1} - 0x{1:X8}" -f $exp.Message, $ErrorCode)
+}
+
+# Determine if the device is already installed
+$dev_info_set = [Ansible.Device.NativeMethods]::SetupDiGetClassDevsW(
+    [Guid]::Empty,
+    [NullString]::Value,
+    [System.IntPtr]::Zero,
+    [Ansible.Device.NativeHelpers+GetClassFlags]::DIGCF_ALLCLASSES
+); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+try {
+    if ($dev_info_set.IsInvalid) {
+        $msg = Get-Win32ErrorMessage -ErrorCode $err
+        $module.FailJson("Failed to get device information set for installed devices: $msg")
+    }
+
+    $dev_info = $null
+    if ($null -ne $name) {
+        # Loop through the set of all devices and compare the name
+        $idx = 0
+        while ($true) {
+            $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA
+            $res = [Ansible.Device.NativeMethods]::SetupDiEnumDeviceInfo(
+                $dev_info_set,
+                $idx,
+                $dev_info
+            ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+            if (-not $res) {
+                $dev_info = $null
+                if ($err -eq 0x00000103) {  # ERROR_NO_MORE_ITEMS
+                    break
+                }
+
+                $msg = Get-Win32ErrorMessage -ErrorCode $err
+                $module.FailJson("Failed to enumerate device information set at index $($idx): $msg")
+            }
+
+            $device_name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info)
+            if ($device_name -eq $name) {
+                break
+            }
+
+            $dev_info = $null
+            $idx++
+        }
+    }
+
+    if ($state -eq "absent" -and $null -ne $dev_info) {
+        if (-not $module.CheckMode) {
+            $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+                [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE,
+                $dev_info_set,
+                $dev_info
+            ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+            if (-not $res) {
+                $msg = Get-Win32ErrorMessage -ErrorCode $err
+                $module.FailJson("Failed to remove device $($name): $msg")
+            }
+        }
+
+        $module.Result.changed = $true
+    } elseif ($state -eq "present" -and $null -eq $dev_info) {
+        # Populate the class guid and display name if the path to an inf file was set.
+        $class_id = [Guid]::Empty
+        $class_name = $null
+        if ($path) {
+            if (-not (Test-Path -LiteralPath $path)) {
+                $module.FailJson("Could not find the inf file specified at '$path'")
+            }
+
+            $class_name_sb = New-Object -TypeName System.Text.StringBuilder -ArgumentList 32  # MAX_CLASS_NAME_LEN
+            $required_size = 0
+            $res = [Ansible.Device.NativeMethods]::SetupDiGetINFClassW(
+                $path,
+                [ref]$class_id,
+                $class_name_sb,
+                $class_name_sb.Capacity,
+                [ref]$required_size
+            ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+            if (-not $res) {
+                $msg = Get-Win32ErrorMessage -ErrorCode $err
+                $module.FailJson("Failed to parse driver inf at '$path': $msg")
+            }
+
+            $class_name = $class_name_sb.ToString()
+        }
+
+        # When creating a new device we want to start with a blank device information set.
+        $dev_info_set.Dispose()
+
+        $dev_info_set = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoList(
+            $class_id,
+            [System.IntPtr]::Zero
+        ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+        if ($dev_info_set.IsInvalid) {
+            $msg = Get-Win32ErrorMessage -ErrorCode $err
+            $module.FailJson("Failed to create device info set for the class $($class_id): $msg")
+        }
+
+        # Create the new device element and add it to the device info set
+        $dev_info = New-Object -TypeName Ansible.Device.NativeHelpers+SP_DEVINFO_DATA
+        $res = [Ansible.Device.NativeMethods]::SetupDiCreateDeviceInfoW(
+            $dev_info_set,
+            $class_name,
+            $class_id,
+            $null,
+            [System.IntPtr]::Zero,
+            [Ansible.Device.NativeHelpers+DeviceInfoCreationFlags]::DICD_GENERATE_ID,
+            $dev_info
+        ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+        if (-not $res) {
+            $msg = Get-Win32ErrorMessage -ErrorCode $err
+            $module.FailJson("Failed to create new device element for class $($class_name): $msg")
+        }
+
+        # Set the hardware id of the new device so we can load the proper driver.
+        [Ansible.Device.DeviceUtil]::SetDeviceHardwareId($dev_info_set, $dev_info, $hardware_id)
+
+        if (-not $module.CheckMode) {
+            # Install the device
+            $res = [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+                [Ansible.Device.NativeHelpers+DifCodes]::DIF_REGISTERDEVICE,
+                $dev_info_set,
+                $dev_info
+            ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+            if (-not $res) {
+                $msg = Get-Win32ErrorMessage -ErrorCode $err
+                $module.FailJson("Failed to register new device for class $($class_name): $msg")
+            }
+
+            # Load the drivers for the new device
+            $reboot_required = $false
+            $res = [Ansible.Device.NativeMethods]::UpdateDriverForPlugAndPlayDevicesW(
+                [System.IntPtr]::Zero,
+                $hardware_id,
+                $path,
+                [Ansible.Device.NativeHelpers+InstallFlags]'INSTALLFLAG_FORCE, INSTALLFLAG_NONINTERACTIVE',
+                [ref]$reboot_required
+            ); $err = [System.Runtime.InteropServices.Marshal]::GetLastWin32Error()
+
+            if (-not $res) {
+                # On a failure make sure we cleanup the "installed" device
+                [Ansible.Device.NativeMethods]::SetupDiCallClassInstaller(
+                    [Ansible.Device.NativeHelpers+DifCodes]::DIF_REMOVE,
+                    $dev_info_set,
+                    $dev_info
+                ) > $null
+
+                $msg = Get-Win32ErrorMessage -ErrorCode $err
+                $module.FailJson("Failed to update device driver: $msg")
+            }
+
+            $module.Result.reboot_required = $reboot_required
+
+            # Now get the name of the newly created device which we return back to Ansible.
+            $name = [Ansible.Device.DeviceUtil]::GetDeviceFriendlyName($dev_info_set, $dev_info)
+        } else {
+            # Generate random name for check mode output
+            $name = "Check mode generated device for $($class_name)"
+        }
+        $module.Result.changed = $true
+    }
+} finally {
+    $dev_info_set.Dispose()
+}
+
+$module.Result.name = $name
+
+$module.ExitJson()
diff --git a/test/integration/targets/win_netbios/tasks/main.yml b/test/integration/targets/win_netbios/tasks/main.yml
new file mode 100644
index 00000000000..01f5b435b4a
--- /dev/null
+++ b/test/integration/targets/win_netbios/tasks/main.yml
@@ -0,0 +1,54 @@
+# Test code for win_netbios module
+# Copyright: (c) 2019, Thomas Moore <hi@tmmr.uk>
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+
+- name: ensure netbios is set to default to start with
+  win_netbios:
+    state: default
+
+- name: create dummy network adapter device
+  win_device:
+    path: '%WinDir%\Inf\netloop.inf'
+    hardware_id: '*msloop'
+    state: present
+  register: test_device_name
+
+- set_fact:
+    test_device_name: '{{ test_device_name.name }}'
+
+- block:
+  - name: get name of the dummy network adapter
+    win_shell: (Get-CimInstance -Class Win32_NetworkAdapter -Filter "Name='{{ test_device_name }}'").NetConnectionID
+    changed_when: False
+    register: test_adapter
+
+  - set_fact:
+      test_adapter: '{{ test_adapter.stdout | trim }}'
+
+  - name: run tests
+    include_tasks: tests.yml
+
+  always:
+  - name: remove dummy network adapter device
+    win_device:
+      name: '{{ test_device_name }}'
+      state: absent
+
+  - name: set netbios back to default after tests
+    win_netbios:
+      state: default
\ No newline at end of file
diff --git a/test/integration/targets/win_netbios/tasks/tests.yml b/test/integration/targets/win_netbios/tasks/tests.yml
new file mode 100644
index 00000000000..9527ab691a4
--- /dev/null
+++ b/test/integration/targets/win_netbios/tasks/tests.yml
@@ -0,0 +1,159 @@
+# Test code for win_netbios module
+# Copyright: (c) 2019, Thomas Moore <hi@tmmr.uk>
+
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+#
+# Ansible is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Ansible is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
+
+- set_fact:
+    get_netbios_script: |
+      $adapter = Get-CimInstance -ClassName Win32_NetworkAdapter -Filter "NetConnectionID='{{ test_adapter }}'"
+      $config = Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration -Filter "Index=$($adapter.DeviceID)"
+      $config.TcpipNetbiosOptions
+
+- name: disable netbios single adapter (check mode)
+  win_netbios:
+    adapter_names: '{{ test_adapter }}'
+    state: disabled
+  register: set_single_check
+  check_mode: yes
+
+- name: get result of disable a single adapter test (check mode)
+  win_shell: '{{ get_netbios_script }}'
+  changed_when: no
+  register: set_single_actual_check
+
+- name: assert disable a single adapter (check mode)
+  assert:
+    that:
+    - set_single_check is changed
+    - set_single_actual_check.stdout_lines == ["0"]
+
+- name: disable netbios single adapter
+  win_netbios:
+    adapter_names: '{{ test_adapter }}'
+    state: disabled
+  register: set_single
+
+- name: get result of disable a single adapter test
+  win_shell: '{{ get_netbios_script }}'
+  changed_when: no
+  register: set_single_actual
+
+- name: assert disable a single adapter
+  assert:
+    that:
+    - set_single_check is changed
+    - set_single_actual.stdout_lines == ["2"]
+
+- name: fail with invalid network adapter name
+  win_netbios:
+    state: disabled
+    adapter_names:
+      - FakeAdapterName
+  register: invalid_adapter
+  failed_when: invalid_adapter.msg != "Not all of the target adapter names could be found on the system. No configuration changes have been made. FakeAdapterName"
+
+- name: disable netbios all adapters (check mode)
+  win_netbios:
+    state: disabled
+  check_mode: yes
+  register: disable_check
+
+- name: assert disable netbios (check mode)
+  assert:
+    that:
+      - disable_check.changed
+
+- name: disable netbios all adapters
+  win_netbios:
+    state: disabled
+  register: netbios_disable
+
+- name: assert netbios disabled
+  assert:
+    that:
+      - netbios_disable.changed
+
+- name: test disable idempotence
+  win_netbios:
+    state: disabled
+  register: netbios_disable
+
+- name: test disable idempotence
+  assert:
+    that:
+      - not netbios_disable.changed
+
+- name: enable netbios all adapters (check mode)
+  win_netbios:
+    state: enabled
+  check_mode: yes
+  register: enable_check
+
+- name: assert enable netbios all adapters (check mode)
+  assert:
+    that:
+      - enable_check.changed
+
+- name: enable netbios all adapters
+  win_netbios:
+    state: enabled
+  register: netbios_enable
+
+- name: assert netbios enabled
+  assert:
+    that:
+      - netbios_enable.changed
+
+- name: test enable idempotence
+  win_netbios:
+    state: enabled
+  register: netbios_enable
+
+- name: assert enable idempotence
+  assert:
+    that:
+      - not netbios_enable.changed
+
+- name: default netbios all adapters (check mode)
+  win_netbios:
+    state: default
+  check_mode: yes
+  register: default_check
+
+- name: assert default netbios (check mode)
+  assert:
+    that:
+      - default_check.changed
+
+- name: default netbios all adapters
+  win_netbios:
+    state: default
+  register: default_enable
+
+- name: assert netbios default all adapters
+  assert:
+    that:
+      - default_enable.changed
+
+- name: test default idempotence
+  win_netbios:
+    state: default
+  register: netbios_default
+
+- name: assert default idempotence
+  assert:
+    that:
+      - not netbios_default.changed
\ No newline at end of file