Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using PowerShell to programmatically configure Internet Explorer proxy settings to work before it has been opened

Lots of PowerShell cmdlets (such as the AWS cmdlets) refer to the Internet Explorer proxy settings to find which proxy and bypass lists to use.

I'm trying to configure a proxy server and bypass lists to be used as a part of the userdata scripts that execute on new AWS instances.

I've tried multiple methods of getting this working but can't seem to get it working reliably.

Firstly let's set variables for the proxy server and bypass lists, and note that these addresses are different depending on which VPC the instance is in:

$proxy = "security-elb-1111111111.us-east-2.elb.amazonaws.com:3128"
$bypassList = "169.254.169.254;octopus-769734587.us-east-2.elb.amazonaws.com;s3.dualstack.us-east-1.amazonaws.com"

Secondly, netsh:

netsh winhttp set proxy $proxy bypass-list=$bypassList

This works well, but sadly lots of cmdlets don't refer to it.

Also this looked potentially useful:

& C:\windows\System32\bitsadmin.exe /Util /SetIEProxy LOCALSYSTEM Manual_proxy $proxy $bypassList

But that only sets the proxy server for the accounts LOCALSYSTEM,NETWORKSERVICE or LOCALSERVICE. I think the userdata script runs as Administrator, so this doesn't seem as useful as it first appeared.

So I tried hacking the registry, like this:

$reg = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
Set-ItemProperty -Path $reg -Name ProxyServer -Value $proxy
Set-ItemProperty -Path $reg -Name ProxyEnable -Value 1
Set-ItemProperty -Path $reg -Name ProxyOverride -Value $bypassList

This turned the proxy on and set up the basic details. But it looked like there was a vital piece missing as that wasn't working. Then I found

[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Connections]

which contained the keys "DefaultConnectionSettings" and "SavedLegacySettings". These seemed to contain hex versions of the proxy settings. So I created this:

$proxyString = ""
    for ($i = 0;$i -lt (([System.Text.Encoding]::Unicode.GetBytes($proxy)).length); $i++) {
        if ($i % 2 -eq 0) {
            $byte = (([System.Text.Encoding]::Unicode.GetBytes($proxy))[$i])
            $convertedByte=%{[System.Convert]::ToString($byte,16)}
            $proxyString = $proxystring + $convertedByte  + ","
        }
    }
    $bypassString = ""
    for ($i = 0;$i -lt (([System.Text.Encoding]::Unicode.GetBytes($bypassList)).length); $i++) {
        if ($i % 2 -eq 0) {
            $byte = (([System.Text.Encoding]::Unicode.GetBytes($bypassList))[$i])
            $convertedByte=%{[System.Convert]::ToString($byte,16)}
            $bypassString = $bypassString + $convertedByte  + ","
        }
    }

That converted the $proxy and $bypass into hexadecimal strings, which I combined into the long string to use in the registry like this:

$regString="46,00,00,00,00,00,00,00,0b,00,00,00,3c,00,00,00," + $proxystring + (%{[System.Convert]::ToString($bypassList.length,16)}) + ",00,00,00," + $bypassString +  "00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00"

This put in some (seemingly) arbitrary lines of hex (this could be where my problem lies), followed by the proxy string, followed by a hex indicator of the length of the bypass list, followed by the bypass list, followed by another seemingly arbitrary series of hex values.

It worked for instances on some networks, but not on others. The proxy address was one character shorter on the failing networks than the working ones.

But the strange thing is, if I logged onto the machine, opened up internet explorer and closed it again, suddenly the cmdlets would be able to use the proxy successfully.

So what is exactly going on when I open internet explorer? There must be registry keys that are changing which aids this process? I tried comparing the registry keys before and after but couldn't see anything.

Another thing I tried was programatically creating a PAC file to configure the settings. I did that like this:

