using namespace System.Security.Principal using namespace System.Management.Automation function Set-Ics { <# .SYNOPSIS Enables Internet Connection Sharing (ICS) for a specified network connection pair. .DESCRIPTION Set-Ics lets you share the internet connection of a network connection (called the public connection) with another network connection (called the private connection). The specified network connections must exist beforehand. In order to be able to set ICS, the function will first disable ICS for any existing network connections. .PARAMETER PublicConnectionName The name of the network connection that internet connection will be shared from. .PARAMETER PrivateConnectionName The name of the network connection that internet connection will be shared with. .PARAMETER PassThru If this parameter is specified Set-Ics returns an object representing the set connections. Optional. By default Set-Ics does not generate any output. .PARAMETER WhatIf Shows what would happen if the function runs. The function is not run. .PARAMETER Confirm Prompts you for confirmation before each change the function makes. .EXAMPLE Set-Ics -PublicConnectionName 'Ethernet' -PrivateConnectionName 'VM Host-Only Network' # Sets ICS for the specified public and private connections. .EXAMPLE Set-Ics Ethernet 'VM Host-Only Network' # Sets ICS for the specified public and private connections. .EXAMPLE Set-Ics Ethernet 'VM Host-Only Network' -PassThru # Sets ICS for the specified public and private connections and generates an output. .INPUTS Set-Ics does not take pipeline input. .OUTPUTS Default is no output. If parameter PassThru is specified Set-Ics returns a PSCustomObject. .NOTES Set-Ics requires elevated permissions. Use the Run as administrator option when starting PowerShell. Testing for administrator rights is done in the beginning of function. .LINK Online version: https://github.com/loxia01/PSInternetConnectionSharing#set-ics Get-Ics Disable-Ics #> [CmdletBinding(SupportsShouldProcess)] param ( [Parameter(Mandatory)] [string]$PublicConnectionName, [Parameter(Mandatory)] [string]$PrivateConnectionName, [switch]$PassThru ) begin { if (-not ([WindowsPrincipal][WindowsIdentity]::GetCurrent()).IsInRole([WindowsBuiltInRole]'Administrator')) { $exception = "This function requires administrator rights." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'AdminPrivilegeRequired', 18, $null)) } regsvr32 /s hnetcfg.dll $netShare = New-Object -ComObject HNetCfg.HNetShare $connections = @($netShare.EnumEveryConnection) $connectionsProps = $connections | ForEach-Object {$netShare.NetConnectionProps.Invoke($_)} Get-Variable PublicConnectionName, PrivateConnectionName | ForEach-Object { if ($connectionsProps.Name -notcontains $_.Value) { $exception = New-Object PSArgumentException "Cannot find a network connection with name '$($_.Value)'." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'ConnectionNotFound', 13, $null)) } else { $_.Value = $connectionsProps | Where-Object Name -EQ $_.Value | Select-Object -ExpandProperty Name } } if ($PrivateConnectionName -eq $PublicConnectionName) { $exception = New-Object PSArgumentException "The private connection cannot be the same as the public connection." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'InvalidConnection', 5, $null)) } if (($connectionsProps | Where-Object Name -EQ $PrivateConnectionName).Status -eq 0) { $exception = "Private connection '${PrivateConnectionName}' must be enabled to set ICS." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'ConnectionNotEnabled', 31, $null)) } } process { foreach ($connection in $connections) { try { if ($netShare.NetConnectionProps.Invoke($connection).Name -eq $PublicConnectionName) { $publicConnectionConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($connection) } elseif ($netShare.NetConnectionProps.Invoke($connection).Name -eq $PrivateConnectionName) { $privateConnectionConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($connection) } else { continue } } catch { $exception = New-Object RuntimeException -Args ( "ICS is not possible to set for connection '$($netShare.NetConnectionProps.Invoke($connection).Name)'.", $_.Exception ) $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, $_.CategoryInfo.Reason, $_.CategoryInfo.Category, $null)) } } if (-not (($publicConnectionConfig.SharingEnabled -and $publicConnectionConfig.SharingConnectionType -eq 0) -and ($privateConnectionConfig.SharingEnabled -and $privateConnectionConfig.SharingConnectionType -eq 1))) { $icsConnections = foreach ($method in "EnumPublicConnections","EnumPrivateConnections") { try { [pscustomobject]@{ Name = $netshare.$method.Invoke(0) | ForEach-Object {$netShare.NetConnectionProps.Invoke($_).Name} Config = $netshare.$method.Invoke(0) | ForEach-Object {$netShare.INetSharingConfigurationForINetConnection.Invoke($_)} } } catch { continue } } if ($icsConnections -and $PSCmdlet.ShouldProcess(($icsConnections.Name -join ", "), 'Disable-Ics')) { $icsConnections.Config | ForEach-Object {$_.DisableSharing()} } if ($PSCmdlet.ShouldProcess(($PublicConnectionName, $PrivateConnectionName) -join ", ")) { $publicConnectionConfig.EnableSharing(0) $privateConnectionConfig.EnableSharing(1) } } } end { if ($PassThru -and -not $WhatIfPreference) { Get-Ics } } } function Get-Ics { <# .SYNOPSIS Gets Internet Connection Sharing (ICS) status for network connections. .DESCRIPTION Gets network connections where ICS is enabled, or optionally for all specified network connections. Output is a PSCustomObject representing the connections. .PARAMETER ConnectionNames Name(s) of the network connection(s) to get ICS status for. Optional. .PARAMETER AllConnections If parameter ConnectionNames is omitted, Get-Ics by default only lists network connections where ICS is enabled. To list ICS status for all network connections, add the switch parameter AllConnections. Cannot be combined with parameter ConnectionNames. .EXAMPLE Get-Ics # Gets ICS status for network connections where ICS is enabled. .EXAMPLE Get-Ics -AllConnections # Gets ICS status for all network connections. .EXAMPLE Get-Ics -ConnectionNames Ethernet, Ethernet2, 'VM Host-Only Network' # Gets ICS status for the specified network connections. .EXAMPLE Get-Ics Ethernet, Ethernet2, 'VM Host-Only Network' # Gets ICS status for the specified network connections. .INPUTS Get-Ics does not take pipeline input. .OUTPUTS PSCustomObject. .NOTES Get-Ics requires elevated permissions. Use the Run as administrator option when starting PowerShell. Testing for administrator rights is done in the beginning of function. .LINK Online version: https://github.com/loxia01/PSInternetConnectionSharing#get-ics Set-Ics Disable-Ics #> [CmdletBinding(DefaultParameterSetName='ConnectionNames')] param ( [Parameter(ParameterSetName='ConnectionNames', Position=0)] [SupportsWildcards()] [string[]]$ConnectionNames, [Parameter(ParameterSetName='AllConnections')] [switch]$AllConnections ) begin { if ($PSCmdlet.MyInvocation.PSCommandPath -notmatch 'PSInternetConnectionSharing.psm1$') { if (-not ([WindowsPrincipal][WindowsIdentity]::GetCurrent()).IsInRole([WindowsBuiltInRole]'Administrator')) { $exception = "This function requires administrator rights." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'AdminPrivilegeRequired', 18, $null)) } regsvr32 /s hnetcfg.dll $netShare = New-Object -ComObject HNetCfg.HNetShare $connections = @($netShare.EnumEveryConnection) $connectionsProps = $connections | ForEach-Object {$netShare.NetConnectionProps.Invoke($_)} if ($ConnectionNames) { $ConnectionNames = foreach ($connectionName in $ConnectionNames) { if (-not ($connectionsProps.Name -like $connectionName)) { $exception = New-Object PSArgumentException "Cannot find a network connection with name '$($_.Value)'." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'ConnectionNotFound', 13, $null)) } else { $connectionsProps.Name -like $connectionName } } } elseif ($AllConnections) { $ConnectionNames = $connectionsProps.Name } else {} } else { if (-not $connections) { $connections = @($netShare.EnumEveryConnection) } } } process { if ($ConnectionNames) { $output = foreach ($connectionName in $ConnectionNames) { $connection = $connections | Where-Object {$netShare.NetConnectionProps.Invoke($_).Name -eq $connectionName} try { $connectionConfig = $netShare.INetSharingConfigurationForINetConnection.Invoke($connection) } catch { $connectionConfig = $null if (-not $AllConnections) { Write-Warning "ICS is not settable for connection '${connectionName}'." } } if ($connectionConfig.SharingEnabled -eq 1) { [pscustomobject]@{ ConnectionName = $connectionName ICSEnabled = $true ConnectionType = if ($connectionConfig.SharingConnectionType -eq 0) { 'Public' } else { 'Private' } } } else { [pscustomobject]@{ ConnectionName = $connectionName ICSEnabled = if ($connectionConfig.SharingEnabled -eq 0) { $false } else { $null } } } } } else { $output = foreach ($method in "EnumPublicConnections","EnumPrivateConnections") { try { [pscustomobject]@{ ConnectionName = $netshare.$method.Invoke(0) | ForEach-Object {$netShare.NetConnectionProps.Invoke($_).Name} ICSEnabled = $true ConnectionType = if ($method -match 'Public') { 'Public' } else { 'Private' } } } catch { continue } } } } end { if ($PSCmdlet.MyInvocation.PSCommandPath -notmatch 'PSInternetConnectionSharing.psm1$') { $output | Sort-Object ConnectionType -Descending } else { $output } } } function Disable-Ics { <# .SYNOPSIS Disables Internet Connection Sharing (ICS) for all network connections. .DESCRIPTION Disable-Ics checks for if ICS is enabled for any network connections and disables ICS for those connections. .PARAMETER PassThru If this parameter is specified Disable-Ics returns an object representing the disabled connections. Optional. By default Disable-Ics does not generate any output. .PARAMETER WhatIf Shows what would happen if the function runs. The function is not run. .PARAMETER Confirm Prompts you for confirmation before each change the function makes. .EXAMPLE Disable-Ics # Disables ICS for all connections. .EXAMPLE Disable-Ics -PassThru # Disables ICS for all connections and generates an output. .INPUTS Disable-Ics does not take pipeline input. .OUTPUTS Default is no output. If parameter PassThru is specified Disable-Ics returns a PSCustomObject. .NOTES Disable-Ics requires elevated permissions. Use the Run as administrator option when starting PowerShell. Testing for administrator rights is done in the beginning of function. .LINK Online version: https://github.com/loxia01/PSInternetConnectionSharing#disable-ics Set-Ics Get-Ics #> [CmdletBinding(SupportsShouldProcess)] param ([switch]$PassThru) begin { if (-not ([WindowsPrincipal][WindowsIdentity]::GetCurrent()).IsInRole([WindowsBuiltInRole]'Administrator')) { $exception = "This function requires administrator rights." $PSCmdlet.ThrowTerminatingError((New-Object ErrorRecord -Args $exception, 'AdminPrivilegeRequired', 18, $null)) } regsvr32 /s hnetcfg.dll $netShare = New-Object -ComObject HNetCfg.HNetShare } process { $icsConnections = foreach ($method in "EnumPublicConnections","EnumPrivateConnections") { try { [pscustomobject]@{ Name = $netShare.$method.Invoke(0) | ForEach-Object {$netShare.NetConnectionProps.Invoke($_).Name} Config = $netShare.$method.Invoke(0) | ForEach-Object {$netShare.INetSharingConfigurationForINetConnection.Invoke($_)} } } catch { continue } } if ($icsConnections -and $PSCmdlet.ShouldProcess($icsConnections.Name -join ", ")) { $icsConnections.Config | ForEach-Object {$_.DisableSharing()} } } end { if ($PassThru -and -not $WhatIfPreference) { Get-Ics -ConnectionNames $icsConnections.Name } } }