Finding Locked Out Domain Accounts, Or At Least, How Not To

I hadn't posted in a little while, so I thought I'd do a two-fer today.

You might see some advice on the internet about using the userAccountControl attribute to identify locked out domain accounts.  More specifically, the following LDAP filter:

(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=16))

The =16 part should mean "locked out", per the attribute's documentation, keeping in mind that 0x10 in hex is 16 in decimal.

DON'T USE IT.  It doesn't work. I don't think it has ever worked. Apparently it was just an idea that some person on the AD design team had that never got implemented. If anyone has any history on this bit, and if it has ever worked in the past, I would love to hear about it. All I know is that it does not work now.

You can easily verify for yourself that it doesn't work with Powershell:

Get-ADUser -LDAPFilter "(&(objectCategory=User)(userAccountControl:1.2.840.113556.1.4.803:=16))"

You'll probably get 0, or some other very inaccurate value. (Other userAccountControl flags however do definitely work and can be used reliably. Just not this one.)

Here is another LDAP filter you will often see on the web for finding locked out accounts:

(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))

DON'T USE THAT EITHER. That will return too many results.  The reason why is that lockoutTime is not reset until the next time that person successfully logs in. So if an account is locked out, then their lockoutTime attribute gets set, then if the domain lockout duration expires, the account is no longer technically locked out, but lockoutTime remains populated until the next time that user logs in. Now if you're thinking that we should filter this list by only the users who have a lockoutTime that is less than [domain lockout duration] minutes in the past, then you're on the right track. Those would be the users who are still really locked out.

When I type  Search-ADAccount -LockedOut , however, I am given what seems to be an accurate number of users that are currently locked out. I should point out that if working in a large AD environment, I think it's best to point directly to your PDC-emulator whenever possible, because your PDC-emulator will always have the most up-to-date information about account lockouts. From a Microsoft article about urgent replication:

... account lockout is urgently replicated to the primary domain controller (PDC) emulator role owner and is then urgently replicated to the following:

• Domain controllers in the same domain that are located in the same site as the PDC emulator.

• Domain controllers in the same domain that are located in the same site as the domain controller that handled the account lockout.

• Domain controllers in the same domain that are located in sites that have been configured to allow change notification between sites (and, therefore, urgent replication) with the site that contains the PDC emulator or with the site where the account lockout was handled. These sites include any site that is included in the same site link as the site that contains the PDC emulator or in the same site link as the site that contains the domain controller that handled the account lockout.

In addition, when authentication fails at a domain controller other than the PDC emulator, the authentication is retried at the PDC emulator. For this reason, the PDC emulator locks the account before the domain controller that handled the failed-password attempt if the bad-password-attempt threshold is reached.

If you follow my earlier instructions on how to peek inside the Search-ADAccount cmdlet itself, you'll see that Microsoft themselves is keying on the Account Lockout Time to perform this search:

Finally, I can reproduce the same behavior of  Search-ADAccount -LockedOut  with the following bit of Powershell, given that I know my domain's account lockout duration:

Get-ADUser -LDAPFilter "(&(objectCategory=Person)(objectClass=User)(lockoutTime>=1))" -Properties LockoutTime | 
Select Name, @{n="LockoutTime";e={[DateTime]::FromFileTime($_.LockoutTime)}} | 
Sort LockoutTime -Descending | ? { $_.LockoutTime -gt (Get-Date).AddMinutes($AccountLockoutDuration * -1) }

That gives the exact same results as  Search-ADAccount -LockedOut .

So Long, TechNet Subscription.

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?

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
Try
{
    Get-Childitem $BackupPath -Recurse -Force | Remove-Item -Recurse -Force -ErrorAction Stop
}
Catch
{
    "$(Get-Date) - Error during Get-Childitem or Remove-Item: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Return
}
Try
{
    Get-VM -ErrorAction Stop | Stop-VM -ErrorAction Stop -Save
}
Catch
{
    "$(Get-Date) - Error during Get-VM Stop-VM -Save: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Return
}
Try
{
    Get-VM -ErrorAction Stop | Export-VM -ErrorAction Stop -Path $BackupPath
}
Catch
{
    "$(Get-Date) - Error during Export-VM: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Return
}
Try
{
    Get-VM -ErrorAction Stop | Start-VM -ErrorAction Stop
}
Catch
{    
    "$(Get-Date) - Error during Start-VM: $($_.Exception.Message)" | Out-File $ErrorLog -Append
    Return
}
$End = Get-Date
"$(Get-Date) - Hyper-V Backups completed in $([Math]::Round((New-TimeSpan $Start $End).TotalMinutes)) minutes." | Out-File $ErrorLog -Append

A Few Powershell Commands That Have Been Useful To Me Lately

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)

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.