Accessing HKEY_USERS With Powershell

by Ryan 19. July 2013 11:18

If you run  Get-PSDrive  in Powershell, you will see that you are given two registry providers: HKEY_LOCAL_MACHINE (HKLM) and HKEY_CURRENT_USER (HKCU).

Given that HKCU doesn't actually exist per se, but is rather just a "projection" or "mapped view" of HKEY_USERS\<Your SID>, that means that the HKCU provider can be problematic in certain remote registry or network logon situations, and of course it's no good at all if you want to view or manipulate the registry of another user.

So how do we access HKEY_USERS in Powershell?  Here are three ways that will work just fine:

Set-Location Registry::\HKEY_USERS
New-PSDrive HKU Registry HKEY_USERS
Set-Location HKU:

And in this last example, I will set the desktop wallpaper for my own user account to cats.jpg, without using HKCU. This way I can run it at system boot, before I ever even log on:

Set-ItemProperty -Path Microsoft.PowerShell.Core\Registry::HKEY_USERS\S-1-5-21-2381515279-1434780867-6353740611-13738\Software\Microsoft\Windows\CurrentVersion\Policies\System -Name Wallpaper -Value C:\Pictures\cats.jpg

Taking a Peek Inside Powershell Cmdlets

by Ryan 8. July 2013 13:18

Have you ever wondered how a particular Powershell Cmdlet works under the hood?  Maybe you're trying to mimic a certain behavior of a Cmdlet, and you'd like to see how Microsoft did it.

Turns out, it's surprisingly easy. The first thing you need is a .NET decompiler. There are many to choose from, but I like DotPeek.

Next, pick a Cmdlet, such as  Get-ADUser . To find the DLL that the Cmdlet comes from, do this:

Cmdlet DLL

If you add a  | clip  on the end there, the output will go straight to your clipboard.

(Did you know the hexadecimal color code for the Powershell background color is 012456?)

Anyhow, now that we know in what DLL the Cmdlet resides, we need to find out what method(s) within that DLL the Cmdlet is actually calling.  We can do that with  Trace-Command :


There's a little more output after that, but this last line here is what we want. Microsoft.ActiveDirectory.Management.Commands.GetADUser.

Now we know the actual .NET method being called, and which DLL it's in. All that's left to do is fire up your .NET decompiler and disassemble!

Get-ADUser DotPeek

So Long, TechNet Subscription.

by Ryan 1. July 2013 18:45

It's been fun.  Got the email this afternoon.  I'm not sure that I'll be able to do much lab stuff any more.  Which means less content for this blog.  Less ability to answer questions on Server Fault through having the ability to quickly verify things.  Less ability for me take the things I've learned and tested and use them for the benefit of my employers.  Less ability to try out the extremely atypical scenarios that I'd get asked in the usual tricky Microsoft exam yet never see in a production environment.

I guess I can still get stuff from TechNet Evaluation Center, but as far as I can tell I'll have to promptly rebuild my entire lab every 6 months, which makes me less inclined.

I'll think of something.  Man, I never thought I'd be saying this, but sometimes I feel like things would be a lot easier on me if I just specialized in Linux stuff.

Psst, You Want A Script To Backup Your Lab VMs?

by Ryan 23. June 2013 09:33

I can hook you up...

So I'm always doing a lot of lab work with Hyper-V virtual machines. Every once in a while I want to just save the state of the entire lab all at once and back it up to a safe storage volume.  I suppose I could set up Windows Server Backup on each of the VMs, and find some disk to use as a pass-through disk for one of the virtual machines and then share that so that the VMs could back up to the network share... but that's a ton of hassle.

How about I just save the state of all the VMs, and export them directly to my backup volume, then resume the VMs, all from the hypervisor?  As a scheduled task, perhaps?

