Recently @ImADataGuy posed an interesting question on Twitter. Is there an easy way to use Powershell to get the Internet Explorer browsing history for all users on a computer?

If you’ve worked long enough in IT you know that this is a pretty common request by managers for a variety of reasons. But posing it in this way is the start to a pretty deep rabbit hole if you aren’t careful.

It’s one thing to target a single user on a single machine. But how can I make it easy to harvest the browser history for all users for a collection of machines?

The Usual Approach

If you start googling around about this problem, probably one of the first links you’ll find will be an excellent post at Richard Siddaway’s blog.

The code is very good, but there is one problem that makes it unsuitable for our task. That code will only get the browsing history for the user currently executing the code. We want the history for all users.

The problem lies in call to $shell.NameSpace(34). Looking at the MSDN documentation we see that 34 in this call is a reference to an enum that in Windows Server 2008+ type systems just translates to C:\Users\currentUser\AppData\Local\Microsoft\Windows\History. In fact if you change the call to say $shell.NameSpace(“C:\Users\currentUser\AppData\Local\Microsoft\Windows\History”) and insert your user folder name, the script works exactly the same.

But after trying a number of different approaches, including using PSExec to run as the system user, I was unable to solve the fact that trying to get another users history this way just results in permissions errors. It’s just not going to work.

The Solution

The thing is, Nirsoft has already done 90% of the work for us with its BrowsingHistoryView tool. We just need to turn it into a script that will get us across the finish line.

The summary is we give the script the location of the executable, the list of computers, and where we want the files to go. Execute the script and you get a nice tidy collection of csv text files, one per machine, with all of the browser history you need.

I have no idea how NirSoft is getting this information, but the script is short and to the point, and uses a nice, lightweight, standalone executable to get the job done. It also gets all of the history on the machine, not just IE history. Oh yeah, and it’s free.

The problem

I want to use some automation tools to help me keep this contact info up to date, but Windows support for getting this string programmatically isn’t very good. Most tutorials for managing this value involve clicking around in the GUI. Below is the code for a couple easy functions to get and set this value remotely on large numbers of Windows machines, and a helper I wrote for gathering the names of the machines I want to manage based on their Active Directory OU’s, just because that happened to be useful to me. Below the code I’ll talk briefly about how I’m using the functions with Jenkins and Pester testing to automate notifications when someone leaves the company and I need to make sure some one new takes responsibility for a server.

Lets talk about it

Now we have a nice programatic way of getting the contact info for a bunch of servers, but how do we turn that into an actual process?

For me, the answer is that we turn this into a Jenkins job. Many of you are familiar with Jenkins as a build server, but if you think a little more generally, it’s also just a great general task runner, especially for anything that you can express in terms of pass fail testing, and that’s where Pester comes in.

In the Jenkins job the tests look like this:

Gather my list of computers using the Get-ComputersByOU function.

Feed that list to the Get-SNMPAgent function to get your computer and agent objects.

Use Pester tests to examine the owner/server pair to see if the combination is still valid. You can use any logic you like for this test. In my case the current test is simple. Is this user still an enabled user in Active Directory or a valid group. If not it means they probably left the company, and any servers they are still responsible for will be represented by failed Pester tests.

Jenkins takes the Pester output (did you know Pester can output NUnit XML files? It’s fantastic.) and marks the “build” as either successful (all servers have valid owners), or failed and takes action accordingly. In my case it sends me an email that one of my servers needs a new owner.

In a later blog post we’ll look at some of the code to make this happen. It’s very short and elegant and will help ensure that anyone on the network who wants to know something about a server will always know exactly who to contact.