Configure Internet Connection Sharing with PowerShell

My test environment runs as Hyper-V VM's on my IBM Thinkpad P50. I use ICS (Internet Connection Sharing) to shield my Hyper-V test environment virtual network from my production network connection. ICS allows me to temporarily give my test VM's Internet access when needed without putting them directly on the production network. You might ask why? Because my test environment VM's run things like DHCP servers that would cause havoc on the production network. I use an Internal virtual switch with Hyper-V and I keep both that internal network adapter and ICS disabled unless I need the VM's to have Internet access.

From what I've found, there's no easy way to configure ICS with PowerShell so I decided to write a couple of functions to accomplish that task. The first function, Get-MrInternetConnectionSharing retrieves the current settings.

 1#Requires -Version 3.0
 2function Get-MrInternetConnectionSharing {
 3
 4<#
 5.SYNOPSIS
 6    Retrieves the status of Internet connection sharing for the specified network adapter(s).
 7
 8.DESCRIPTION
 9    Get-MrInternetConnectionSharing is an advanced function that retrieves the status of Internet connection sharing
10    for the specified network adapter(s).
11
12.PARAMETER InternetInterfaceName
13    The name of the network adapter(s) to check the Internet connection sharing status for.
14
15.EXAMPLE
16    Get-MrInternetConnectionSharing -InternetInterfaceName Ethernet, 'Internal Virtual Switch'
17
18.EXAMPLE
19    'Ethernet', 'Internal Virtual Switch' | Get-MrInternetConnectionSharing
20
21.EXAMPLE
22    Get-NetAdapter | Get-MrInternetConnectionSharing
23
24.INPUTS
25    String
26
27.OUTPUTS
28    PSCustomObject
29
30.NOTES
31    Author:  Mike F Robbins
32    Website: http://mikefrobbins.com
33    Twitter: @mikefrobbins
34#>
35
36    [CmdletBinding()]
37    param (
38        [Parameter(Mandatory,
39                   ValueFromPipeline,
40                   ValueFromPipelineByPropertyName)]
41        [Alias('Name')]
42        [string[]]$InternetInterfaceName
43    )
44
45    BEGIN {
46        regsvr32.exe /s hnetcfg.dll
47        $netShare = New-Object -ComObject HNetCfg.HNetShare
48    }
49
50    PROCESS {
51        foreach ($Interface in $InternetInterfaceName){
52
53            $publicConnection = $netShare.EnumEveryConnection |
54            Where-Object {
55                $netShare.NetConnectionProps.Invoke($_).Name -eq $Interface
56            }
57
58            try {
59                $Results = $netShare.INetSharingConfigurationForINetConnection.Invoke($publicConnection)
60            }
61            catch {
62                Write-Warning -Message "An unexpected error has occurred for network adapter: '$Interface'"
63                Continue
64            }
65
66            [pscustomobject]@{
67                Name = $Interface
68                SharingEnabled = $Results.SharingEnabled
69                SharingConnectionType = $Results.SharingConnectionType
70                InternetFirewallEnabled = $Results.InternetFirewallEnabled
71            }
72
73        }
74
75    }
76
77}

Since the function used to retrieve the information can accept more than one network adapter name, I didn't want to use parameter validation to verify the name otherwise the function would terminate for all the ones specified if any invalid names were specified. I decided to handle any invalid network adapter names in the code itself with a try/catch block and a continue statement which skips producing any output for the invalid ones other than the warning message that I have it generate with Write-Warning.

I'll specify the two network adapters used in my Internet connection scenario.

1Get-MrInternetConnectionSharing -InternetInterfaceName Ethernet, 'Internal Virtual Switch'

ics1a.jpg