About 10 minutes in the Powershell ISE and I've done just that.  A couple things to be warned of - First, you can't do this in production. The virtual machines are frozen while they're being exported, and it can take several minutes to export a VM. Secondly, make sure you are running with full Administrator privileges, or else cmdlets such as Get-VM will silently return nothing.


# Ryan Ries, 2013
# Backs up some lab VMs. Takes several minutes at least.

[String]$BackupPath = "D:\Backups\Hyper-V"
[String]$ErrorLog   = "D:\Backups\Hyper-VBackups.log"
$Start = Get-Date
"$(Get-Date) - Hyper-V Backups Starting." | Out-File $ErrorLog -Append
    Get-Childitem $BackupPath -Recurse -Force | Remove-Item -Recurse -Force -ErrorAction Stop
    "$(Get-Date) - Error during Get-Childitem or Remove-Item: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Get-VM -ErrorAction Stop | Stop-VM -ErrorAction Stop -Save
    "$(Get-Date) - Error during Get-VM Stop-VM -Save: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Get-VM -ErrorAction Stop | Export-VM -ErrorAction Stop -Path $BackupPath
    "$(Get-Date) - Error during Export-VM: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Get-VM -ErrorAction Stop | Start-VM -ErrorAction Stop
    "$(Get-Date) - Error during Start-VM: $($_.Exception.Message)" | Out-File $ErrorLog -Append
$End = Get-Date
"$(Get-Date) - Hyper-V Backups completed in $([Math]::Round((New-TimeSpan $Start $End).TotalMinutes)) minutes." | Out-File $ErrorLog -Append

In Which I Go Debuggin'!

by Ryan 18. June 2013 17:17

So a couple days ago, I watched what has to be my favorite TechEd 2013 video. I very highly encourage you take an hour and watch it too - but only after you've read this post!  This video finally inspired me to take care of a problem that had been bugging me (no pun intended) on my own Windows machine for several weeks.

On my Windows 7 work laptop, I use Outlook for my work email.  A few weeks ago, I began to notice an odd behavior.  It would happen about twice a day.  I would be doing various different things on my computer at the time, but Outlook was always open, at least in the background.  Suddenly, the system would get sluggish and unresponsive for about 1 minute, and during that one minute, the fan inside the laptop would audibly spin up and my mouse cursor would rapidly switch between a normal cursor and a "wait" cursor with the little spinning ring next to the pointer... exactly like this:

