diff --git a/lib/ansible/modules/windows/win_http_proxy.ps1 b/lib/ansible/modules/windows/win_http_proxy.ps1
new file mode 100644
index 00000000000..04ea473b998
--- /dev/null
+++ b/lib/ansible/modules/windows/win_http_proxy.ps1
@@ -0,0 +1,267 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$spec = @{
+    options = @{
+        bypass = @{ type = "list" }
+        proxy = @{ type = "raw" }
+        source = @{ type = "str"; choices = @("ie") }
+    }
+    mutually_exclusive = @(
+        @("proxy", "source"),
+        @("bypass", "source")
+    )
+    required_by = @{
+        bypass = @("proxy")
+    }
+    supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$proxy = $module.Params.proxy
+$bypass = $module.Params.bypass
+$source = $module.Params.source
+
+# Parse the raw value, it should be a Dictionary or String
+if ($proxy -is [System.Collections.IDictionary]) {
+    $valid_keys = [System.Collections.Generic.List`1[String]]@("http", "https", "ftp", "socks")
+    # Check to make sure we don't have any invalid keys in the dict
+    $invalid_keys = [System.Collections.Generic.List`1[String]]@()
+    foreach ($k in $proxy.Keys) {
+        if ($k -notin $valid_keys) {
+            $invalid_keys.Add($k)
+        }
+    }
+
+    if ($invalid_keys.Count -gt 0) {
+        $invalid_keys = $invalid_keys | Sort-Object  # So our test assertion doesn't fail due to random ordering
+        $module.FailJson("Invalid keys found in proxy: $($invalid_keys -join ', '). Valid keys are $($valid_keys -join ', ').")
+    }
+
+    # Build the proxy string in the form 'protocol=host;', the order of valid_keys is also important
+    $proxy_list = [System.Collections.Generic.List`1[String]]@()
+    foreach ($k in $valid_keys) {
+        if ($proxy.ContainsKey($k)) {
+            $proxy_list.Add("$k=$($proxy.$k)")
+        }
+    }
+    $proxy = $proxy_list -join ";"
+} elseif ($null -ne $proxy) {
+    $proxy = $proxy.ToString()
+}
+
+if ($bypass) {
+    if ([System.String]::IsNullOrEmpty($proxy)) {
+        $module.FailJson("missing parameter(s) required by ''bypass'': proxy")
+    }
+    $bypass = $bypass -join ';'
+}
+
+$win_http_invoke = @'
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinHttpProxy
+{
+    internal class NativeHelpers
+    {
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class WINHTTP_CURRENT_USER_IE_PROXY_CONFIG : IDisposable
+        {
+            public bool fAutoDetect;
+            public IntPtr lpszAutoConfigUrl;
+            public IntPtr lpszProxy;
+            public IntPtr lpszProxyBypass;
+
+            public void Dispose()
+            {
+                if (lpszAutoConfigUrl != IntPtr.Zero)
+                    Marshal.FreeHGlobal(lpszAutoConfigUrl);
+                if (lpszProxy != IntPtr.Zero)
+                    Marshal.FreeHGlobal(lpszProxy);
+                if (lpszProxyBypass != IntPtr.Zero)
+                    Marshal.FreeHGlobal(lpszProxyBypass);
+                GC.SuppressFinalize(this);
+            }
+            ~WINHTTP_CURRENT_USER_IE_PROXY_CONFIG() { this.Dispose(); }
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class WINHTTP_PROXY_INFO : IDisposable
+        {
+            public UInt32 dwAccessType;
+            public IntPtr lpszProxy;
+            public IntPtr lpszProxyBypass;
+
+            public void Dispose()
+            {
+                if (lpszProxy != IntPtr.Zero)
+                    Marshal.FreeHGlobal(lpszProxy);
+                if (lpszProxyBypass != IntPtr.Zero)
+                    Marshal.FreeHGlobal(lpszProxyBypass);
+                GC.SuppressFinalize(this);
+            }
+            ~WINHTTP_PROXY_INFO() { this.Dispose(); }
+        }
+    }
+
+    internal class NativeMethods
+    {
+        [DllImport("Winhttp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool WinHttpGetDefaultProxyConfiguration(
+            [Out] NativeHelpers.WINHTTP_PROXY_INFO pProxyInfo);
+
+        [DllImport("Winhttp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool WinHttpGetIEProxyConfigForCurrentUser(
+            [Out] NativeHelpers.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG pProxyConfig);
+
+        [DllImport("Winhttp.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool WinHttpSetDefaultProxyConfiguration(
+            NativeHelpers.WINHTTP_PROXY_INFO pProxyInfo);
+    }
+
+    public class Win32Exception : System.ComponentModel.Win32Exception
+    {
+        private string _msg;
+
+        public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
+        public Win32Exception(int errorCode, string message) : base(errorCode)
+        {
+            _msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode);
+        }
+
+        public override string Message { get { return _msg; } }
+        public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
+    }
+
+    public class WinINetProxy
+    {
+        public bool AutoDetect;
+        public string AutoConfigUrl;
+        public string Proxy;
+        public string ProxyBypass;
+    }
+
+    public class WinHttpProxy
+    {
+        public string Proxy;
+        public string ProxyBypass;
+
+        public WinHttpProxy()
+        {
+            Refresh();
+        }
+
+        public void Set()
+        {
+            using (NativeHelpers.WINHTTP_PROXY_INFO proxyInfo = new NativeHelpers.WINHTTP_PROXY_INFO())
+            {
+                if (String.IsNullOrEmpty(Proxy))
+                    proxyInfo.dwAccessType = 1; // WINHTTP_ACCESS_TYPE_NO_PROXY
+                else
+                {
+                    proxyInfo.dwAccessType = 3; // WINHTTP_ACCESS_TYPE_NAMED_PROXY
+                    proxyInfo.lpszProxy = Marshal.StringToHGlobalUni(Proxy);
+
+                    if (!String.IsNullOrEmpty(ProxyBypass))
+                        proxyInfo.lpszProxyBypass = Marshal.StringToHGlobalUni(ProxyBypass);
+                }
+
+                if (!NativeMethods.WinHttpSetDefaultProxyConfiguration(proxyInfo))
+                    throw new Win32Exception("WinHttpSetDefaultProxyConfiguration() failed");
+            }
+        }
+
+        public void Refresh()
+        {
+            using (NativeHelpers.WINHTTP_PROXY_INFO proxyInfo = new NativeHelpers.WINHTTP_PROXY_INFO())
+            {
+                if (!NativeMethods.WinHttpGetDefaultProxyConfiguration(proxyInfo))
+                    throw new Win32Exception("WinHttpGetDefaultProxyConfiguration() failed");
+
+                Proxy = Marshal.PtrToStringUni(proxyInfo.lpszProxy);
+                ProxyBypass = Marshal.PtrToStringUni(proxyInfo.lpszProxyBypass);
+            }
+        }
+
+        public static WinINetProxy GetIEProxyConfig()
+        {
+            using (NativeHelpers.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieProxy = new NativeHelpers.WINHTTP_CURRENT_USER_IE_PROXY_CONFIG())
+            {
+                if (!NativeMethods.WinHttpGetIEProxyConfigForCurrentUser(ieProxy))
+                    throw new Win32Exception("WinHttpGetIEProxyConfigForCurrentUser() failed");
+
+                return new WinINetProxy
+                {
+                    AutoDetect = ieProxy.fAutoDetect,
+                    AutoConfigUrl = Marshal.PtrToStringUni(ieProxy.lpszAutoConfigUrl),
+                    Proxy = Marshal.PtrToStringUni(ieProxy.lpszProxy),
+                    ProxyBypass = Marshal.PtrToStringUni(ieProxy.lpszProxyBypass),
+                };
+            }
+        }
+    }
+}
+'@
+Add-CSharpType -References $win_http_invoke -AnsibleModule $module
+
+$actual_proxy = New-Object -TypeName Ansible.WinHttpProxy.WinHttpProxy
+
+$module.Diff.before = @{
+    proxy = $actual_proxy.Proxy
+    bypass = $actual_proxy.ProxyBypass
+}
+
+if ($source -eq "ie") {
+    # If source=ie we need to get the server and bypass values from the IE configuration
+    $ie_proxy = [Ansible.WinHttpProxy.WinHttpProxy]::GetIEProxyConfig()
+    $proxy = $ie_proxy.Proxy
+    $bypass = $ie_proxy.ProxyBypass
+}
+
+$previous_proxy = $actual_proxy.Proxy
+$previous_bypass = $actual_proxy.ProxyBypass
+
+# Make sure an empty string is converted to $null for easier comparisons
+if ([String]::IsNullOrEmpty($proxy)) {
+    $proxy = $null
+}
+if ([String]::IsNullOrEmpty($bypass)) {
+    $bypass = $null
+}
+
+if ($previous_proxy -ne $proxy -or $previous_bypass -ne $bypass) {
+    $actual_proxy.Proxy = $proxy
+    $actual_proxy.ProxyBypass = $bypass
+
+    if (-not $module.CheckMode) {
+        $actual_proxy.Set()
+
+        # Validate that the change was made correctly and revert if it wasn't. The Set() method won't fail on invalid
+        # values so we need to check again to make sure all was good.
+        $actual_proxy.Refresh()
+        if ($actual_proxy.Proxy -ne $proxy -or $actual_proxy.ProxyBypass -ne $bypass) {
+            $actual_proxy.Proxy = $previous_proxy
+            $actual_proxy.ProxyBypass = $previous_bypass
+            $actual_proxy.Set()
+
+            $module.FailJson("Unknown error when trying to set proxy '$proxy' or bypass '$bypass'")
+        }
+    }
+
+    $module.Result.changed = $true
+}
+
+$module.Diff.after = @{
+    proxy = $proxy
+    bypass = $bypass
+}
+
+$module.ExitJson()
+
diff --git a/lib/ansible/modules/windows/win_http_proxy.py b/lib/ansible/modules/windows/win_http_proxy.py
new file mode 100644
index 00000000000..d9abb858e25
--- /dev/null
+++ b/lib/ansible/modules/windows/win_http_proxy.py
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+                    'status': ['preview'],
+                    'supported_by': 'community'}
+
+DOCUMENTATION = r'''
+---
+module: win_http_proxy
+version_added: '2.8'
+short_description: Manages proxy settings for WinHTTP
+description:
+- Used to set, remove, or import proxy settings for Windows HTTP Services
+  C(WinHTTP).
+- WinHTTP is a framework used by applications or services, typically .NET
+  applications or non-interactive services, to make web requests.
+options:
+  bypass:
+    description:
+    - A list of hosts that will bypass the set proxy when being accessed.
+    - Use C(<local>) to match hostnames that are not fully qualified domain
+      names. This is useful when needing to connect to intranet sites using
+      just the hostname.
+    - Omit, set to null or an empty string/list to remove the bypass list.
+    - If this is set then I(proxy) must also be set.
+    type: list
+  proxy:
+    description:
+    - A string or dict that specifies the proxy to be set.
+    - If setting a string, should be in the form C(hostname), C(hostname:port),
+      or C(protocol=hostname:port).
+    - If the port is undefined, the default port for the protocol in use is
+      used.
+    - If setting a dict, the keys should be the protocol and the values should
+      be the hostname and/or port for that protocol.
+    - Valid protocols are C(http), C(https), C(ftp), and C(socks).
+    - Omit, set to null or an empty string to remove the proxy settings.
+  source:
+    description:
+    - Instead of manually specifying the I(proxy) and/or I(bypass), set this to
+      import the proxy from a set source like Internet Explorer.
+    - Using C(ie) will import the Internet Explorer proxy settings for the
+      current active network connection of the current user.
+    - Only IE's proxy URL and bypass list will be imported into WinHTTP.
+    - This is like running C(netsh winhttp import proxy source=ie).
+    - The value is imported when the module runs and will not automatically
+      be updated if the IE configuration changes in the future. The module will
+      have to be run again to sync the latest changes.
+    choices:
+    - ie
+    type: str
+notes:
+- This is not the same as the proxy settings set in Internet Explorer, also
+  known as C(WinINet); use the M(win_inet_proxy) module to manage that instead.
+- These settings are set system wide and not per user, it will require
+  Administrative privileges to run.
+seealso:
+- module: win_inet_proxy
+author:
+- Jordan Borean (@jborean93)
+'''
+
+EXAMPLES = r'''
+- name: Set a proxy to use for all protocols
+  win_http_proxy:
+    proxy: hostname
+
+- name: Set a proxy with a specific port with a bypass list
+  win_http_proxy:
+    proxy: hostname:8080
+    bypass:
+    - server1
+    - server2
+    - <local>
+
+- name: Set the proxy based on the IE proxy settings
+  win_http_proxy:
+    source: ie
+
+- name: Set a proxy for specific protocols
+  win_http_proxy:
+    proxy:
+      http: hostname:8080
+      https: hostname:8443
+
+- name: Set a proxy for specific protocols using a string
+  win_http_proxy:
+    proxy: http=hostname:8080;https=hostname:8443
+    bypass: server1,server2,<local>
+
+- name: Remove any proxy settings
+  win_http_proxy:
+    proxy: ''
+    bypass: ''
+'''
+
+RETURN = r'''
+#
+'''
diff --git a/lib/ansible/modules/windows/win_inet_proxy.ps1 b/lib/ansible/modules/windows/win_inet_proxy.ps1
new file mode 100644
index 00000000000..3b0420f6486
--- /dev/null
+++ b/lib/ansible/modules/windows/win_inet_proxy.ps1
@@ -0,0 +1,495 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$spec = @{
+    options = @{
+        auto_detect = @{ type = "bool"; default = $true }
+        auto_config_url = @{ type = "str" }
+        proxy = @{ type = "raw" }
+        bypass = @{ type = "list" }
+        connection = @{ type = "str" }
+    }
+    required_by = @{
+        bypass = @("proxy")
+    }
+    supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$auto_detect = $module.Params.auto_detect
+$auto_config_url = $module.Params.auto_config_url
+$proxy = $module.Params.proxy
+$bypass = $module.Params.bypass
+$connection = $module.Params.connection
+
+# Parse the raw value, it should be a Dictionary or String
+if ($proxy -is [System.Collections.IDictionary]) {
+    $valid_keys = [System.Collections.Generic.List`1[String]]@("http", "https", "ftp", "socks")
+    # Check to make sure we don't have any invalid keys in the dict
+    $invalid_keys = [System.Collections.Generic.List`1[String]]@()
+    foreach ($k in $proxy.Keys) {
+        if ($k -notin $valid_keys) {
+            $invalid_keys.Add($k)
+        }
+    }
+
+    if ($invalid_keys.Count -gt 0) {
+        $invalid_keys = $invalid_keys | Sort-Object  # So our test assertion doesn't fail due to random ordering
+        $module.FailJson("Invalid keys found in proxy: $($invalid_keys -join ', '). Valid keys are $($valid_keys -join ', ').")
+    }
+
+    # Build the proxy string in the form 'protocol=host;', the order of valid_keys is also important
+    $proxy_list = [System.Collections.Generic.List`1[String]]@()
+    foreach ($k in $valid_keys) {
+        if ($proxy.ContainsKey($k)) {
+            $proxy_list.Add("$k=$($proxy.$k)")
+        }
+    }
+    $proxy = $proxy_list -join ";"
+} elseif ($null -ne $proxy) {
+    $proxy = $proxy.ToString()
+}
+
+if ($bypass) {
+    if ([System.String]::IsNullOrEmpty($proxy)) {
+        $module.FailJson("missing parameter(s) required by ''bypass'': proxy")
+    }
+    $bypass = $bypass -join ';'
+}
+
+$win_inet_invoke = @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinINetProxy
+{
+    internal class NativeHelpers
+    {
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class INTERNET_PER_CONN_OPTION_LISTW : IDisposable
+        {
+            public UInt32 dwSize;
+            public IntPtr pszConnection;
+            public UInt32 dwOptionCount;
+            public UInt32 dwOptionError;
+            public IntPtr pOptions;
+
+            public INTERNET_PER_CONN_OPTION_LISTW()
+            {
+                dwSize = (UInt32)Marshal.SizeOf(this);
+            }
+
+            public void Dispose()
+            {
+                if (pszConnection != IntPtr.Zero)
+                    Marshal.FreeHGlobal(pszConnection);
+                if (pOptions != IntPtr.Zero)
+                    Marshal.FreeHGlobal(pOptions);
+                GC.SuppressFinalize(this);
+            }
+            ~INTERNET_PER_CONN_OPTION_LISTW() { this.Dispose(); }
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class INTERNET_PER_CONN_OPTIONW : IDisposable
+        {
+            public INTERNET_PER_CONN_OPTION dwOption;
+            public ValueUnion Value;
+
+            [StructLayout(LayoutKind.Explicit)]
+            public class ValueUnion
+            {
+                [FieldOffset(0)]
+                public UInt32 dwValue;
+
+                [FieldOffset(0)]
+                public IntPtr pszValue;
+
+                [FieldOffset(0)]
+                public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
+            }
+
+            public void Dispose()
+            {
+                // We can't just check if Value.pszValue is not IntPtr.Zero as the union means it could be set even
+                // when the value is a UInt32 or FILETIME. We check against a known string option type and only free
+                // the value in those cases.
+                List<INTERNET_PER_CONN_OPTION> stringOptions = new List<INTERNET_PER_CONN_OPTION>
+                {
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL },
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS },
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER }
+                };
+                if (Value != null && Value.pszValue != IntPtr.Zero && stringOptions.Contains(dwOption))
+                    Marshal.FreeHGlobal(Value.pszValue);
+                GC.SuppressFinalize(this);
+            }
+            ~INTERNET_PER_CONN_OPTIONW() { this.Dispose(); }
+        }
+
+        public enum INTERNET_OPTION : uint
+        {
+            INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
+            INTERNET_OPTION_PROXY_SETTINGS_CHANGED = 95,
+        }
+
+        public enum INTERNET_PER_CONN_OPTION : uint
+        {
+            INTERNET_PER_CONN_FLAGS = 1,
+            INTERNET_PER_CONN_PROXY_SERVER = 2,
+            INTERNET_PER_CONN_PROXY_BYPASS = 3,
+            INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
+            INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5,
+            INTERNET_PER_CONN_FLAGS_UI = 10,  // IE8+ - Included with Windows 7 and Server 2008 R2
+        }
+
+        [Flags]
+        public enum PER_CONN_FLAGS : uint
+        {
+            PROXY_TYPE_DIRECT = 0x00000001,
+            PROXY_TYPE_PROXY = 0x00000002,
+            PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,
+            PROXY_TYPE_AUTO_DETECT = 0x00000008,
+        }
+    }
+
+    internal class NativeMethods
+    {
+        [DllImport("Wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool InternetQueryOptionW(
+            IntPtr hInternet,
+            NativeHelpers.INTERNET_OPTION dwOption,
+            SafeMemoryBuffer lpBuffer,
+            ref UInt32 lpdwBufferLength);
+
+        [DllImport("Wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool InternetSetOptionW(
+            IntPtr hInternet,
+            NativeHelpers.INTERNET_OPTION dwOption,
+            SafeMemoryBuffer lpBuffer,
+            UInt32 dwBufferLength);
+
+        [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+        public static extern UInt32 RasValidateEntryNameW(
+            string lpszPhonebook,
+            string lpszEntry);
+    }
+
+    internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+    {
+        public SafeMemoryBuffer() : base(true) { }
+        public SafeMemoryBuffer(int cb) : base(true)
+        {
+            base.SetHandle(Marshal.AllocHGlobal(cb));
+        }
+        public SafeMemoryBuffer(IntPtr handle) : base(true)
+        {
+            base.SetHandle(handle);
+        }
+
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        protected override bool ReleaseHandle()
+        {
+            Marshal.FreeHGlobal(handle);
+            return true;
+        }
+    }
+
+    public class Win32Exception : System.ComponentModel.Win32Exception
+    {
+        private string _msg;
+
+        public Win32Exception(string message) : this(Marshal.GetLastWin32Error(), message) { }
+        public Win32Exception(int errorCode, string message) : base(errorCode)
+        {
+            _msg = String.Format("{0} ({1}, Win32ErrorCode {2})", message, base.Message, errorCode);
+        }
+
+        public override string Message { get { return _msg; } }
+        public static explicit operator Win32Exception(string message) { return new Win32Exception(message); }
+    }
+
+    public class WinINetProxy
+    {
+        private string Connection;
+
+        public string AutoConfigUrl;
+        public bool AutoDetect;
+        public string Proxy;
+        public string ProxyBypass;
+
+        public WinINetProxy(string connection)
+        {
+            Connection = connection;
+            Refresh();
+        }
+
+        public static bool IsValidConnection(string name)
+        {
+            // RasValidateEntryName is used to verify is a name can be a valid phonebook entry. It returns 0 if no
+            // entry exists and 183 if it already exists. We just need to check if it returns 183 to verify the
+            // connection name.
+            return NativeMethods.RasValidateEntryNameW(null, name) == 183;
+        }
+
+        public void Refresh()
+        {
+            using (var connFlags = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS_UI))
+            using (var autoConfigUrl = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL))
+            using (var server = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER))
+            using (var bypass = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS))
+            {
+                NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options = new NativeHelpers.INTERNET_PER_CONN_OPTIONW[]
+                {
+                    connFlags, autoConfigUrl, server, bypass
+                };
+
+                try
+                {
+                    QueryOption(options, Connection);
+                }
+                catch (Win32Exception e)
+                {
+                    if (e.NativeErrorCode == 87) // ERROR_INVALID_PARAMETER
+                    {
+                        // INTERNET_PER_CONN_FLAGS_UI only works for IE8+, try the fallback in case we are still working
+                        // with an ancient version.
+                        connFlags.dwOption = NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS;
+                        QueryOption(options, Connection);
+                    }
+                    else
+                        throw;
+                }
+
+                NativeHelpers.PER_CONN_FLAGS flags = (NativeHelpers.PER_CONN_FLAGS)connFlags.Value.dwValue;
+
+                AutoConfigUrl = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_PROXY_URL)
+                    ? Marshal.PtrToStringUni(autoConfigUrl.Value.pszValue) : null;
+                AutoDetect = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_DETECT);
+                if (flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_PROXY))
+                {
+                    Proxy = Marshal.PtrToStringUni(server.Value.pszValue);
+                    ProxyBypass = Marshal.PtrToStringUni(bypass.Value.pszValue);
+                }
+                else
+                {
+                    Proxy = null;
+                    ProxyBypass = null;
+                }
+            }
+        }
+
+        public void Set()
+        {
+            using (var connFlags = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS_UI))
+            using (var autoConfigUrl = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL))
+            using (var server = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER))
+            using (var bypass = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS))
+            {
+                List<NativeHelpers.INTERNET_PER_CONN_OPTIONW> options = new List<NativeHelpers.INTERNET_PER_CONN_OPTIONW>();
+
+                // PROXY_TYPE_DIRECT seems to always be set, need to verify
+                NativeHelpers.PER_CONN_FLAGS flags = NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_DIRECT;
+                if (AutoDetect)
+                    flags |= NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_DETECT;
+
+                if (!String.IsNullOrEmpty(AutoConfigUrl))
+                {
+                    flags |= NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_PROXY_URL;
+                    autoConfigUrl.Value.pszValue = Marshal.StringToHGlobalUni(AutoConfigUrl);
+                }
+                options.Add(autoConfigUrl);
+
+                if (!String.IsNullOrEmpty(Proxy))
+                {
+                    flags |= NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_PROXY;
+                    server.Value.pszValue = Marshal.StringToHGlobalUni(Proxy);
+                }
+                options.Add(server);
+
+                if (!String.IsNullOrEmpty(ProxyBypass))
+                    bypass.Value.pszValue = Marshal.StringToHGlobalUni(ProxyBypass);
+                options.Add(bypass);
+
+                connFlags.Value.dwValue = (UInt32)flags;
+                options.Add(connFlags);
+
+                SetOption(options.ToArray(), Connection);
+
+                // Tell IE that the proxy settings have been changed.
+                if (!NativeMethods.InternetSetOptionW(
+                    IntPtr.Zero,
+                    NativeHelpers.INTERNET_OPTION.INTERNET_OPTION_PROXY_SETTINGS_CHANGED,
+                    new SafeMemoryBuffer(IntPtr.Zero),
+                    0))
+                {
+                    throw new Win32Exception("InternetSetOptionW(INTERNET_OPTION_PROXY_SETTINGS_CHANGED) failed");
+                }
+            }
+        }
+
+        internal static NativeHelpers.INTERNET_PER_CONN_OPTIONW CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION option)
+        {
+            return new NativeHelpers.INTERNET_PER_CONN_OPTIONW
+            {
+                dwOption = option,
+                Value = new NativeHelpers.INTERNET_PER_CONN_OPTIONW.ValueUnion(),
+            };
+        }
+
+        internal static void QueryOption(NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection = null)
+        {
+            using (NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList = new NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW())
+            using (SafeMemoryBuffer optionListPtr = MarshalOptionList(optionList, options, connection))
+            {
+                UInt32 bufferSize = optionList.dwSize;
+                if (!NativeMethods.InternetQueryOptionW(
+                    IntPtr.Zero,
+                    NativeHelpers.INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
+                    optionListPtr,
+                    ref bufferSize))
+                {
+                    throw new Win32Exception("InternetQueryOptionW(INTERNET_OPTION_PER_CONNECTION_OPTION) failed");
+                }
+
+                for (int i = 0; i < options.Length; i++)
+                {
+                    IntPtr opt = IntPtr.Add(optionList.pOptions, i * Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW)));
+                    NativeHelpers.INTERNET_PER_CONN_OPTIONW option = (NativeHelpers.INTERNET_PER_CONN_OPTIONW)Marshal.PtrToStructure(opt,
+                        typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+                    options[i].Value = option.Value;
+                    option.Value = null;  // Stops the GC from freeing the same memory twice
+                }
+            }
+        }
+
+        internal static void SetOption(NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection = null)
+        {
+            using (NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList = new NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW())
+            using (SafeMemoryBuffer optionListPtr = MarshalOptionList(optionList, options, connection))
+            {
+                if (!NativeMethods.InternetSetOptionW(
+                    IntPtr.Zero,
+                    NativeHelpers.INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
+                    optionListPtr,
+                    optionList.dwSize))
+                {
+                    throw new Win32Exception("InternetSetOptionW(INTERNET_OPTION_PER_CONNECTION_OPTION) failed");
+                }
+            }
+        }
+
+        internal static SafeMemoryBuffer MarshalOptionList(NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList,
+            NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection)
+        {
+            optionList.pszConnection = Marshal.StringToHGlobalUni(connection);
+            optionList.dwOptionCount = (UInt32)options.Length;
+
+            int optionSize = Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+            optionList.pOptions = Marshal.AllocHGlobal(optionSize * options.Length);
+            for (int i = 0; i < options.Length; i++)
+            {
+                IntPtr option = IntPtr.Add(optionList.pOptions, i * optionSize);
+                Marshal.StructureToPtr(options[i], option, false);
+            }
+
+            SafeMemoryBuffer optionListPtr = new SafeMemoryBuffer((int)optionList.dwSize);
+            Marshal.StructureToPtr(optionList, optionListPtr.DangerousGetHandle(), false);
+            return optionListPtr;
+        }
+    }
+}
+'@
+Add-CSharpType -References $win_inet_invoke -AnsibleModule $module
+
+# We need to validate the connection because WinINet will just silently continue even if the connection does not
+# already exist.
+if ($null -ne $connection -and -not [Ansible.WinINetProxy.WinINetProxy]::IsValidConnection($connection)) {
+    $module.FailJson("The connection '$connection' does not exist.")
+}
+
+$actual_proxy = New-Object -TypeName Ansible.WinINetProxy.WinINetProxy -ArgumentList @(,$connection)
+$module.Diff.before = @{
+    auto_config_url = $actual_proxy.AutoConfigUrl
+    auto_detect = $actual_proxy.AutoDetect
+    bypass = $actual_proxy.ProxyBypass
+    server = $actual_proxy.Proxy
+}
+
+# Make sure an empty string is converted to $null for easier comparisons
+if ([String]::IsNullOrEmpty($auto_config_url)) {
+    $auto_config_url = $null
+}
+if ([String]::IsNullOrEmpty($proxy)) {
+    $proxy = $null
+}
+if ([String]::IsNullOrEmpty($bypass)) {
+    $bypass = $null
+}
+
+# Record the original values in case we need to revert on a failure
+$previous_auto_config_url = $actual_proxy.AutoConfigUrl
+$previous_auto_detect = $actual_proxy.AutoDetect
+$previous_proxy = $actual_proxy.Proxy
+$previous_bypass = $actual_proxy.ProxyBypass
+
+$changed = $false
+if ($auto_config_url -ne $previous_auto_config_url) {
+    $actual_proxy.AutoConfigUrl = $auto_config_url
+    $changed = $true
+}
+
+if ($auto_detect -ne $previous_auto_detect) {
+    $actual_proxy.AutoDetect = $auto_detect
+    $changed = $true
+}
+
+if ($proxy -ne $previous_proxy) {
+    $actual_proxy.Proxy = $proxy
+    $changed = $true
+}
+
+if ($bypass -ne $previous_bypass) {
+    $actual_proxy.ProxyBypass = $bypass
+    $changed = $true
+}
+
+if ($changed -and -not $module.CheckMode) {
+    $actual_proxy.Set()
+
+    # Validate that the change was made correctly and revert if it wasn't. THe Set() method won't fail on invalid
+    # values so we need to check again to make sure all was good
+    $actual_proxy.Refresh()
+    if ($actual_proxy.AutoConfigUrl -ne $auto_config_url -or
+        $actual_proxy.AutoDetect -ne $auto_detect -or
+        $actual_proxy.Proxy -ne $proxy -or
+        $actual_proxy.ProxyBypass -ne $bypass) {
+
+        $actual_proxy.AutoConfigUrl = $previous_auto_config_url
+        $actual_proxy.AutoDetect = $previous_auto_detect
+        $actual_proxy.Proxy = $previous_proxy
+        $actual_proxy.ProxyBypass = $previous_bypass
+        $actual_proxy.Set()
+
+        $module.FailJson("Unknown error when trying to set auto_config_url '$auto_config_url', proxy '$proxy', or bypass '$bypass'")
+    }
+}
+$module.Result.changed = $changed
+
+$module.Diff.after = @{
+    auto_config_url = $auto_config_url
+    auto_detect = $auto_detect
+    bypass = $bypass
+    proxy = $proxy
+}
+
+$module.ExitJson()
diff --git a/lib/ansible/modules/windows/win_inet_proxy.py b/lib/ansible/modules/windows/win_inet_proxy.py
new file mode 100644
index 00000000000..417c774f9a8
--- /dev/null
+++ b/lib/ansible/modules/windows/win_inet_proxy.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+                    'status': ['preview'],
+                    'supported_by': 'community'}
+
+DOCUMENTATION = r'''
+---
+module: win_inet_proxy
+version_added: '2.8'
+short_description: Manages proxy settings for WinINet and Internet Explorer
+description:
+- Used to set or remove proxy settings for Windows INet which includes Internet
+  Explorer.
+- WinINet is a framework used by interactive applications to submit web
+  requests through.
+- The proxy settings can also be used by other applications like Firefox,
+  Chrome, and others but there is no definitive list.
+options:
+  auto_detect:
+    description:
+    - Whether to configure WinINet to automatically detect proxy settings
+      through Web Proxy Auto-Detection C(WPAD).
+    - This corresponds to the checkbox I(Automatically detect settings) in the
+      connection settings window.
+    default: yes
+    type: bool
+  auto_config_url:
+    description:
+    - The URL of a proxy configuration script.
+    - Proxy configuration scripts are typically JavaScript files with the
+      C(.pac) extension that implement the C(FindProxyForURL(url, host)
+      function.
+    - Omit, set to null or an empty string to remove the auto config URL.
+    - This corresponds to the checkbox I(Use automatic configuration script) in
+      the connection settings window.
+    type: str
+  bypass:
+    description:
+    - A list of hosts that will bypass the set proxy when being accessed.
+    - Use C(<local>) to match hostnames that are not fully qualified domain
+      names. This is useful when needing to connect to intranet sites using
+      just the hostname. If defined, this should be the last entry in the
+      bypass list.
+    - Use C(<-loopback>) to stop automatically bypassing the proxy when
+      connecting through any loopback address like C(127.0.0.1), C(localhost),
+      or the local hostname.
+    - Omit, set to null or an empty string/list to remove the bypass list.
+    - If this is set then I(proxy) must also be set.
+    type: list
+  connection:
+    description:
+    - The name of the IE connection to set the proxy settings for.
+    - These are the connections under the I(Dial-up and Virtual Private Network)
+      header in the IE settings.
+    - When ommited, the default LAN connection is used.
+    type: str
+  proxy:
+    description:
+    - A string or dict that specifies the proxy to be set.
+    - If setting a string, should be in the form C(hostname), C(hostname:port),
+      or C(protocol=hostname:port).
+    - If the port is undefined, the default port for the protocol in use is
+      used.
+    - If setting a dict, the keys should be the protocol and the values should
+      be the hostname and/or port for that protocol.
+    - Valid protocols are C(http), C(https), C(ftp), and C(socks).
+    - Omit, set to null or an empty string to remove the proxy settings.
+notes:
+- This is not the same as the proxy settings set in WinHTTP through the
+  C(netsh) command. Use the M(win_http_proxy) module to manage that instead.
+- These settings are by default set per user and not system wide. A registry
+  property must be set independently from this module if you wish to apply the
+  proxy for all users. See examples for more detail.
+- If per user proxy settings are desired, use I(become) to become any local
+  user on the host. No password is needed to be set for this to work.
+- If the proxy requires authentication, set the credentials using the
+  M(win_credential) module. This requires I(become) to be used so the
+  credential store can be accessed.
+seealso:
+- module: win_http_proxy
+- module: win_credential
+author:
+- Jordan Borean (@jborean93)
+'''
+
+EXAMPLES = r'''
+# This should be set before running the win_inet_proxy module
+- name: Configure IE proxy settings to apply to all users
+  win_regedit:
+    path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings
+    name: ProxySettingsPerUser
+    data: 0
+    type: dword
+    state: present
+
+# This should be set before running the win_inet_proxy module
+- name: Configure IE proxy settings to apply per user
+  win_regedit:
+    path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\CurrentVersion\Internet Settings
+    name: ProxySettingsPerUser
+    data: 1
+    type: dword
+    state: present
+
+- name: Configure IE proxy to use auto detected settings without an explicit proxy
+  win_inet_proxy:
+    auto_detect: yes
+
+- name: Configure IE proxy to use auto detected settings with a configuration script
+  win_inet_proxy:
+    auto_detect: yes
+    auto_config_url: http://proxy.ansible.com/proxy.pac
+
+- name: Configure IE to use explicit proxy host
+  win_inet_proxy:
+    auto_detect: yes
+    proxy: ansible.proxy
+
+- name: Configure IE to use explicit proxy host with port and without auto detection
+  win_inet_proxy:
+    auto_detect: no
+    proxy: ansible.proxy:8080
+
+- name: Configure IE to use a specific proxy per protocol
+  win_inet_proxy:
+    proxy:
+      http: ansible.proxy:8080
+      https: ansible.proxy:8443
+
+- name: Configure IE to use a specific proxy per protocol using a string
+  win_inet_proxy:
+    proxy: http=ansible.proxy:8080;https=ansible.proxy:8443
+
+- name: Set a proxy with a bypass list
+  win_inet_proxy:
+    proxy: ansible.proxy
+    bypass:
+    - server1
+    - server2
+    - <-loopback>
+    - <local>
+
+- name: Remove any explicit proxies that are set
+  win_inet_proxy:
+    proxy: ''
+    bypass: ''
+
+# This should be done after setting the IE proxy with win_inet_proxy
+- name: Import IE proxy configuration to WinHTTP
+  win_http_proxy:
+    source: ie
+
+# Explicit credentials can only be set per user and require become to work
+- name: Set credential to use for proxy auth
+  win_credential:
+    name: ansible.proxy  # The name should be the FQDN of the proxy host
+    type: generic_password
+    username: proxyuser
+    secret: proxypass
+    state: present
+  become: yes
+  become_user: '{{ ansible_user }}'
+  become_method: runas
+'''
+
+RETURN = r'''
+#
+'''
diff --git a/test/integration/targets/win_http_proxy/aliases b/test/integration/targets/win_http_proxy/aliases
new file mode 100644
index 00000000000..215e0b06920
--- /dev/null
+++ b/test/integration/targets/win_http_proxy/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/test/integration/targets/win_http_proxy/tasks/main.yml b/test/integration/targets/win_http_proxy/tasks/main.yml
new file mode 100644
index 00000000000..5da9aa7fecb
--- /dev/null
+++ b/test/integration/targets/win_http_proxy/tasks/main.yml
@@ -0,0 +1,14 @@
+---
+- name: make sure we start the tests with no proxy set
+  win_http_proxy:
+
+- block:
+  - name: run tests
+    include_tasks: tests.yml
+
+  always:
+  - name: remove any explicit proxy settings
+    win_http_proxy:
+
+  - name: reset WinINet proxy settings
+    win_inet_proxy:
diff --git a/test/integration/targets/win_http_proxy/tasks/tests.yml b/test/integration/targets/win_http_proxy/tasks/tests.yml
new file mode 100644
index 00000000000..c68ea611b72
--- /dev/null
+++ b/test/integration/targets/win_http_proxy/tasks/tests.yml
@@ -0,0 +1,265 @@
+---
+- name: ensure we fail when proxy is not set with bypass
+  win_http_proxy:
+    bypass: abc
+  register: fail_bypass
+  failed_when: 'fail_bypass.msg != "missing parameter(s) required by ''bypass'': proxy"'
+
+- name: ensure we fail when proxy and source is set
+  win_http_proxy:
+    proxy: proxy
+    source: ie
+  register: fail_source
+  failed_when: 'fail_source.msg != "parameters are mutually exclusive: proxy, source"'
+
+- name: ensure we fail if an invalid protocol is specified
+  win_http_proxy:
+    proxy:
+      fail1: fail
+      fail2: fail
+  register: fail_protocol
+  failed_when: 'fail_protocol.msg != "Invalid keys found in proxy: fail1, fail2. Valid keys are http, https, ftp, socks."'
+
+# WinHTTP does not validate on set, this ensures the module checks and revert any failed attempts at setting the proxy
+# FIXME: Only certain hosts seem to have a strict winhttp definition, we can't run this in CI for now
+#- name: ensure we fail if invalid value is set
+#  win_http_proxy:
+#    proxy: fake=proxy
+#  register: fail_invalid
+#  failed_when: fail_invalid.msg != "Unknown error when trying to set proxy 'fake=proxy' or bypass ''"
+#
+#- name: check proxy is still set to Direct access
+#  win_command: netsh winhttp show proxy
+#  register: fail_invalid_actual
+#  failed_when: fail_invalid_actual.stdout_lines[3]|trim != "Direct access (no proxy server)."
+
+- name: set a proxy using a string (check)
+  win_http_proxy:
+    proxy: proxyhost
+  register: proxy_str_check
+  check_mode: True
+
+- name: get result of set a proxy using a string (check)
+  win_command: netsh winhttp show proxy
+  register: proxy_str_actual_check
+
+- name: assert set a proxy using a string (check)
+  assert:
+    that:
+    - proxy_str_check is changed
+    - proxy_str_actual_check.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: set a proxy using a string
+  win_http_proxy:
+    proxy: proxyhost
+  register: proxy_str
+
+- name: get result of set a proxy using a string
+  win_command: netsh winhttp show proxy
+  register: proxy_str_actual
+
+- name: assert set a proxy using a string
+  assert:
+    that:
+    - proxy_str is changed
+    - 'proxy_str_actual.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost"'
+    - 'proxy_str_actual.stdout_lines[4]|trim == "Bypass List     :  (none)"'
+
+- name: set a proxy using a string (idempotent)
+  win_http_proxy:
+    proxy: proxyhost
+  register: proxy_str_again
+
+- name: assert set a proxy using a string (idempotent)
+  assert:
+    that:
+    - not proxy_str_again is changed
+
+- name: change a proxy and set bypass (check)
+  win_http_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - def
+    - <local>
+  register: change_proxy_check
+  check_mode: True
+
+- name: get result of change a proxy and set bypass (check)
+  win_command: netsh winhttp show proxy
+  register: change_proxy_actual_check
+
+- name: assert change a proxy and set bypass (check)
+  assert:
+    that:
+    - change_proxy_check is changed
+    - 'change_proxy_actual_check.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost"'
+    - 'change_proxy_actual_check.stdout_lines[4]|trim == "Bypass List     :  (none)"'
+
+- name: change a proxy and set bypass
+  win_http_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - def
+    - <local>
+  register: change_proxy
+
+- name: get result of change a proxy and set bypass
+  win_command: netsh winhttp show proxy
+  register: change_proxy_actual
+
+- name: assert change a proxy and set bypass
+  assert:
+    that:
+    - change_proxy is changed
+    - 'change_proxy_actual.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost:8080"'
+    - 'change_proxy_actual.stdout_lines[4]|trim == "Bypass List     :  abc;def;<local>"'
+
+- name: change a proxy and set bypass (idempotent)
+  win_http_proxy:
+    proxy: proxyhost:8080
+    bypass: abc,def,<local>
+  register: change_proxy_again
+
+- name: assert change a proxy and set bypass (idempotent)
+  assert:
+    that:
+    - not change_proxy_again is changed
+
+- name: change bypass list
+  win_http_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - <-loopback>
+  register: change_bypass
+
+- name: get result of change bypass list
+  win_command: netsh winhttp show proxy
+  register: change_bypass_actual
+
+- name: assert change bypass list
+  assert:
+    that:
+    - change_bypass is changed
+    - 'change_bypass_actual.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost:8080"'
+    - 'change_bypass_actual.stdout_lines[4]|trim == "Bypass List     :  abc;<-loopback>"'
+
+- name: remove proxy without options (check)
+  win_http_proxy:
+  register: remove_proxy_check
+  check_mode: yes
+
+- name: get result of remove proxy without options (check)
+  win_command: netsh winhttp show proxy
+  register: remove_proxy_actual_check
+
+- name: assert remove proxy without options (check)
+  assert:
+    that:
+    - remove_proxy_check is changed
+    - 'remove_proxy_actual_check.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost:8080"'
+    - 'remove_proxy_actual_check.stdout_lines[4]|trim == "Bypass List     :  abc;<-loopback>"'
+
+- name: remove proxy without options
+  win_http_proxy:
+  register: remove_proxy
+
+- name: get result of remove proxy without options
+  win_command: netsh winhttp show proxy
+  register: remove_proxy_actual
+
+- name: assert remove proxy without options
+  assert:
+    that:
+    - remove_proxy is changed
+    - remove_proxy_actual.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: remove proxy without options (idempotent)
+  win_http_proxy:
+  register: remove_proxy_again
+
+- name: assert remove proxy without options (idempotent)
+  assert:
+    that:
+    - not remove_proxy_again is changed
+
+- name: set proxy with dictionary
+  win_http_proxy:
+    proxy:
+      http: proxy:8080
+      https: proxy:8443
+      ftp: proxy:821
+      socks: proxy:888
+  register: set_dict
+
+- name: get result of set proxy with dictionary
+  win_command: netsh winhttp show proxy
+  register: set_dict_actual
+
+- name: assert set proxy with dictionary
+  assert:
+    that:
+    - set_dict is changed
+    - 'set_dict_actual.stdout_lines[3]|trim == "Proxy Server(s) :  http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888"'
+    - 'set_dict_actual.stdout_lines[4]|trim == "Bypass List     :  (none)"'
+
+- name: set proxy protocol with str
+  win_http_proxy:
+    proxy: http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888
+  register: set_str_protocol
+
+- name: assert set proxy protocol with str
+  assert:
+    that:
+    - not set_str_protocol is changed
+
+- name: remove proxy with empty string
+  win_http_proxy:
+    proxy: ''
+  register: remove_empty_str
+
+- name: get result of remove proxy with empty string
+  win_command: netsh winhttp show proxy
+  register: remove_empty_str_actual
+
+- name: assert remove proxy with empty string
+  assert:
+    that:
+    - remove_empty_str is changed
+    - remove_empty_str_actual.stdout_lines[3]|trim == "Direct access (no proxy server)."
+
+- name: set explicit proxy for WinINet
+  win_inet_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - def
+    - <local>
+
+- name: import proxy from IE
+  win_http_proxy:
+    source: ie
+  register: import_ie
+
+- name: get result of import proxy from IE
+  win_command: netsh winhttp show proxy
+  register: import_ie_actual
+
+- name: assert import proxy from IE
+  assert:
+    that:
+    - import_ie is changed
+    - 'import_ie_actual.stdout_lines[3]|trim == "Proxy Server(s) :  proxyhost:8080"'
+    - 'import_ie_actual.stdout_lines[4]|trim == "Bypass List     :  abc;def;<local>"'
+
+- name: import proxy from IE (idempotent)
+  win_http_proxy:
+    source: ie
+  register: import_ie_again
+
+- name: assert import proxy from IE (idempotent)
+  assert:
+    that:
+    - not import_ie_again is changed
diff --git a/test/integration/targets/win_inet_proxy/aliases b/test/integration/targets/win_inet_proxy/aliases
new file mode 100644
index 00000000000..215e0b06920
--- /dev/null
+++ b/test/integration/targets/win_inet_proxy/aliases
@@ -0,0 +1 @@
+shippable/windows/group4
diff --git a/test/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1 b/test/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
new file mode 100644
index 00000000000..d52b11d3ad3
--- /dev/null
+++ b/test/integration/targets/win_inet_proxy/library/win_inet_proxy_info.ps1
@@ -0,0 +1,275 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+$spec = @{
+    options = @{
+        connection = @{ type = "str" }
+    }
+    supports_check_mode = $true
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$connection = $module.Params.connection
+
+$win_inet_invoke = @'
+using Microsoft.Win32.SafeHandles;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinINetProxyInfo
+{
+    internal class NativeHelpers
+    {
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class INTERNET_PER_CONN_OPTION_LISTW : IDisposable
+        {
+            public UInt32 dwSize;
+            public IntPtr pszConnection;
+            public UInt32 dwOptionCount;
+            public UInt32 dwOptionError;
+            public IntPtr pOptions;
+
+            public INTERNET_PER_CONN_OPTION_LISTW()
+            {
+                dwSize = (UInt32)Marshal.SizeOf(this);
+            }
+
+            public void Dispose()
+            {
+                if (pszConnection != IntPtr.Zero)
+                    Marshal.FreeHGlobal(pszConnection);
+                if (pOptions != IntPtr.Zero)
+                    Marshal.FreeHGlobal(pOptions);
+                GC.SuppressFinalize(this);
+            }
+            ~INTERNET_PER_CONN_OPTION_LISTW() { this.Dispose(); }
+        }
+
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class INTERNET_PER_CONN_OPTIONW : IDisposable
+        {
+            public INTERNET_PER_CONN_OPTION dwOption;
+            public ValueUnion Value;
+
+            [StructLayout(LayoutKind.Explicit)]
+            public class ValueUnion
+            {
+                [FieldOffset(0)]
+                public UInt32 dwValue;
+
+                [FieldOffset(0)]
+                public IntPtr pszValue;
+
+                [FieldOffset(0)]
+                public System.Runtime.InteropServices.ComTypes.FILETIME ftValue;
+            }
+
+            public void Dispose()
+            {
+                // We can't just check if Value.pszValue is not IntPtr.Zero as the union means it could be set even
+                // when the value is a UInt32 or FILETIME. We check against a known string option type and only free
+                // the value in those cases.
+                List<INTERNET_PER_CONN_OPTION> stringOptions = new List<INTERNET_PER_CONN_OPTION>
+                {
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL },
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS },
+                    { INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER }
+                };
+                if (Value != null && Value.pszValue != IntPtr.Zero && stringOptions.Contains(dwOption))
+                    Marshal.FreeHGlobal(Value.pszValue);
+                GC.SuppressFinalize(this);
+            }
+            ~INTERNET_PER_CONN_OPTIONW() { this.Dispose(); }
+        }
+
+        public enum INTERNET_OPTION : uint
+        {
+            INTERNET_OPTION_PER_CONNECTION_OPTION = 75,
+        }
+
+        public enum INTERNET_PER_CONN_OPTION : uint
+        {
+            INTERNET_PER_CONN_FLAGS = 1,
+            INTERNET_PER_CONN_PROXY_SERVER = 2,
+            INTERNET_PER_CONN_PROXY_BYPASS = 3,
+            INTERNET_PER_CONN_AUTOCONFIG_URL = 4,
+            INTERNET_PER_CONN_AUTODISCOVERY_FLAGS = 5,
+            INTERNET_PER_CONN_FLAGS_UI = 10,  // IE8+ - Included with Windows 7 and Server 2008 R2
+        }
+
+        [Flags]
+        public enum PER_CONN_FLAGS : uint
+        {
+            PROXY_TYPE_DIRECT = 0x00000001,
+            PROXY_TYPE_PROXY = 0x00000002,
+            PROXY_TYPE_AUTO_PROXY_URL = 0x00000004,
+            PROXY_TYPE_AUTO_DETECT = 0x00000008,
+        }
+    }
+
+    internal class NativeMethods
+    {
+        [DllImport("Wininet.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+        public static extern bool InternetQueryOptionW(
+            IntPtr hInternet,
+            NativeHelpers.INTERNET_OPTION dwOption,
+            SafeMemoryBuffer lpBuffer,
+            ref UInt32 lpdwBufferLength);
+    }
+
+    internal class SafeMemoryBuffer : SafeHandleZeroOrMinusOneIsInvalid
+    {
+        public SafeMemoryBuffer() : base(true) { }
+        public SafeMemoryBuffer(int cb) : base(true)
+        {
+            base.SetHandle(Marshal.AllocHGlobal(cb));
+        }
+        public SafeMemoryBuffer(IntPtr handle) : base(true)
+        {
+            base.SetHandle(handle);
+        }
+
+        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
+        protected override bool ReleaseHandle()
+        {
+            Marshal.FreeHGlobal(handle);
+            return true;
+        }
+    }
+
+    public class WinINetProxy
+    {
+        private string Connection;
+
+        public string AutoConfigUrl;
+        public bool AutoDetect;
+        public string Proxy;
+        public string ProxyBypass;
+
+        public WinINetProxy(string connection)
+        {
+            Connection = connection;
+            Refresh();
+        }
+
+        public void Refresh()
+        {
+            using (var connFlags = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS_UI))
+            using (var autoConfigUrl = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_AUTOCONFIG_URL))
+            using (var server = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_SERVER))
+            using (var bypass = CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_PROXY_BYPASS))
+            {
+                NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options = new NativeHelpers.INTERNET_PER_CONN_OPTIONW[]
+                {
+                    connFlags, autoConfigUrl, server, bypass
+                };
+
+                try
+                {
+                    QueryOption(options, Connection);
+                }
+                catch (Win32Exception e)
+                {
+                    if (e.NativeErrorCode == 87) // ERROR_INVALID_PARAMETER
+                    {
+                        // INTERNET_PER_CONN_FLAGS_UI only works for IE8+, try the fallback in case we are still working
+                        // with an ancient version.
+                        connFlags.dwOption = NativeHelpers.INTERNET_PER_CONN_OPTION.INTERNET_PER_CONN_FLAGS;
+                        QueryOption(options, Connection);
+                    }
+                    else
+                        throw;
+                }
+
+                NativeHelpers.PER_CONN_FLAGS flags = (NativeHelpers.PER_CONN_FLAGS)connFlags.Value.dwValue;
+
+                AutoConfigUrl = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_PROXY_URL)
+                    ? Marshal.PtrToStringUni(autoConfigUrl.Value.pszValue) : null;
+                AutoDetect = flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_AUTO_DETECT);
+                if (flags.HasFlag(NativeHelpers.PER_CONN_FLAGS.PROXY_TYPE_PROXY))
+                {
+                    Proxy = Marshal.PtrToStringUni(server.Value.pszValue);
+                    ProxyBypass = Marshal.PtrToStringUni(bypass.Value.pszValue);
+                }
+                else
+                {
+                    Proxy = null;
+                    ProxyBypass = null;
+                }
+            }
+        }
+
+        internal static NativeHelpers.INTERNET_PER_CONN_OPTIONW CreateConnOption(NativeHelpers.INTERNET_PER_CONN_OPTION option)
+        {
+            return new NativeHelpers.INTERNET_PER_CONN_OPTIONW
+            {
+                dwOption = option,
+                Value = new NativeHelpers.INTERNET_PER_CONN_OPTIONW.ValueUnion(),
+            };
+        }
+
+        internal static void QueryOption(NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection = null)
+        {
+            using (NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList = new NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW())
+            using (SafeMemoryBuffer optionListPtr = MarshalOptionList(optionList, options, connection))
+            {
+                UInt32 bufferSize = optionList.dwSize;
+                if (!NativeMethods.InternetQueryOptionW(
+                    IntPtr.Zero,
+                    NativeHelpers.INTERNET_OPTION.INTERNET_OPTION_PER_CONNECTION_OPTION,
+                    optionListPtr,
+                    ref bufferSize))
+                {
+                    throw new Win32Exception();
+                }
+
+                for (int i = 0; i < options.Length; i++)
+                {
+                    IntPtr opt = IntPtr.Add(optionList.pOptions, i * Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW)));
+                    NativeHelpers.INTERNET_PER_CONN_OPTIONW option = (NativeHelpers.INTERNET_PER_CONN_OPTIONW)Marshal.PtrToStructure(opt,
+                        typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+                    options[i].Value = option.Value;
+                    option.Value = null;  // Stops the GC from freeing the same memory twice
+                }
+            }
+        }
+
+        internal static SafeMemoryBuffer MarshalOptionList(NativeHelpers.INTERNET_PER_CONN_OPTION_LISTW optionList,
+            NativeHelpers.INTERNET_PER_CONN_OPTIONW[] options, string connection)
+        {
+            optionList.pszConnection = Marshal.StringToHGlobalUni(connection);
+            optionList.dwOptionCount = (UInt32)options.Length;
+
+            int optionSize = Marshal.SizeOf(typeof(NativeHelpers.INTERNET_PER_CONN_OPTIONW));
+            optionList.pOptions = Marshal.AllocHGlobal(optionSize * options.Length);
+            for (int i = 0; i < options.Length; i++)
+            {
+                IntPtr option = IntPtr.Add(optionList.pOptions, i * optionSize);
+                Marshal.StructureToPtr(options[i], option, false);
+            }
+
+            SafeMemoryBuffer optionListPtr = new SafeMemoryBuffer((int)optionList.dwSize);
+            Marshal.StructureToPtr(optionList, optionListPtr.DangerousGetHandle(), false);
+            return optionListPtr;
+        }
+    }
+}
+'@
+Add-CSharpType -References $win_inet_invoke -AnsibleModule $module
+
+$proxy = New-Object -TypeName Ansible.WinINetProxyInfo.WinINetProxy -ArgumentList @(,$connection)
+$module.Result.auto_config_url = $proxy.AutoConfigUrl
+$module.Result.auto_detect = $proxy.AutoDetect
+$module.Result.proxy = $proxy.Proxy
+$module.Result.bypass = $proxy.ProxyBypass
+
+$module.ExitJson()
diff --git a/test/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1 b/test/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1
new file mode 100644
index 00000000000..1746921f6d7
--- /dev/null
+++ b/test/integration/targets/win_inet_proxy/library/win_phonebook_entry.ps1
@@ -0,0 +1,521 @@
+#!powershell
+
+# Copyright: (c) 2019, Ansible Project
+# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
+
+#AnsibleRequires -CSharpUtil Ansible.Basic
+#Requires -Module Ansible.ModuleUtils.AddType
+
+# This is a very basic skeleton of a possible Windows module for managing RAS connections. It is mostly barebones
+# to enable testing for win_inet_proxy but I've done a bit of extra work in the PInvoke space to possible expand
+# sometime in the future.
+
+$spec = @{
+    options = @{
+        device_type = @{
+            type = "str"
+            choices = @("atm", "framerelay", "generic", "rda", "isdn", "modem", "pad",
+                "parallel", "pppoe", "vpn", "serial", "sonet", "sw56", "x25")
+        }
+        device_name = @{ type = "str" }
+        framing_protocol = @{ type = "str"; choices = @("ppp", "ras", "slip") }
+        name = @{ type = "str"; required = $true }
+        options = @{ type = "list" }
+        state = @{ type = "str"; choices = @("absent", "present"); default = "present" }
+        type = @{ type = "str"; choices = @("broadband", "direct", "phone", "vpn")}
+    }
+    required_if = @(
+        ,@("state", "present", @("type", "device_name", "device_type", "framing_protocol"))
+    )
+    supports_check_mode = $false
+}
+
+$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
+
+$device_type = $module.Params.device_type
+$device_name = $module.Params.device_name
+$framing_protocol = $module.Params.framing_protocol
+$name = $module.Params.name
+$options = $module.Params.options
+$state = $module.Params.state
+$type = $module.Params.type
+
+$module.Result.guid = [System.Guid]::Empty
+
+$win_ras_invoke = @'
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ansible.WinPhonebookEntry
+{
+    public class NativeHelpers
+    {
+        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+        public class RASENTRYW
+        {
+            public UInt32 dwSize;
+            public RasEntryOptions dwfOptions;
+            public UInt32 dwCountryId;
+            public UInt32 dwCountryCode;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 11)] public string szAreaCode;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szLocalPhoneNumber;
+            public UInt32 dwAlternateOffset;
+            public RASIPADDR ipaddr;
+            public RASIPADDR ipaddrDns;
+            public RASIPADDR ipaddrDnsAlt;
+            public RASIPADDR ipaddrWins;
+            public RASIPADDR ipaddrWinsAlt;
+            public UInt32 dwFrameSize;
+            public RasNetProtocols dwfNetProtocols;
+            public RasFramingProtocol dwFramingProtocol;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szScript;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szAutodialDll;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szAutodialFunc;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 17)] public string szDeviceType;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 129)] public string szDeviceName;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 33)] public string szX25PadType;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25Address;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25Facilities;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 201)] public string szX25UserData;
+            public UInt32 dwChannels;
+            public UInt32 dwReserved1;
+            public UInt32 dwReserved2;
+            public UInt32 dwSubEntries;
+            public RasDialMode dwDialMode;
+            public UInt32 dwDialExtraPercent;
+            public UInt32 dwDialExtraSampleSeconds;
+            public UInt32 dwHangUpExtraPercent;
+            public UInt32 dwHangUpExtraSampleSeconds;
+            public UInt32 dwIdleDisconnectSeconds;
+            public RasEntryTypes dwType;
+            public RasEntryEncryption dwEntryptionType;
+            public UInt32 dwCustomAuthKey;
+            public Guid guidId;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szCustomDialDll;
+            public RasVpnStrategy dwVpnStrategy;
+            public RasEntryOptions2 dwfOptions2;
+            public UInt32 dwfOptions3;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] public string szDnsSuffix;
+            public UInt32 dwTcpWindowSize;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string szPrerequisitePbk;
+            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 257)] public string szPrerequisiteEntry;
+            public UInt32 dwRedialCount;
+            public UInt32 dwRedialPause;
+            public RASIPV6ADDR ipv6addrDns;
+            public RASIPV6ADDR ipv6addrDnsAlt;
+            public UInt32 dwIPv4InterfaceMatrix;
+            public UInt32 dwIPv6InterfaceMatrix;
+            // Server 2008 R2 / Windows 7+
+            // We cannot include these fields when running in Server 2008 as it will break the SizeOf calc of the struct
+#if !LONGHORN
+            public RASIPV6ADDR ipv6addr;
+            public UInt32 dwIPv6PrefixLength;
+            public UInt32 dwNetworkOutageTime;
+#endif
+
+            public RASENTRYW()
+            {
+                this.dwSize = (UInt32)Marshal.SizeOf(this);
+            }
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct RASIPADDR
+        {
+            public byte a;
+            public byte b;
+            public byte c;
+            public byte d;
+        }
+
+        [StructLayout(LayoutKind.Sequential)]
+        public struct RASIPV6ADDR
+        {
+            byte a;
+            byte b;
+            byte c;
+            byte d;
+            byte e;
+            byte f;
+            byte g;
+            byte h;
+            byte i;
+            byte j;
+            byte k;
+            byte l;
+            byte m;
+            byte n;
+            byte o;
+            byte p;
+        }
+
+        public enum RasDialMode : uint
+        {
+            RASEDM_DialAll = 1,
+            RASEDM_DialAsNeeded = 2,
+        }
+
+        public enum RasEntryEncryption : uint
+        {
+            ET_None = 0,
+            ET_Require = 1,
+            ET_RequireMax = 2,
+            ET_Optional = 3
+        }
+
+        [Flags]
+        public enum RasEntryOptions : uint
+        {
+            RASEO_UseCountryAndAreaCodes = 0x00000001,
+            RASEO_SpecificIpAddr = 0x00000002,
+            RASEO_SpecificNameServers = 0x00000004,
+            RASEO_IpHeaderCompression = 0x00000008,
+            RASEO_RemoteDefaultGateway = 0x00000010,
+            RASEO_DisableLcpExtensions = 0x00000020,
+            RASEO_TerminalBeforeDial = 0x00000040,
+            RASEO_TerminalAfterDial = 0x00000080,
+            RASEO_ModemLights = 0x00000100,
+            RASEO_SwCompression = 0x00000200,
+            RASEO_RequireEncrptedPw = 0x00000400,
+            RASEO_RequireMsEncrptedPw = 0x00000800,
+            RASEO_RequireDataEncrption = 0x00001000,
+            RASEO_NetworkLogon = 0x00002000,
+            RASEO_UseLogonCredentials = 0x00004000,
+            RASEO_PromoteAlternates = 0x00008000,
+            RASEO_SecureLocalFiles = 0x00010000,
+            RASEO_RequireEAP = 0x00020000,
+            RASEO_RequirePAP = 0x00040000,
+            RASEO_RequireSPAP = 0x00080000,
+            RASEO_Custom = 0x00100000,
+            RASEO_PreviewPhoneNumber = 0x00200000,
+            RASEO_SharedPhoneNumbers = 0x00800000,
+            RASEO_PreviewUserPw = 0x01000000,
+            RASEO_PreviewDomain = 0x02000000,
+            RASEO_ShowDialingProgress = 0x04000000,
+            RASEO_RequireCHAP = 0x08000000,
+            RASEO_RequireMsCHAP = 0x10000000,
+            RASEO_RequireMsCHAP2 = 0x20000000,
+            RASEO_RequireW95MSCHAP = 0x40000000,
+            RASEO_CustomScript = 0x80000000,
+        }
+
+        [Flags]
+        public enum RasEntryOptions2 : uint
+        {
+            RASEO2_None = 0x00000000,
+            RASEO2_SecureFileAndPrint = 0x00000001,
+            RASEO2_SecureClientForMSNet = 0x00000002,
+            RASEO2_DontNegotiateMultilink = 0x00000004,
+            RASEO2_DontUseRasCredentials = 0x00000008,
+            RASEO2_UsePreSharedKey = 0x00000010,
+            RASEO2_Internet = 0x00000020,
+            RASEO2_DisableNbtOverIP = 0x00000040,
+            RASEO2_UseGlobalDeviceSettings = 0x00000080,
+            RASEO2_ReconnectIfDropped = 0x00000100,
+            RASEO2_SharePhoneNumbers = 0x00000200,
+            RASEO2_SecureRoutingCompartment = 0x00000400,
+            RASEO2_UseTypicalSettings = 0x00000800,
+            RASEO2_IPv6SpecificNameServers = 0x00001000,
+            RASEO2_IPv6RemoteDefaultGateway = 0x00002000,
+            RASEO2_RegisterIpWithDNS = 0x00004000,
+            RASEO2_UseDNSSuffixForRegistration = 0x00008000,
+            RASEO2_IPv4ExplicitMetric = 0x00010000,
+            RASEO2_IPv6ExplicitMetric = 0x00020000,
+            RASEO2_DisableIKENameEkuCheck = 0x00040000,
+            // Server 2008 R2 / Windows 7+
+            RASEO2_DisableClassBasedStaticRoute = 0x00800000,
+            RASEO2_SpecificIPv6Addr = 0x01000000,
+            RASEO2_DisableMobility = 0x02000000,
+            RASEO2_RequireMachineCertificates = 0x04000000,
+            // Server 2012 / Windows 8+
+            RASEO2_UsePreSharedKeyForIkev2Initiator = 0x00800000,
+            RASEO2_UsePreSharedKeyForIkev2Responder = 0x01000000,
+            RASEO2_CacheCredentials = 0x02000000,
+            // Server 2012 R2 / Windows 8.1+
+            RASEO2_AutoTriggerCapable = 0x04000000,
+            RASEO2_IsThirdPartyProfile = 0x08000000,
+            RASEO2_AuthTypeIsOtp = 0x10000000,
+            // Server 2016 / Windows 10+
+            RASEO2_IsAlwaysOn = 0x20000000,
+            RASEO2_IsPrivateNetwork = 0x40000000,
+        }
+
+        public enum RasEntryTypes : uint
+        {
+            RASET_Phone = 1,
+            RASET_Vpn = 2,
+            RASET_Direct = 3,
+            RASET_Internet = 4,
+            RASET_Broadband = 5,
+        }
+
+        public enum RasFramingProtocol : uint
+        {
+            RASFP_Ppp = 0x00000001,
+            RASFP_Slip = 0x00000002,
+            RASFP_Ras = 0x00000004
+        }
+
+        [Flags]
+        public enum RasNetProtocols : uint
+        {
+            RASNP_NetBEUI = 0x00000001,
+            RASNP_Ipx = 0x00000002,
+            RASNP_Ip = 0x00000004,
+            RASNP_Ipv6 = 0x00000008
+        }
+
+        public enum RasVpnStrategy : uint
+        {
+            VS_Default = 0,
+            VS_PptpOnly = 1,
+            VS_PptpFirst = 2,
+            VS_L2tpOnly = 3,
+            VS_L2tpFirst = 4,
+            VS_SstpOnly = 5,
+            VS_SstpFirst = 6,
+            VS_Ikev2Only = 7,
+            VS_Ikev2First = 8,
+            VS_GREOnly = 9,
+            VS_PptpSstp = 12,
+            VS_L2tpSstp = 13,
+            VS_Ikev2Sstp = 14,
+        }
+    }
+
+    internal class NativeMethods
+    {
+        [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+        public static extern UInt32 RasDeleteEntryW(
+            string lpszPhonebook,
+            string lpszEntry);
+
+        [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+        public static extern UInt32 RasGetEntryPropertiesW(
+            string lpszPhonebook,
+            string lpszEntry,
+            [In, Out] NativeHelpers.RASENTRYW lpRasEntry,
+            ref UInt32 dwEntryInfoSize,
+            IntPtr lpbDeviceInfo,
+            ref UInt32 dwDeviceInfoSize);
+
+        [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+        public static extern UInt32 RasSetEntryPropertiesW(
+            string lpszPhonebook,
+            string lpszEntry,
+            NativeHelpers.RASENTRYW lpRasEntry,
+            UInt32 dwEntryInfoSize,
+            IntPtr lpbDeviceInfo,
+            UInt32 dwDeviceInfoSize);
+
+        [DllImport("Rasapi32.dll", CharSet = CharSet.Unicode)]
+        public static extern UInt32 RasValidateEntryNameW(
+            string lpszPhonebook,
+            string lpszEntry);
+    }
+
+    public class Phonebook
+    {
+        public static void CreateEntry(string entry, NativeHelpers.RASENTRYW details)
+        {
+            UInt32 res = NativeMethods.RasSetEntryPropertiesW(null, entry, details,
+                details.dwSize, IntPtr.Zero, 0);
+
+            if (res != 0)
+                throw new Exception(String.Format("RasSetEntryPropertiesW({0}) failed {1}", entry, res));
+        }
+
+        public static void DeleteEntry(string entry)
+        {
+            UInt32 res = NativeMethods.RasDeleteEntryW(null, entry);
+            if (res != 0)
+                throw new Exception(String.Format("RasDeleteEntryW({0}) failed {1}", entry, res));
+        }
+
+        public static NativeHelpers.RASENTRYW GetEntry(string entry)
+        {
+            NativeHelpers.RASENTRYW details = new NativeHelpers.RASENTRYW();
+            UInt32 dwEntryInfoSize = details.dwSize;
+            UInt32 dwDeviceInfoSize = 0;
+
+            UInt32 res = NativeMethods.RasGetEntryPropertiesW(null, entry, details, ref dwEntryInfoSize,
+                IntPtr.Zero, ref dwDeviceInfoSize);
+
+            if (res != 0)
+                throw new Exception(String.Format("RasGetEntryPropertiesW({0}) failed {1}", entry, res));
+
+            return details;
+        }
+
+        public static bool IsValidEntry(string entry)
+        {
+            // 183 == ENTRY_ALREADY_EXISTS
+            return NativeMethods.RasValidateEntryNameW(null, entry) == 183;
+        }
+    }
+}
+'@
+
+$add_type_params = @{
+    Reference = $win_ras_invoke
+    AnsibleModule = $module
+}
+# We need to set a custom compile option when running on Server 2008 due to the change in the RASENTRYW structure
+$os_version = [Version](Get-Item -LiteralPath $env:SystemRoot\System32\kernel32.dll).VersionInfo.ProductVersion
+if ($os_version -lt [Version]"6.1") {
+    $add_type_params.CompileSymbols = @("LONGHORN")
+}
+Add-CSharpType @add_type_params
+
+$exists = [Ansible.WinPhonebookEntry.Phonebook]::IsValidEntry($name)
+if ($exists) {
+    $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+    $module.Result.guid = $entry.guidId
+}
+
+if ($state -eq "present") {
+    # Convert the input values to enum values
+    $expected_type = switch ($type) {
+        "broadband" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Broadband }
+        "direct" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Direct }
+        "phone" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Phone }
+        "vpn" { [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryTypes]::RASET_Vpn }
+    }
+
+    $expected_framing_protocol = switch ($framing_protocol) {
+        "ppp" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Ppp }
+        "ras" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Ras }
+        "slip" { [Ansible.WinPhonebookEntry.NativeHelpers+RasFramingProtocol]::RASFP_Slip }
+    }
+
+    $expected_options1 = [System.Collections.Generic.List`1[String]]@()
+    $expected_options2 = [System.Collections.Generic.List`1[String]]@()
+    $invalid_options = [System.Collections.Generic.List`1[String]]@()
+    foreach ($option in $options) {
+        # See https://msdn.microsoft.com/en-us/25c46850-4fb7-47a9-9645-139f0e869559 for more info on the options
+        # TODO: some of these options are set to indicate entries in RASENTRYW, we should automatically add them
+        # based on the input values.
+        switch ($option) {
+            # dwfOptions
+            "use_country_and_area_codes" { $expected_options1.Add("RASEO_UseCountryAndAreaCode") }
+            "specific_ip_addr" { $expected_options1.Add("RASEO_SpecificIpAddr") }
+            "specific_name_servers" { $expected_options1.Add("RASEO_SpecificNameServers") }
+            "ip_header_compression" { $expected_options1.Add("RASEO_IpHeaderCompression") }
+            "remote_default_gateway" { $expected_options1.Add("RASEO_RemoteDefaultGateway") }
+            "disable_lcp_extensions" { $expected_options1.Add("RASEO_DisableLcpExtensions") }
+            "terminal_before_dial" { $expected_options1.Add("RASEO_TerminalBeforeDial") }
+            "terminal_after_dial" { $expected_options1.Add("RASEO_TerminalAfterDial") }
+            "modem_lights" { $expected_options1.Add("RASEO_ModemLights") }
+            "sw_compression" { $expected_options1.Add("RASEO_SwCompression") }
+            "require_encrypted_password" { $expected_options1.Add("RASEO_RequireEncrptedPw") }
+            "require_ms_encrypted_password" { $expected_options1.Add("RASEO_RequireMsEncrptedPw") }
+            "require_data_encryption" { $expected_options1.Add("RASEO_RequireDataEncrption") }
+            "network_logon" { $expected_options1.Add("RASEO_NetworkLogon") }
+            "use_logon_credentials" { $expected_options1.Add("RASEO_UseLogonCredentials") }
+            "promote_alternates" { $expected_options1.Add("RASEO_PromoteAlternates") }
+            "secure_local_files" { $expected_options1.Add("RASEO_SecureLocalFiles") }
+            "require_eap" { $expected_options1.Add("RASEO_RequireEAP") }
+            "require_pap" { $expected_options1.Add("RASEO_RequirePAP") }
+            "require_spap" { $expected_options1.Add("RASEO_RequireSPAP") }
+            "custom" { $expected_options1.Add("RASEO_Custom") }
+            "preview_phone_number" { $expected_options1.Add("RASEO_PreviewPhoneNumber") }
+            "shared_phone_numbers" { $expected_options1.Add("RASEO_SharedPhoneNumbers") }
+            "preview_user_password" { $expected_options1.Add("RASEO_PreviewUserPw") }
+            "preview_domain" { $expected_options1.Add("RASEO_PreviewDomain") }
+            "show_dialing_progress" { $expected_options1.Add("RASEO_ShowDialingProgress") }
+            "require_chap" { $expected_options1.Add("RASEO_RequireCHAP") }
+            "require_ms_chap" { $expected_options1.Add("RASEO_RequireMsCHAP") }
+            "require_ms_chap2" { $expected_options1.Add("RASEO_RequireMsCHAP2") }
+            "require_w95_ms_chap" { $expected_options1.Add("RASEO_RequireW95MSCHAP") }
+            "custom_script" { $expected_options1.Add("RASEO_CustomScript") }
+            # dwfOptions2
+            "secure_file_and_print" { $expected_options2.Add("RASEO2_SecureFileAndPrint") }
+            "secure_client_for_ms_net" { $expected_options2.Add("RASEO2_SecureClientForMSNet") }
+            "dont_negotiate_multilink" { $expected_options2.Add("RASEO2_DontNegotiateMultilink") }
+            "dont_use_ras_credential" { $expected_options2.Add("RASEO2_DontUseRasCredentials") }
+            "use_pre_shared_key" { $expected_options2.Add("RASEO2_UsePreSharedKey") }
+            "internet" { $expected_options2.Add("RASEO2_Internet") }
+            "disable_nbt_over_ip" { $expected_options2.Add("RASEO2_DisableNbtOverIP") }
+            "use_global_device_settings" { $expected_options2.Add("RASEO2_UseGlobalDeviceSettings") }
+            "reconnect_if_dropped" { $expected_options2.Add("RASEO2_ReconnectIfDropped") }
+            "share_phone_numbers" { $expected_options2.Add("RASEO2_SharePhoneNumbers") }
+            "secure_routing_compartment" { $expected_options2.Add("RASEO2_SecureRoutingCompartment") }
+            "use_typical_settings" { $expected_options2.Add("RASEO2_UseTypicalSettings") }
+            "ipv6_specific_name_servers" { $expected_options2.Add("RASEO2_IPv6SpecificNameServers") }
+            "ipv6_remote_default_gateway" { $expected_options2.Add("RASEO2_IPv6RemoteDefaultGateway") }
+            "register_ip_with_dns" { $expected_options2.Add("RASEO2_RegisterIpWithDNS") }
+            "use_dns_suffix_for_registration" { $expected_options2.Add("RASEO2_UseDNSSuffixForRegistration") }
+            "ipv4_explicit_metric" { $expected_options2.Add("RASEO2_IPv4ExplicitMetric") }
+            "ipv6_explicit_metric" { $expected_options2.Add("RASEO2_IPv6ExplicitMetric") }
+            "disable_ike_name_eku_check" { $expected_options2.Add("RASEO2_DisableIKENameEkuCheck") }
+            # TODO: Version check for the below, OS Version >= 6.1
+            "disable_class_based_static_route" { $expected_options2.Add("RASEO2_DisableClassBasedStaticRoute") }
+            "specific_ipv6_addr" { $expected_options2.Add("RASEO2_SpecificIPv6Addr") }
+            "disable_mobility" { $expected_options2.Add("RASEO2_DisableMobility") }
+            "require_machine_certificates" { $expected_options2.Add("RASEO2_RequireMachineCertificates") }
+            # TODO: Version check for the below, OS Version >= 6.2
+            "use_pre_shared_key_for_ikev2_initiator" { $expected_options2.Add("RASEO2_UsePreSharedKeyForIkev2Initiator") }
+            "use_pre_shared_key_for_ikev2_responder" { $expected_options2.Add("RASEO2_UsePreSharedKeyForIkev2Responder") }
+            "cache_credentials" { $expected_options2.Add("RASEO2_CacheCredentials") }
+            # TODO: Version check for the below, OS Version >= 6.3
+            "auto_trigger_capable" { $expected_options2.Add("RASEO2_AutoTriggerCapable") }
+            "is_third_party_profile" { $expected_options2.Add("RASEO2_IsThirdPartyProfile") }
+            "auth_type_is_otp" { $expected_options2.Add("RASEO2_AuthTypeIsOtp") }
+            # TODO: Version check for the below, OS Version >= 10.0
+            "is_always_on" { $expected_options2.Add("RASEO2_IsAlwaysOn") }
+            "is_private_network" { $expected_options2.Add("RASEO2_IsPrivateNetwork") }
+            default { $invalid_options.Add($option) }
+        }
+    }
+    if ($invalid_options.Count -gt 0) {
+        $module.FailJson("Encountered invalid options: $($invalid_options -join ", ")")
+    }
+    $expected_options1 = [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryOptions]($expected_options1 -join ", ")
+    $expected_options2 = [Ansible.WinPhonebookEntry.NativeHelpers+RasEntryOptions2]($expected_options2 -join ", ")
+
+    $property_map = @{
+        szDeviceName = $device_name
+        szDeviceType = $device_type
+        dwFramingProtocol = $expected_framing_protocol
+        dwfOptions = $expected_options1
+        dwfOptions2 = $expected_options2
+        dwType = $expected_type
+    }
+
+    if (-not $exists) {
+        $entry = New-Object -TypeName Ansible.WinPhonebookEntry.NativeHelpers+RASENTRYW
+        foreach ($kvp in $property_map.GetEnumerator()) {
+            $entry."$($kvp.Key)" = $kvp.Value
+        }
+
+        [Ansible.WinPhonebookEntry.Phonebook]::CreateEntry($name, $entry)
+        $module.Result.changed = $true
+
+        # Once created we then get the entry object again to retrieve the unique GUID ID to return
+        $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+        $module.Result.guid = $entry.guidId
+    } else {
+        $entry = [Ansible.WinPhonebookEntry.Phonebook]::GetEntry($name)
+        $changed = $false
+        foreach ($kvp in $property_map.GetEnumerator()) {
+            $key = $kvp.Key
+            $actual_value = $entry.$key
+            if ($actual_value -ne $kvp.Value) {
+                $entry.$key = $kvp.Value
+                $changed = $true
+            }
+        }
+
+        if ($changed) {
+            [Ansible.WinPhonebookEntry.Phonebook]::CreateEntry($name, $entry)
+            $module.Result.changed = $true
+        }
+    }
+} else {
+    if ($exists) {
+        [Ansible.WinPhonebookEntry.Phonebook]::DeleteEntry($name)
+        $module.Result.changed = $true
+    }
+}
+
+$module.ExitJson()
diff --git a/test/integration/targets/win_inet_proxy/tasks/main.yml b/test/integration/targets/win_inet_proxy/tasks/main.yml
new file mode 100644
index 00000000000..f92a60eab57
--- /dev/null
+++ b/test/integration/targets/win_inet_proxy/tasks/main.yml
@@ -0,0 +1,16 @@
+---
+- name: make sure we start the tests with the defaults
+  win_inet_proxy:
+
+- block:
+  - name: run tests
+    include_tasks: tests.yml
+
+  always:
+  - name: reset proxy back to defaults
+    win_inet_proxy:
+
+  - name: remove phonebook entry
+    win_phonebook_entry:
+      name: Ansible Test Dialup
+      state: absent
diff --git a/test/integration/targets/win_inet_proxy/tasks/tests.yml b/test/integration/targets/win_inet_proxy/tasks/tests.yml
new file mode 100644
index 00000000000..47ddfbe2e80
--- /dev/null
+++ b/test/integration/targets/win_inet_proxy/tasks/tests.yml
@@ -0,0 +1,308 @@
+---
+- name: ensure we fail when proxy is not set with bypass
+  win_inet_proxy:
+    bypass: abc
+  register: fail_bypass
+  failed_when: 'fail_bypass.msg != "missing parameter(s) required by ''bypass'': proxy"'
+
+- name: ensure we fail if an invalid protocol is specified
+  win_inet_proxy:
+    proxy:
+      fail1: fail
+      fail2: fail
+  register: fail_proxy
+  failed_when: 'fail_proxy.msg != "Invalid keys found in proxy: fail1, fail2. Valid keys are http, https, ftp, socks."'
+
+- name: ensure we fail if invalid value is set
+  win_inet_proxy:
+    proxy: fake=proxy
+  register: fail_invalid
+  failed_when: fail_invalid.msg != "Unknown error when trying to set auto_config_url '', proxy 'fake=proxy', or bypass ''"
+
+- name: ensure we fail if an invalid connection is set
+  win_inet_proxy:
+    connection: Fake Connection
+  register: fail_connection
+  failed_when: fail_connection.msg != "The connection 'Fake Connection' does not exist."
+
+- name: check proxy is still set to Direct access
+  win_inet_proxy_info:
+  register: fail_invalid_actual
+  failed_when: fail_invalid_actual.proxy == 'fake=proxy'
+
+- name: disable auto detect (check)
+  win_inet_proxy:
+    auto_detect: no
+  register: disable_auto_detect_check
+  check_mode: yes
+
+- name: get result of disable auto detect (check)
+  win_inet_proxy_info:
+  register: disable_auto_detect_actual_check
+
+- name: assert disable auto detect (check)
+  assert:
+    that:
+    - disable_auto_detect_check is changed
+    - disable_auto_detect_actual_check.auto_detect
+
+- name: disable auto detect
+  win_inet_proxy:
+    auto_detect: no
+  register: disable_auto_detect
+
+- name: get result of disable auto detect
+  win_inet_proxy_info:
+  register: disable_auto_detect_actual
+
+- name: assert disable auto detect
+  assert:
+    that:
+    - disable_auto_detect is changed
+    - not disable_auto_detect_actual.auto_detect
+
+- name: disable auto detect (idempotent)
+  win_inet_proxy:
+    auto_detect: no
+  register: disable_auto_detect_again
+
+- name: assert disable auto detect (idempotent)
+  assert:
+    that:
+    - not disable_auto_detect_again is changed
+
+- name: set auto config url
+  win_inet_proxy:
+    auto_config_url: http://ansible.com/proxy.pac
+  register: set_auto_url
+
+- name: get result of set auto config url
+  win_inet_proxy_info:
+  register: set_auto_url_actual
+
+- name: assert set auto config url
+  assert:
+    that:
+    - set_auto_url is changed
+    - set_auto_url_actual.auto_detect
+    - set_auto_url_actual.auto_config_url == 'http://ansible.com/proxy.pac'
+
+- name: set auto config url (idempotent)
+  win_inet_proxy:
+    auto_config_url: http://ansible.com/proxy.pac
+  register: set_auto_url_again
+
+- name: set auto config url (idempotent)
+  assert:
+    that:
+    - not set_auto_url_again is changed
+
+- name: set a proxy using a string
+  win_inet_proxy:
+    proxy: proxyhost
+  register: proxy_str
+
+- name: get result of set a proxy using a string
+  win_inet_proxy_info:
+  register: proxy_str_actual
+
+- name: assert set a proxy using a string
+  assert:
+    that:
+    - proxy_str is changed
+    - proxy_str_actual.auto_detect
+    - proxy_str_actual.auto_config_url == None
+    - proxy_str_actual.proxy == 'proxyhost'
+
+- name: set a proxy using a string (idempotent)
+  win_inet_proxy:
+    proxy: proxyhost
+  register: proxy_str_again
+
+- name: assert set a proxy using a string (idempotent)
+  assert:
+    that:
+    - not proxy_str_again is changed
+
+- name: change a proxy and set bypass
+  win_inet_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - def
+    - <local>
+  register: change_proxy
+
+- name: get result of change a proxy and set bypass
+  win_inet_proxy_info:
+  register: change_proxy_actual
+
+- name: assert change a proxy and set bypass
+  assert:
+    that:
+    - change_proxy is changed
+    - change_proxy_actual.proxy == 'proxyhost:8080'
+    - change_proxy_actual.bypass == 'abc;def;<local>'
+
+- name: change a proxy and set bypass (idempotent)
+  win_inet_proxy:
+    proxy: proxyhost:8080
+    bypass: abc,def,<local>
+  register: change_proxy_again
+
+- name: assert change a proxy and set bypass (idempotent)
+  assert:
+    that:
+    - not change_proxy_again is changed
+
+- name: change bypass list
+  win_inet_proxy:
+    proxy: proxyhost:8080
+    bypass:
+    - abc
+    - <-loopback>
+  register: change_bypass
+
+- name: get reuslt of change bypass list
+  win_inet_proxy_info:
+  register: change_bypass_actual
+
+- name: assert change bypass list
+  assert:
+    that:
+    - change_bypass is changed
+    - change_bypass_actual.proxy == 'proxyhost:8080'
+    - change_bypass_actual.bypass == 'abc;<-loopback>'
+
+- name: remove proxy without options
+  win_inet_proxy:
+  register: remove_proxy
+
+- name: get result of remove proxy without options
+  win_inet_proxy_info:
+  register: remove_proxy_actual
+
+- name: assert remove proxy without options
+  assert:
+    that:
+    - remove_proxy is changed
+    - remove_proxy_actual.auto_detect == True
+    - remove_proxy_actual.auto_config_url == None
+    - remove_proxy_actual.proxy == None
+    - remove_proxy_actual.bypass == None
+
+- name: remove proxy without options (idempotent)
+  win_inet_proxy:
+  register: remove_proxy_again
+
+- name: assert remove proxy without options (idempotent)
+  assert:
+    that:
+    - not remove_proxy_again is changed
+
+- name: set proxy with dictionary
+  win_inet_proxy:
+    proxy:
+      http: proxy:8080
+      https: proxy:8443
+      ftp: proxy:821
+      socks: proxy:888
+  register: set_dict
+
+- name: get result of set proxy with dictionary
+  win_inet_proxy_info:
+  register: set_dict_actual
+
+- name: assert set proxy with dictionary
+  assert:
+    that:
+    - set_dict is changed
+    - set_dict_actual.proxy == 'http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888'
+
+- name: set proxy protocol with str
+  win_inet_proxy:
+    proxy: http=proxy:8080;https=proxy:8443;ftp=proxy:821;socks=proxy:888
+  register: set_str_protocol
+
+- name: assert set proxy protocol with str
+  assert:
+    that:
+    - not set_str_protocol is changed
+
+- name: remove proxy with empty string
+  win_inet_proxy:
+    proxy: ''
+  register: remove_empty_str
+
+- name: get result of remove proxy with empty string
+  win_inet_proxy_info:
+  register: remove_empty_str_actual
+
+- name: assert remove proxy with empty string
+  assert:
+    that:
+    - remove_empty_str is changed
+    - remove_empty_str_actual.proxy == None
+
+- name: create test phonebook entry
+  win_phonebook_entry:
+    name: Ansible Test Dialup
+    device_type: pppoe
+    device_name: WAN Miniport (PPPOE)
+    framing_protocol: ppp
+    options:
+    - remote_default_gateway
+    - require_pap
+    - internet
+    type: broadband
+    state: present
+
+- name: set proxy for specific connection
+  win_inet_proxy:
+    connection: Ansible Test Dialup
+    auto_detect: no
+    auto_config_url: proxy.com
+    proxy: proxyhost:8080
+    bypass: proxyhost
+  register: set_connection
+
+- name: get result for set proxy for specific connection
+  win_inet_proxy_info:
+    connection: Ansible Test Dialup
+  register: set_connection_actual
+
+- name: get result for LAN connection proxy
+  win_inet_proxy_info:
+  register: set_connection_lan_actual
+
+- name: assert set proxy for specific connection
+  assert:
+    that:
+    - set_connection is changed
+    - set_connection_actual.auto_detect == False
+    - set_connection_actual.auto_config_url == 'proxy.com'
+    - set_connection_actual.proxy == 'proxyhost:8080'
+    - set_connection_actual.bypass == 'proxyhost'
+    - set_connection_lan_actual.auto_detect == True
+    - set_connection_lan_actual.auto_config_url == None
+    - set_connection_lan_actual.proxy == None
+    - set_connection_lan_actual.bypass == None
+
+- name: remove proxy for specific connection
+  win_inet_proxy:
+    connection: Ansible Test Dialup
+  register: remove_connection
+
+- name: get result of remove proxy for specific connection
+  win_inet_proxy_info:
+    connection: Ansible Test Dialup
+  register: remove_connection_actual
+
+- name: assert remove proxy for specific connection
+  assert:
+    that:
+    - remove_connection is changed
+    - remove_connection_actual.auto_detect == True
+    - remove_connection_actual.auto_config_url == None
+    - remove_connection_actual.proxy == None
+    - remove_connection_actual.bypass == None