The second function, Set-MrInternetConnectionSharing configures the settings.

  1#Requires -Version 3.0 -Modules NetAdapter
  2function Set-MrInternetConnectionSharing {
  3
  4<#
  5.SYNOPSIS
  6    Configures Internet connection sharing for the specified network adapter(s).
  7
  8.DESCRIPTION
  9    Set-MrInternetConnectionSharing is an advanced function that configures Internet connection sharing
 10    for the specified network adapter(s). The specified network adapter(s) must exist and must be enabled.
 11    To enable Internet connection sharing, Internet connection sharing cannot already be enabled on any
 12    network adapters.
 13
 14.PARAMETER InternetInterfaceName
 15    The name of the network adapter to enable or disable Internet connection sharing for.
 16
 17 .PARAMETER LocalInterfaceName
 18    The name of the network adapter to share the Internet connection with.
 19
 20 .PARAMETER Enabled
 21    Boolean value to specify whether to enable or disable Internet connection sharing.
 22
 23.EXAMPLE
 24    Set-MrInternetConnectionSharing -InternetInterfaceName Ethernet -LocalInterfaceName 'Internal Virtual Switch' -Enabled $true
 25
 26.EXAMPLE
 27    'Ethernet' | Set-MrInternetConnectionSharing -LocalInterfaceName 'Internal Virtual Switch' -Enabled $false
 28
 29.EXAMPLE
 30    Get-NetAdapter -Name Ethernet | Set-MrInternetConnectionSharing -LocalInterfaceName 'Internal Virtual Switch' -Enabled $true
 31
 32.INPUTS
 33    String
 34
 35.OUTPUTS
 36    PSCustomObject
 37
 38.NOTES
 39    Author:  Mike F Robbins
 40    Website: http://mikefrobbins.com
 41    Twitter: @mikefrobbins
 42#>
 43
 44    [CmdletBinding()]
 45    param (
 46        [Parameter(Mandatory,
 47                   ValueFromPipeline,
 48                   ValueFromPipelineByPropertyName)]
 49        [ValidateScript({
 50            If ((Get-NetAdapter -Name $_ -ErrorAction SilentlyContinue -OutVariable INetNIC) -and (($INetNIC).Status -ne 'Disabled' -or ($INetNIC).Status -ne 'Not Present')) {
 51                $True
 52            }
 53            else {
 54                Throw "$_ is either not a valid network adapter of it's currently disabled."
 55            }
 56        })]
 57        [Alias('Name')]
 58        [string]$InternetInterfaceName,
 59
 60        [ValidateScript({
 61            If ((Get-NetAdapter -Name $_ -ErrorAction SilentlyContinue -OutVariable LocalNIC) -and (($LocalNIC).Status -ne 'Disabled' -or ($INetNIC).Status -ne 'Not Present')) {
 62                $True
 63            }
 64            else {
 65                Throw "$_ is either not a valid network adapter of it's currently disabled."
 66            }
 67        })]
 68        [string]$LocalInterfaceName,
 69
 70        [Parameter(Mandatory)]
 71        [bool]$Enabled
 72    )
 73
 74    BEGIN {
 75        if ((Get-NetAdapter | Get-MrInternetConnectionSharing).SharingEnabled -contains $true -and $Enabled) {
 76            Write-Warning -Message 'Unable to continue due to Internet connection sharing already being enabled for one or more network adapters.'
 77            Break
 78        }
 79
 80        regsvr32.exe /s hnetcfg.dll
 81        $netShare = New-Object -ComObject HNetCfg.HNetShare
 82    }
 83
 84    PROCESS {
 85
 86        $publicConnection = $netShare.EnumEveryConnection |
 87        Where-Object {
 88            $netShare.NetConnectionProps.Invoke($_).Name -eq $InternetInterfaceName
 89        }
 90
 91        $publicConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($publicConnection)
 92
 93        if ($PSBoundParameters.LocalInterfaceName) {
 94            $privateConnection = $netShare.EnumEveryConnection |
 95            Where-Object {
 96                $netShare.NetConnectionProps.Invoke($_).Name -eq $LocalInterfaceName
 97            }
 98
 99            $privateConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($privateConnection)
100        }
101
102        if ($Enabled) {
103            $publicConfig.EnableSharing(0)
104            if ($PSBoundParameters.LocalInterfaceName) {
105                $privateConfig.EnableSharing(1)
106            }
107        }
108        else {
109            $publicConfig.DisableSharing()
110            if ($PSBoundParameters.LocalInterfaceName) {
111                $privateConfig.DisableSharing()
112            }
113        }
114
115    }
116
117}

I've handled all of the problems that I ran into when testing this function. The specified network adapters have to exist as well as be enabled in order to be configured otherwise an error is generated. Both of those problems are handled early on with input validation via ValidateScript since there's no need to allow the function to even get started unless those requirements are met.

Next, I ran into a scenario where ICS was disabled for the Internet connection network adapter, but was enabled for the Internal one which generated an error. I've handled that problem first thing in the Begin block by checking to make sure ICS is disabled before attempting to continue.

Now I'll configure the network adapter named Ethernet to share its Internet connection with the one named Internal Virtual Switch.

1Set-MrInternetConnectionSharing -InternetInterfaceName Ethernet -LocalInterfaceName 'Internal Virtual Switch' -Enabled $true

ics2a.jpg

You can see that Internet connection is enabled by checking the settings again.

1Get-MrInternetConnectionSharing -InternetInterfaceName Ethernet, 'Internal Virtual Switch'

ics3a.jpg

The functions shown in this blog article can be downloaded as part of my MrToolkit module from my PowerShell repository on GitHub.

µ