'[HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings]
"AutoConfigURL"="C:\\scripts\\proxyConfig.pac"'| out-file c:\proxyReg.reg
$proxy = "internal-sec-elb-937750220.us-east-1.elb.amazonaws.com:3128"
$bypassList = "169.254.169.254;internal-mgt-priv-adr-prod-man-lb-769734587.us-east-1.elb.amazonaws.com;" + "s3.dualstack.us-east-1.amazonaws.com"

$pacFileLocation = "c:\scripts\proxyConfig.pac"
if (!(test-path (split-path $pacFileLocation))) {New-Item -ItemType Directory -Path (Split-Path $pacFileLocation)}

$pacText = 'function FindProxyForURL(url, host) {
return "PROXY ' + $proxy + ';
DIRECT";
}
'
foreach ($localAddress in ($bypassList.Split(";"))) {
$pacText = $pacText + 'if (isPlainHostName(' + $localAddress+ '))
{
return "DIRECT";
}
'

}

$pacText = $pacText + "
if (isInNet(hostIP, '0.0.0.0', '255.0.0.0') ||
isInNet(hostIP, '10.0.0.0', '255.0.0.0') ||
isInNet(hostIP, '127.0.0.0', '255.0.0.0') ||
isInNet(hostIP, '169.254.0.0', '255.255.0.0') ||
isInNet(hostIP, '172.16.0.0', '255.240.0.0') ||
isInNet(hostIP, '192.0.2.0', '255.255.255.0') ||
isInNet(hostIP, '192.88.99.0', '255.255.255.0') ||
isInNet(hostIP, '192.168.0.0', '255.255.0.0') ||
isInNet(hostIP, '198.18.0.0', '255.254.0.0') ||
isInNet(hostIP, '224.0.0.0', '240.0.0.0') ||
isInNet(hostIP, '240.0.0.0', '240.0.0.0'))
{
return 'DIRECT';
}"


$pacText | out-file $pacFileLocation -Force

However, it seems to be the case that again, these only settings take effect when Internet Explorer is opened.

Unfortunately I can't open internet explorer because the proxy needs to work before a user logs onto the machine, and running iexplore.exe from within the script doesn't do it.

This all seems really over-complicated. I can configure the proxy within a linux server within two lines. I surely have missed the simple solution somewhere. What is it?

like image 842
Dicky Moore Avatar asked Jan 09 '18 11:01

Dicky Moore


People also ask

How do you change proxy settings in a script?

To set up a proxy server using a setup scriptSelect the Start button, then select Settings > Network & internet > Proxy. If you or your organization uses a setup script, next to Use setup script, select Set up. In the Edit setup script dialog box, turn on Use setup script, enter the script address, then select Save.

How do I automatically detect proxy settings in Internet Explorer?

Use the browser settings In Internet Explorer, open the Tools menu, and then select Internet Options. On the Connections tab, select LAN Settings. In the Local Area Network Settings dialog box, select the Use a proxy server for your LAN settings check box.


1 Answers

I came to the same result as Richard's (slightly shorter) whilst setting proxy for Server Core 2016. Horrific that this is necessary!

function Set-Proxy($proxy, $bypassUrls){
    $proxyBytes = [system.Text.Encoding]::ASCII.GetBytes($proxy)
    $bypassBytes = [system.Text.Encoding]::ASCII.GetBytes($bypassUrls)
    $defaultConnectionSettings = [byte[]]@(@(70,0,0,0,0,0,0,0,11,0,0,0,$proxyBytes.Length,0,0,0)+$proxyBytes+@($bypassBytes.Length,0,0,0)+$bypassBytes+ @(1..36 | % {0}))
    $registryPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Internet Settings"
    Set-ItemProperty -Path $registryPath -Name ProxyServer -Value $proxy
    Set-ItemProperty -Path $registryPath -Name ProxyEnable -Value 1
    Set-ItemProperty -Path "$registryPath\Connections" -Name DefaultConnectionSettings -Value $defaultConnectionSettings
    netsh winhttp set proxy $proxy bypass-list=$bypassUrls
}
Set-Proxy "someproxy:1234" "*.example.com;<local>"
like image 72
Timje Avatar answered Oct 13 '22 11:10

Timje