Dec 222014

This is an experimental PowerShell script that looks at all the physical network adapters on a machine and verifies that they are at or above an arbitrary link speed set in the script. It works by querying the MSNdis_LinkSpeed class in WMI, filtering out non-physical adapters, and then checking each one to make sure the link speed is above the $MinSpeed value that you set. It then returns TRUE or FALSE.

I believe it is useful to use a greator than or equal to comparison instead of saying that all links must equal the minimum speed, especially in server environments where you may have a mixed environment of some servers with gigabit links for instance, and then another set of servers or virtual machines with 10gig links.

I don’t see this being useful in a PC environment because you have less control over what a desktop is hooked in to at any given point in time. Though it may still be useful if you want to enforce such a policy, like trading floor must be at gigabit or higher, and you want to catch non-compliance.

Obviously I can’t account for every InstanceName that isn’t a physical adapter. If there is a better way, by all means let me know and I’ll modify the script, but here it is!

# Robert's experimental NIC speed compliance script. 
# Emphasis on EXPERIMENTAL. 
# It will not break anything but it may not give back a sane result. 
# Manually check suspect compliance, bad compliance will probably come
# from non-physical nics where I didn't account for the InstanceName
# below when it came from MSNdis_LinkSpeed. 

# Minimum allowed speed in megabits. 
$MinSpeed = '1000' 

# This is used for compliancy.
$NonCompliant = 0