Mouse cursor animation
(*This is the first and hopefully last animated gif I've ever used on this blog, sorry! But it really did look just like that.*)

First thing I did was look at the event logs:

Error in the Event Log

An application fault followed by a couple of Windows Error Reporting messages.  This event would get logged at the exact same time as the foul behavior.  I already had a hunch that 'SearchProtocolHost.exe' had something to do with the Windows Search service.  So I stopped and disabled the Windows Search service.  This completely eliminated the errors and the strange application faults... but... it also had the effect of disabling my ability to search my emails in Outlook.  I get tons of email and I rely on the ability to search my email folders for keywords, so this solution was inadequate.  I had to dig deeper.

Since the strange behavior and the application faults happened pretty regularly and lasted for a while, that gave me ample time to observe the process behavior in Process Explorer:

Process Explorer

The above screenshot doesn't show what I really wanted to show, and that was while this malfunction was taking place, I could see dozens of SearchProtocolHost.exe processes dying and spawning in rapid succession, and also dozens of WerFault.exe (the Windows Error Reporting tool) processes dying and spawning for every SearchProtocolHost.exe that would spawn and then immediately die.

I could see this happening because of the red highlighting and green highlighting in Process Explorer that indicates processes that have either just been created or just exited.

All this crazy process spawning and immediately dying activity in the background is what was causing my epileptic mouse cursor, as well as the general high CPU and disk usage.

At this point I decided I would set up procdump to capture process dumps of this SearchProtocolHost.exe thing whenever it crashed, by typing procdump -ma -i C:\dumps  I already had the Windows Debugging Tools installed, and I already had my symbols properly set up.  Andrew Richards teaches you how to set all that up in the video I told you about at the beginning of this post, as do various other sources you can find readily on the web.

A few minutes later, sure enough I started getting procdump process windows popping up and writing out crash dumps as quickly as SearchProtocolHost.exe was crashing.  It captured about 12 dumps, one for each time the process crashed in rapid succession, and each dump was about 90MB.

I opened one at random. Luckily, this dump was pretty easy. A perfect learning curve for a debugging novice such as myself:


Well the helpful text tells you right off the bat that the .ecxr command will tell you something interesting. (Exception Context Record.)  The only interesting thing I see here is that Windbg does not find symbols for EVMSP32.dll. If your symbol server is already set up, then that is usually a pretty big tipoff that you're working with a non-Microsoft DLL.

Let's try !analyze -v: 

More debugging

This is a little more interesting info. What we have here is the thread stack that caused everything to go pear-shaped. Notice the last thing on the stack before death (stacks grow upward) is some function in EVMSP32.

So what the heck is EVMSP32 already?  Windbg must be reading my mind, because it provides a handy hyperlink to the details of that exact module. Let's click it!




Symantec!  How could you do this to me!?  It was you causing my system to go nuts while you tried to index my email!

Hey, I never asked for Symantec Enterprise Vault. It was a "gift" that corporate IT pushed onto my laptop, oh... about exactly the same time when I started having this problem.

I uninstalled the Symantec Enterprise Vault Outlook Add-in via Programs and Features in the Control Panel.  Problem solved.  No more annoying system behavior or background application faults, and I can still search my email in Outlook.



A Few Powershell Commands That Have Been Useful To Me Lately

by Ryan 16. June 2013 19:30

I've been building lots of new Server 2012 machines lately, which means lots of Server Core, which means lots of command line interface, which means lots of Powershell.

So, a few quick tricks I've found useful the past couple days.

foreach($_ In Get-ADComputer -Filter *) { Invoke-Command -ComputerName $_.Name { Set-ItemProperty -Path HKLM:\SYSTEM\CurrentControlSet\Control\Filesystem -Name NtfsDisable8dot3NameCreation -Value 1 } }

This nifty one-liner grabs all the computer names from Active Directory, remotely disables 8.3 file name creation on each machine.  It's good for filesystem performance, as Windows no longer needs to maintain records of old DOS-style names like FILENA~1.TXT for every file with a long name. Better yet, the Best Practices Analyzer will stop complaining about it once you disable 8.3 file name creation. Unfortunately, MAX_PATH in Windows is still 260 characters. When you hit that limit, you will be extremely annoyed. .NET, and thus Powershell, are especially flummoxed by really long file paths. The Windows API does technically allow you to exceed MAX_PATH by using the \\?\ handle, but you also lose a lot of sanitizing and security features when you perform that bypass.  Note, you need to reboot the machine after changing the 8.3 file name policy.

New-NetIPAddress -AddressFamily IPv6 -InterfaceIndex 13 -IPAddress "2001:2c98:ee9c:279b::3" -PrefixLength 64

 Get used to setting your IP configs with Powershell. Not just IPv4, but IPv6 too. Hmm, speaking of TCP/IP configurations, what else do I need besides an IP address? Oh, yeah:

Set-DnsClientServerAddress -Addresses fd58:2c98:ee9c:279b::1,fd58:2c98:ee9c:279b::2 -InterfaceIndex 13

DNS servers! And of course, if you need to know the index of the network adapter you're working on, it's as simple as Get-NetAdapter.


Which Hyper-V VM Worker Process Belongs To Which VM, PART 2! (And also about IDE and SCSI controllers)

by Ryan 3. June 2013 17:38

It is with great shame that I admit that the information in yesterday's post is not accurate.  Yesterday, I spoke about the "Hyper-V Virtual IDE Controller (Emulated)" performance counters as though they would give you I/O statistics for virtual machines using the virtual IDE controller.

Virtual IDE Controller

Au contraire!

There are only two scenarios in which those counters will show anything useful. Either when the VM very first boots up, for about 1 second before the OS is completely loaded... or, if the Hyper-V VM integration tools are not installed.

See, when the virtual machine has its integration tools installed, then even when the configuration screen about says "IDE Controller," it's no longer an emulated IDE controller. It's a synthetic virtual controller, just like you would get if you used the SCSI controller on the virtual machine.

If the VM did not have the integration tools installed, and was thus using the actual emulated IDE controller, that would mean that the I/O would need extra steps in processing, and it would travel through its vmwp.exe process on the Hyper-V host.  However, if the enlightenments are installed on the VM, the I/O travels through the VMBUS.  This makes the I/O faster, and it explains why when using synthetic devices as opposed to emulated ones means that you can no longer see I/O happening in vmwp.exe, (it should travel straight to the "System" process on the root partition,) nor will you see anything but zeros in the "Hyper-V Virtual IDE Controller (Emulated)" performance counters.

To reassure you that I'm not just making s*$@ up this time, this MSDN blog post says basically the same thing. And so does this even better one.

"The next thing to notice is the “Fast Path Filter”.  This is a filter driver that gets installed on all disk objects in the virtual machine – whether they are IDE or SCSI.  It allows us to pass directly to the VMBUS based path for everything except low level disk operations (like partitioning a disk)."

So there you have it. But unfortunately, this means those counters I mentioned are pretty much worthless now. But all is not lost!  You can still use the "Hyper-V Virtual Storage Device" counters, however, the counters seem to be about how much I/O is being done on the VHD/X of the virtual machine, and not the precise I/O being done by the virtual machine itself.

Not as good, in my opinion, but it's still something.

Also, I'd like to thank Chris S from Serverfault for enlightening me (pun fully intended) and putting me on the right path.

Which Hyper-V VM Worker Process Belongs To Which VM?

by Ryan 2. June 2013 15:13

Warning! This info is not totally accurate! Please read the next day's post for corrections.

I wanted to track down which virtual machine on my Hyper-V host was causing an inordinate amount of disk I/O on my host without logging in to each one.

In Hyper-V, you will notice that on the root partition, you will see one instance of vmms.exe (VM Management Service,) and then you will see a separate instance of vmwp.exe (VM Worker Process) for each virtual machine that is currently running.

Notice that the vmwp.exe processes run under a special user context which contains the GUID that you would find in that virtual machine's configuration files on disk. The same GUID is also supplied to vmwp.exe as an argument as the process is created, like so:

"C:\Windows\System32\vmwp.exe" c83cdee4-1a6d-4f51-9d05-e57df8403ed4

It's not immediately apparent which vmwp.exe belongs to which VM. Furthermore, the I/O charged against each individual vmwp.exe process is not necessarily indicative of what's actually happening on the virtual machine that its hosting. So we'll need to go to the performance counters instead. The "Hyper-V Virtual IDE Controller (Emulated)" set of counters should do the trick, assuming you're using the IDE controller on your VMs.

I have all the information I need now to determine which virtual machine is responsible for the large amount of I/O... but I didn't want to just do it manually. Why not write a reusable tool that can also be run on Core servers with no GUI?

So this simple script, when run on a Hyper-V host, does just that. The output looks like this:

Get-VMPidAndIO | Out-GridView

My VMs were all idle then, hence all the zeros. The screenshot loses all its dramatic flair, but whatever.

The script could easily be enhanced by supporting remote Hyper-V hosts, alternate credentials, etc. But what do you want for 30 minutes?

#Requires -Version 3
function Get-VMPidAndIO
	Gets the Process ID and I/O statistics of each virtual machine running on the Hyper-V host.
	Gets the Process ID and I/O statistics of each virtual machine running on the Hyper-V host.
    Currently only works for VMs using virtual IDE controllers.
    Requires Powershell 3 at a minimum.
    Written by Ryan Ries, June 2013.
            $VMProcesses = Get-CimInstance -Query "Select ProcessId,CommandLine From Win32_Process Where Name ='vmwp.exe'" -ErrorAction Stop
            Write-Error $_.Exception.Message

        Foreach($_ In $VMProcesses) 
            $VMName = $((Get-VM | Where Id -EQ $_.CommandLine.Split(' ')[-1]).Name)            
                              ReadBytesPerSec=[Math]::Round($(Get-Counter "\Hyper-V Virtual IDE Controller (Emulated)($VMName`:Ide Controller)\Read Bytes/sec").CounterSamples.CookedValue, 2);
                              WriteBytesPerSec=[Math]::Round($(Get-Counter "\Hyper-V Virtual IDE Controller (Emulated)($VMName`:Ide Controller)\Write Bytes/sec").CounterSamples.CookedValue, 2); }


