I recently upgraded my workstation to Windows 8.1 and as such, am now using Internet Explorer 11. While there are some welcomed improvements, there are several changes that have made day-to-day administration activities a bit challenging. For instance, all of the Dell hardware we use has a Remote Access Controller installed that allows us to perform various remote administration tasks. Unfortunately, the current version of firmware for these DRACs is not compatible with IE 11. However, running in IE 7 compatibility mode allows the UI of the DRACs to function properly.
The problem is, we access all of these directly by private IP and adding hundreds of IP addresses to the IE compatibility view settings on multiple workstations is a bit of a pain. Thankfully, these compatibility view exceptions can be set with Group Policy, but the workstations I use are in a Workgroup and do not belong to a domain. I set out to find a way to programmatically add these exceptions using powershell.
First, it’s important to note that the registry keys that control this behavior changed in IE 11. In previous versions of IE, the setting was exclusively maintained under HKCU(HKLM)\Software\[Wow6432Node]\Policies\Microsoft\Internet Explorer\BrowserEmulation\PolicyList. Starting with IE 11, there’s an additional key under HKCU\Software\Microsoft\Internet Explorer\BrowserEmulation\ClearableListData\UserFilter that controls compatibility view settings. Unfortunately, this new key is stored in binary format and there’s not much information regarding it. I was able to find a stackoverflow post where a user attempted to decipher the data, but I found that some of the assumptions they made did not hold true. Via a process of trial-and-error, I was able to come up with a script that can set this value. However, because IE 11 still supports the previous registry key, I HIGHLY recommend using the other method described later in this post. While this seems to work, there are several values I was not able to decode.
The script will pipe the values in the $domains array into the UserFilter registry key. It accepts either top-level domains, IP addresses or Subnets in CIDR notation.
$key = "HKCU:\Software\Microsoft\Internet Explorer\BrowserEmulation\ClearableListData" $item = "UserFilter" . .\Get-IPrange.ps1 $cidr = "^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)/(3[0-2]|[1-2]?[0-9])$" [byte[]] $regbinary = @() #This seems constant [byte[]] $header = 0x41,0x1F,0x00,0x00,0x53,0x08,0xAD,0xBA #This appears to be some internal value delimeter [byte[]] $delim_a = 0x01,0x00,0x00,0x00 #This appears to separate entries [byte[]] $delim_b = 0x0C,0x00,0x00,0x00 #This is some sort of checksum, but this value seems to work [byte[]] $checksum = 0xFF,0xFF,0xFF,0xFF #This could be some sort of timestamp for each entry ending with 0x01, but setting to this value seems to work [byte[]] $filler = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01 #Examples: mydomain.com, 192.168.1.0/24 $domains = @("google.com","192.168.1.0/24") function Get-DomainEntry($domain) { [byte[]] $tmpbinary = @() [byte[]] $length = [BitConverter]::GetBytes([int16]$domain.Length) [byte[]] $data = [System.Text.Encoding]::Unicode.GetBytes($domain) $tmpbinary += $delim_b $tmpbinary += $filler $tmpbinary += $delim_a $tmpbinary += $length $tmpbinary += $data return $tmpbinary } if($domains.Length -gt 0) { [int32] $count = $domains.Length [byte[]] $entries = @() foreach($domain in $domains) { if($domain -match $cidr) { $network = $domain.Split("/")[0] $subnet = $domain.Split("/")[1] $ips = Get-IPrange -ip $network -cidr $subnet $ips | %{$entries += Get-DomainEntry $_} $count = $count - 1 + $ips.Length } else { $entries += Get-DomainEntry $domain } } $regbinary = $header $regbinary += [byte[]] [BitConverter]::GetBytes($count) $regbinary += $checksum $regbinary += $delim_a $regbinary += [byte[]] [BitConverter]::GetBytes($count) $regbinary += $entries } Set-ItemProperty -Path $key -Name $item -Value $regbinary |
You’ll need the Get-IPrange.ps1 script from the technet gallery and you can download the above script here: IE11_CV
IE 11 still supports the older registry key, therefore it is the preferred method not only because the above is a hack, but also because the data is stored in the registry as strings and it supports specific hosts instead of only top-level domains. Again, this script supports hosts, domains, IP Addresses and Subnets in CIDR notation.
$key = "HKLM:\SOFTWARE\Wow6432Node\Policies\Microsoft" if(-Not (Test-Path "$key\Internet Explorer")) { New-Item -Path $key -Name "Internet Explorer" | Out-Null } if(-Not (Test-Path "$key\Internet Explorer\BrowserEmulation")) { New-Item -Path "$key\Internet Explorer" -Name "BrowserEmulation" | Out-Null } if(-Not (Test-Path "$key\Internet Explorer\BrowserEmulation\PolicyList")) { New-Item -Path "$key\Internet Explorer\BrowserEmulation" -Name "PolicyList" | Out-Null } . .\Get-IPrange.ps1 $cidr = "^((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)/(3[0-2]|[1-2]?[0-9])$" #Examples: mydomain.com, 192.168.1.0/24 $domains = @("google.com","192.168.1.0/24") $regkey = "$key\Internet Explorer\BrowserEmulation\PolicyList" foreach($domain in $domains) { if($domain -match $cidr) { $network = $domain.Split("/")[0] $subnet = $domain.Split("/")[1] $ips = Get-IPrange -ip $network -cidr $subnet $ips | %{$val = New-ItemProperty -Path $regkey -Name $_ -Value $_ -PropertyType String | Out-Null} $count = $count - 1 + $ips.Length } else { New-ItemProperty -Path $regkey -Name $domain -Value $domain -PropertyType String | Out-Null } } |
Again, you’ll need the Get-IPrange.ps1 script from the technet gallery and you can download the above script here: IE_CV
I have been trying to run your script, the one that is not a hack, and continue to receive the following error:
Expressions are only allowed as the first element of a pipeline.
At C:\iLOM-Compatibility.ps1:16 char:27
+ $cidr = “^((25[0-5]|2[0-4] <<<< \d|1\d\d|[1-9]?\d)\.){3}(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)/(3[0-2]|[1-2]?[0-9])$"
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : ExpressionsMustBeFirstInPipeline
Any input or resolution would be greatly appreciated.
J. R.
Try single quotes around the regex instead
Thanks Jeff for taking the time to post this. I was hoping since PowerShell’s creators like to think it is the best thing since sliced bread. I was hoping they had a better way of modifying the Binary code. It’s so “VBScript Ish” 🙂 I wish Microsoft didn’t use so many binary registry keys or would make it easier editing certain things like compatibility lists.
Thanks again for your blogs, I love it.
I have deciphered some of the data not previously identified.
This is how I see the data
Header [8 bytes] 0x41, 0x1f, 0x00, 0x00, 0x53, 0x08, 0xad, 0xba
Record Count [4 bytes]
Total Record Length [4 bytes] <- this includes these 4 bytes, but not the previous 12 bytes
Unknown [4 bytes] 0x01, 0x00, 0x00, 0x00
Record Count [4 bytes] (seems to be a duplicate)
Begin Record Sentinal [4 bytes] 0x0c, 0x00, 0x00, 0x00
TimeStamp?[4 bytes]
Record Identifier [2 bytes] (this record increments by 1 for each subsequent entry in all my tests, but is a random value to start with.)
Record Sentinal [6 bytes] 0xd1, 0x01, 0x01, 0x00, 0x00, 0x00
This Entry Length in ASCII Characters [2 bytes]
Data [ASCII Length x 2] Unicode characters
Keep in mind that the items that indicate data segment length are little endian
Pingback: Deploying IE11 with SCCM for the best user experience! | Potent Engineer
Hi Jeff,
I have IE 11.0.9600.17959 in the Reg there are no nodes or keys under Wow6432Node. The \Internet Explorer\BrowserEmulation\PolicyList key is under HKCU(HKLM)\Software\Microsoft along with the clearableListData
I am attempting to testing this prior to scripting and have added a domain as a name on the policylist key and an ip address as the data. Rebooting and testing this does not appear as in compatibility mode for that site? Does including on the list flag compatibility on for that site?
Overall the issue is I have a list of intranet web apps and some are compatible with IE11 and some are not and need the compatibility switched on. An individual user may navigate to either site and we need to avoid having them constantly toggle between compatibility on and off – all under the one domain so cannot be handled on the front end.
Hi Jeff,
I‘ve used your scripts,and found that all added items can be seen in IE COMPATIBILITY VIEW SETTINGS firstly.but you open IE again,the items have disappeared except your first opened website.
hat’s wrong with it?
Thanks again for your blogs
Hi Robin try to un-tick “DELETE BROWSING HISTORY ON EXIT”
Is the script above executed using CMD?
Get-IPrange.ps1 cannot download now.
may you mail me one?
thanks a lot!