# Get link speed for all physical network adapters. 
$nics = Get-WmiObject -Namespace root\wmi -Class MSNdis_LinkSpeed | where {`
$_.InstanceName -notlike '*miniport*' -and `
$_.InstanceName -notlike '*WAN*' -and `
$_.InstanceName -notlike '*1394*' -and `
$_.InstanceName -notlike '*ISATAP*' -and `
$_.InstanceName -notlike '*Bluetooth*' -and `
$_.InstanceName -notlike '*RAS*' -and `
$_.InstanceName -notlike 'Direct Parallel' -and `
$_.InstanceName -notlike '*tunnel*' -and `
$_.InstanceName -notlike '*6to4*' -and `
$_.InstanceName -notlike '*Deterministic*' -and `
$_.InstanceName -notlike '*miniport*' -and `
$_.InstanceName -notlike '*kernel*'

# Go through list of NICS and make sure speed is above $MinSpeed
foreach ($nic in $nics) {
    #Make the link speed in megabits instead of bits.
    $LinkSpeed = $nic.NdisLinkSpeed/10000

    #See if this NIC is compliant.
    if ($LinkSpeed -lt $MinSpeed) {

# Am I compliant?
if ($NonCompliant -eq 0) {
    write-host TRUE
    } else {
    write-host FALSE
Nov 232014

The following detection script accomplishes the following.

  • Determines if virtual memory is automatically managed. The desired configuration according to the script is that the pagefile should be managed manually (true can be changed to false if you want to go the automagic route).
  • If the pagefile is not automatically managed, the script determines if the size of the page file is at least double the amount of visible physical memory.

I’m working on a remediation script, but for now I figure’d I would share the love.

# This script simply checks to see if Windows is handling the page file
# automagically. Then if no, it verifies to make sure that the swap file
# is set at or over twice the available memory. 

$system = get-wmiobject -Class win32_ComputerSystem

if ($system.AutomaticManagedPagefile -eq $true) {
    write-host FALSE
    } else {  

    $mem = get-wmiobject -Class win32_OperatingSystem | select-object TotalVisibleMemorySize,TotalVirtualMemorySize

    [int64]$vismem = $mem.TotalVisibleMemorySize
    [int64]$vrtmem = $mem.TotalVirtualMemorySize

    if ($vrtmem -ge ($vismem * 2)) {
        write-host TRUE
        } else {
        write-host FALSE


Nov 112014

Here is a way for you to keep your EMIE site list up to date using CI. Enterprise Mode IE is Microsoft’s method for allowing backwards compatibility with sites that do not fully support Internet Explorer 11’s Edge mode. I don’t go into detail about how to set up EMIE, more information on how to set it up can be found via MSDN.

First we start with the detection script. This script returns the version number of your site list XML. Be sure to replace the $file string listed with the correct path and file name of your EMIE list XML.

# EMIE XML Version Check (Detection) Script for CM12 Compliance Settings
# by Robert Hollingshead

# November 11th, 2014
# Find more CM12 Compliance Setting scripts at!

# Supress error messages.
$ErrorActionPreference = "SilentlyContinue"

# Enter the path and name of the XML file here. 
$file = '{enter path and filename here}'

# Get the XML Content and then unwrap its tags into individual lines.
# We could leave out the split method and just go by the entire InnerXml,
# but IMHO, this way makes more sense and is friendly to ANY 
# odd modifications of the remediation script should they be needed. 

Try {
    [xml]$sites = Get-Content $file
    $unwrappedsites = $sites.innerxml.split('</>')

    # Look for the rules version, split out the line, 
    # and output the second string which will be the
    # version itself. 

    ForEach($line in $unwrappedsites) {
        if ($line -like "*rules version*") {
            write-host $line.split('"')[1]

    # If the split of $sites failed, we'll catch it and
    # spit out versin 0 to indicate the file doesn't exist.

    } catch {   
    write-host 0

The detection script is going to return the current version of the XML file on the client, not a true or false. So your compliance rule will be equal to the version you want all your clients to be at. How to get that updates can be done via this remediation script. First thing, there are two values that must be changed, the $version, and the $file strings. $version will be the equal to the version you want all your clients to be at. Make sure  you have it set to the same version as in your compliance rule or you’ll never be compliant. The second is the $file string, which will be the same as in the detection script.

Next  you will add all the domains. There are four lines beginning with “$domain = New-Object PSOBject.” We are building an array of Domains as well as if they are to be excluded or included in EMIE. Each domain will be a TLD. True means “exclude this site from EMIE” and is useful for preventing an intranet site from running in compatibility mode. False means “include this site in EMIE” and is useful for placing a site on the internet in compatibility mode, or if the site is setting its compatibility via META tag and you wish to override. Here is the script, stay tuned after the script for a few notes.

# EMIE XML Update (Remediation) Script for CM12 Compliance Settings
# by Robert Hollingshead

# November 11th, 2014
# Find more CM12 Compliance Setting scripts at!

# This script keeps your EMIE (Enterprise Mode IE 11) XML up to date.

# Enter the resultant version here. This is your XML list version.
# Increment when there are changes. 
# Make sure that you change the compliance rule to match. 
$version = "{enter version number here}"

# Enter the path and name of the XML file here. 
$file = '{enter path and filename here}'

# Setup Array for domains and the resulting xml 

[system.array]$domains = $null
[system.array]$sitesxml = $null

#Add domain here.
#False indicates that EMIE should run for non-intranet site. 
#False also indicates that EMIE should run for intranet sites that are saying they are
#compatible via server meta tag.
#True indicates that EMIE should not run for intranet site. 
# Copy the following four lines for each new domain. Don't forget to increment the version
# if you make any changes. 
$domain = New-Object PSObject
$domain | Add-Member -membertype noteproperty -Name Domain -Value "{tld like}"
$domain | Add-Member -membertype noteproperty -Name Exclude -Value "{false or true}"
$domains = $domains + $domain

#Now let's write out the XML. We build an array that will be written out to file. 

# Compile the version line and the opening EMIE tag.
$line = New-Object PSObject
$line = ''
$sitesxml = $line
$line = '  '
$sitesxml = $sitesxml + $line

# Compile the domain tags.
ForEach ($domain in $domains) {
    $line = '    ' + $domain.Domain + ''
    $sitesxml = $sitesxml + $line

# Compile the closing tags.
$line = '  '
$sitesxml = $sitesxml + $line
$line = ''
$sitesxml = $sitesxml + $line

# Output to the file. 
$sitesxml | out-file $file

write-host TRUE

Obviously there is some room for improvement in this script. While I can include TLD’s right now, I cannot include subdomains just yet, that ability will be forthcoming in another update of this script, or if you wish to update it yourself and contribute back that is fine too.


Jan 212014

Recently I encountered a little trap with the VB Replace() function. Beware that if you only use the required parameters, like…

strString = Replace(strString,"{find}","{replacewith}")

…it does a binary only comparison. This can muck up instances where you intend to replace a known string, but some instances may come up with mixed case.

W3 Schools has an excellent reference page on replace() here.

Binary only is case-sensitive. The solution is to use textual, which is case-insensitive:

strString = Replace(strString,"{find}","{replacewith}",1,-1,vbTextCompare)

The parameters 1,-1,vbTextCompare is as follows:

  • 1 means “start at position 1”
  • -1 means “find all instances”
  • vbTextCompare is a constant (literally 1), that tells the function this is a text comparison. It’s alternate is vbBinaryCompare.

This can save a headache later on when you’re dealing with an scenario where case in strings are questionable, I would assume it’s always questionable unless you are looking explicitly for a binary match.

But I didn’t make VB. Oh well.