Set Windows Update Schedule on Server 2012 Core with Local Policy

by Ryan 31. May 2013 16:46

I'm seeing a lot more Server Core deployments as 2012 adoption increases. Which I think is awesome - I love Server Core. But there are still a couple things that were completely trivial on a GUI edition of Windows that are a tad tricky on Core.

For instance, here I am on Server 2012 Core using the sconfig utility to set up Windows Automatic Updates:


This is just a lab environment, so I don't mind automatic updates and reboots. But I have two Active Directory domain controllers in this lab, and I don't want them rebooting at the same time. So how do I change the "every day at 3:00 AM" schedule so that I can stagger the patching and reboots? On a GUI install it would be trivial of course. Here, not as much.

The first thing I did was briefly look for a registry entry in HKLM:\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\, but I didn't see anything that looked like it would help me modify the Windows Update schedule like I wanted to.

These are domain members, so of course I could use Group Policy to do it, but I didn't want to create and link separate GPOs for each server that I wanted to have a different Windows Update schedule. Plus I wanted to figure out how to do it on non domain-joined machines as well.

Ah - Local Policies! To edit local policies on Core servers, we'll need to connect to them remotely from what I like to call "a tools machine." When you have a bunch of Server Core machines running out there, you should also keep one machine around that has a full GUI install. I personally like to install all my tools (like RSAT) on that one machine, and use it to centrally manage all of the Core machines remotely.

Here I am using mmc on my tools machine to add Group Policy Object Editor snapins for several of the Server Core computers: 

Local Policies

Again, the name of the snapin is Group Policy Object Editor, and target the remote machine as you add the snapin. You'll of course need RPC over TCP connectivity to the remote machine, and you'll need to modify Windows Firewall on the remote machine to allow the incoming connection. (I like to use domain Group Policies for that, so all my machines have consistent firewall settings.)

All that's left to do now is navigate to Computer Configuration > Administrative Templates > Windows Components > Windows Update, and configure the "Configure Automatic Updates" setting for the server. It allows you to modify the hour and the day of the week that Windows Update will download and install updates on that machine.

As per Active Directory Group Policy application precedence, remember that any conflicting domain-based GPO will override settings you make to a machine's Local Policy. 

Lastly - don't forget that automatic update option 4 - "Auto download and schedule the install" - is the only option here that applies to Server Core. The others won't work because Server Core can't "notify" the user of updates the way it could were the GUI installed.

My Entry for the Advanced Event #4 of the 2013 Scripting Games

by Ryan 21. May 2013 12:35

We're on the downhill stretch now. Honestly I'm kind of glad.  These scripts are fun to write, and great practice, but it's work.  I can tell that I'm not the only one loosing steam, as the number of votes on other people's entries has gone way down.  Anyway, about the script I wrote: I like that the #Requires -Modules statement at the top automatically loads the AD module for you if it's not already loaded. I still didn't do the BEGIN/PROCESS/END blocks this time either, which I fail to see how it matters at all, since I'm not dealing with pipeline input... but I'm sure I'll still get crowd scores of 1 and 2 stars for it.  That and dudes with 640x480 monitors going "some of your code goes off the screen why don't you splat!?"  :P

#Requires -Version 3
#Requires -Modules ActiveDirectory
Function Get-RandomADUser
    Retrieves random users from Active Directory and generates an HTML report.
    Retrieves random users from Active Directory, generates an HTML report,
    and then returns the users to the pipeline. 
    Use the -Verbose switch if you want to see console output.
    This Cmdlet requires PS 3 and the Active Directory module. The AD module
    will be loaded automatically if it isn't already.
    The number of random users to get from Active Directory. Minimum is 1,
    maximum is Int16.MaxValue (32767) and the default is 20.
    The filename to write the HTML report to. The filename must end in
    html or htm. The default is .\RandomADUsers.html.
    Gets 20 random users from AD, outputs a report to .\RandomADUsers.html.
    Get-RandomADUser -Count 100 -Filename C:\reports\rpt.html.
    Gets 100 random users from AD, outputs a report to C:\reports\rpt.html.
            [ValidateRange(1, [Int16]::MaxValue)]
            [Int16]$Count = 20,
            [ValidateScript({($_.ToLower().Split('.')[-1] -EQ "html" -OR $_.ToLower().Split('.')[-1] -EQ "htm") -AND (Test-Path -IsValid $_)})]
            [String]$Filename = ".\RandomADUsers.html") 
        Write-Verbose "Retrieving users from Active Directory..."
        $Users = Get-ADUser -Filter * -Properties Department, Title, LastLogonDate, PasswordLastSet, Enabled, LockedOut -ErrorAction Stop | Get-Random -Count $Count
        Write-Verbose "$($Users.Count) users retrieved from Active Directory."
        Write-Error "Unable to retrieve users from Active Directory: $($_.Exception.Message)"
        Write-Verbose "Generating report $Filename..."
        $Header = @'
        <title>Random Active Directory User Audit</title>
            <style type=""text/css"">
                    TABLE { border-width: 1px; border-style: solid;  border-color: black; }
                    TD    { border-width: 1px; border-style: dotted; border-color: black; }
        $Pre  = "<p><h2>Random Active Directory User Audit for $Env:USERDNSDOMAIN</h2></p>"
        $Post = "<hr><p style=`"font-size: 10px; font-style: italic;`">This report was generated on $(Get-Date)</p>"
        $Users | ConvertTo-HTML -Property SamAccountName, Department, Title, LastLogonDate, PasswordLastSet, Enabled, LockedOut -Head $Header -PreContent $Pre -PostContent $Post | Out-File $Filename     
        Return $Users
        Write-Error "Unable to generate report: $($_.Exception.Message)"

About Me

Name: Ryan Ries
Location: Texas, USA
Occupation: Systems Engineer 

I am a Windows engineer and Microsoft advocate, but I can run with pretty much any system that uses electricity.  I'm all about getting closer to the cutting edge of technology while using the right tool for the job.

This blog is about exploring IT and documenting the journey.

Blog Posts (or Vids) You Must Read (or See):

Pushing the Limits of Windows by Mark Russinovich
Mysteries of Windows Memory Management by Mark Russinovich
Accelerating Your IT Career by Ned Pyle
Post-Graduate AD Studies by Ned Pyle
MCM: Active Directory Series by PFE Platforms Team
Encodings And Character Sets by David C. Zentgraf
Active Directory Maximum Limits by Microsoft
How Kerberos Works in AD by Microsoft
How Active Directory Replication Topology Works by Microsoft
Hardcore Debugging by Andrew Richards
The NIST Definition of Cloud by NIST

MCITP: Enterprise Administrator


Profile for Ryan Ries at Server Fault, Q&A for system administrators




I do not discuss my employers on this blog and all opinions expressed are mine and do not reflect the opinions of my employers.