Archive for the 'oneliner' Category

Clear AD attribute

Just yesterday a colleague of mine asked me how to undo an Active Directory object property change from the value he erroneously put back to <not set>. It turned out that I never actually blogged about that – so here you go. 🙂

Clearing AD attributes us actually as easy as just setting the value to $null. For example, here’s how you do it for properties which we have exposed in Set- cmdlets parameters:

Set-QADUser 'Amy Hardy' -City $null

Or for more internal attributes:

Set-QADUser 'Amy Hardy' -ObjectAttributes @{adminDescription=$null}

Hope that helps!


Find group members by location

Today I had to promote a local event to everyone on our cloud taskforce. The distribution list we have for everyone interested in cloud projects is quite large so I thought I would share this one-liner with you.

The first version I tried was quite straight-forward – simply get all team members and filter out the members based on their city:

Get-QADGroupMember Cloud -Indirect |
    where { $_.City-eq "Aliso Viejo" }

However, this actually was quite slow – because the group is big and all the filtering was happening on the client side (all objects were extracted from domain controller and then filtered by PowerShell on my workstation). The solution is to use parameters of the initial Get cmdlet. Get-QADGroupMember unfortunately does not have the City parameter yet, so I used the universal LdapFilter parameter to do the proper filtering.

Get-QADGroupMember Cloud -Indirect -LdapFilter '(l=Aliso Viejo)'

This second one-liner performed almost twice faster – so this is the one I would recommend for large group use!


Get me all groups I manage

Finding all AD groups someone owns is as easy as:

Get-QADGroup -ManagedBy 'Dmitry Sotnikov'

(Obviously put your name, sAMAccountName, DN, email address or another identifier instead of mine. 😉 )

This is one of the nice little features added in QAD cmdlets 1.3.

One interesting modification of this cmdlet is to look for all groups owned by your reports:

Get-QADGroup -ManagedBy (Get-QADUser -Manager 'Dmitry Sotnikov')

Or with some output:

Get-QADGroup -ManagedBy (Get-QADUser -Manager 'Dmitry Sotnikov') | Format-Table Name, ManagedBy

Now you can see which groups maybe you should no longer manage, or find nice unused groups for some safe experiments. 😉

Adding list of users to group

Say, you get an email asking to add a bunch of members to a distribution list you manage. What is the easiest way to do this? Going to Outlook, making 5 clicks to get to the dialog box, and then manually adding each user from the address book picker is definitely not fun. However, PowerShell definitely is.

I’ve seen people submitting lists of members to add in a couple of ways: separated by commas (or semicolons) or each on a separate line. Both would work fine – the only difference is how you would tell PowerShell to split this string into actual members’ names.

Let’s start with a comma-separated list. Like this:

Hey Dmitry,

Could you please add Kirk Munro, Darin Pendergraft, Oleg Shevnin to the PowerGUI DL?


All you need to do, is copy the part of the email with the names, use PowerShell -split operator to break it by comma characters, and pipe the result into Add-QADGroupMember:

'Kirk Munro, Darin Pendergraft, Oleg Shevnin' -split "," | Add-QADGroupMember PowerGUI

That is it!

Line by line option is not much different – you just have to split by newline character ("`n") instead of comma:

'Kirk Munro
Darin Pendergraft
Oleg Shevnin' -split "`n" | Add-QADGroupMember PowerGUI

And by the way, email addresses instead of user names are totally fine too:

',' -split "," | Add-QADGroupMember PowerGUI

One of those cases when command line is so much easier than UI. 🙂

Find large objects in AD

How do you find the user accounts which take up the most space in Active Directory database?

I have just had this very question from a customer who has some BLOB attributes added to user objects and suspect that some of these got much bigger than the others. As result, the overall AD database is now way bigger than the customer would like to have (affecting performance, backups, replication, and so on.)

The problem they had is finding these objects.

My first reaction was: just do a Get-QADUser and sort the objects by size – how much easier can it get? Well, the problem is that there is just no SizeOf function in PowerShell – the system would not tell you how big a given object is.

The workaround I found was very simple. If we cannot get the in-memory size of an object – we can still export it to a file and measure the file size. 🙂

So here is my script:

# Use a different value of SizeLimit 
# if you want a subset of accounts to test the script
Get-QADUser -SizeLimit 0 -IncludeAllProperties | ForEach {
    $_ |  Export-Clixml "$($_.samAccountName).xml"
dir | sort Length -Descending

In a nutshell, all it does is goes through all AD user accounts, and exports each into xml file.

Then I just sort them by size.

The cool part about using ForEach-Object and not keeping all objects in an array is that this is actually very efficient from memory consumption perspective – each object gets cleared from memory after it is saved to xml.

Throughout running the script powershell.exe process was consuming only about 30-40MB of RAM.

One thing to note is that in most domains this script will take a long time to execute (hours). You can make it faster if you can limit the scope of Get-QADUser either by some attributes (SearchRoot, Enabled/Disabled, City, and so on) or properties (I was retrieving all, but if you actually know which properties contribute the most to the size you can include just these properties.) Again, see this post for more consideration on optimizing the script.

Tags: , , , , , ,

AD cmdlets for object undelete

Another great new feature in Quest’s free AD cmdlets 1.2 is ability to locate deleted (tombstoned) Active Directory objects and restore them back.

Locating is very straight-forward: you just add the -Tombstone switch to the Get-* cmdlet of your choice and now your query searches deleted rather than live objects.

Restoring is even easier – all you need is pipeline the deleted objects into Restore-QADDeletedObject.

And the best thing of all is that this works great with Windows 2003 Active Directory – so you can start taking advantage of the feature right away!

For example:

# List all tombstoned user accounts
Get-QADUser -Tombstone

# Restore accounts deleted from a specific OU
Get-QADUser -Tombstone -LastKnownParent 'OU=People,DC=company,dc=local' | Restore-QADDeletedObject

# Restore accounts deleted today
Get-QADUser -Tombstone –LastChangedOn (get-date) | Restore-QADDeletedObject

# Restore a specific deleted user
Get-QADUser -Tombstone –Name 'John Smith*' | Restore-QADDeletedObject

One gotcha to keep in mind is that when objects are tombstoned computer and user objects are stored in AD exactly the same way. This makes Get-QADUser actually return both user and computer objects. Shay found this workaround to make sure that only user objects are returned:

# Return all tombstoned user accounts but no computer objects
Get-QADUser -Tombstone -SizeLimit 0 -ldap '(&(!samAccountName=*$))'

Other Get-* cmdlets which now have these -Tombstone and -LastKnownParent parameters are:

For more information on what a tombstoned object is and how tombstone-based undelete is different from full recovery see Gil’s article here.

Update AD from CSV

Suppose you have a CSV file (a text file with columns separated by commas) with the properties for AD user accounts you want to update. How do you do this in PowerShell?

Turns out, that we talked a lot about creating new accounts from CSV files before, but not about updating existing ones. Let’s fix this right away.

I will be using AD user accounts in my examples, but it is fairly easy to adapt them to other AD objects: groups, computers, OUs, DNS records, and so on.

The command actually depends on the CSV you get. The easiest case is when the column names are exactly the same as Set-QADUser parameters. For example, let’s say you have a CSV file in which you have a samAccountName column which you want to use to locate the accounts to update and Title and Department columns with the new values to set:


The onliner to apply this file to your AD is as simple as:

Import-Csv c:\update.csv | Set-QADUser -Identity { $_.samAccountName }

You basically pipe import into Set-QADUser and specify which column to use as the identity anchor.


Now, suppose that life is not so easy and either you do not control the column labels or you need to update attributes which either do not match the parameter names or have no matching parameters at all. Like:


The automated column matching will not work here but we can use ForEach-Object loop and match the parameters manually + use ObjectAttributes for attributes with no parameters:

Import-Csv c:\update.csv | ForEach-Object {
Set-QADUser $_.samAccountName -Title $_.Job `
-ObjectAttributes @{ExtensionAttribute1=($_.ExtensionAttribute1);

Now we can update from CSV any account properties we want!

Tags: , , , , , , ,

List all Constructed Attributes

Constructed (or computed) Attributes are an important part of the way Active Directory is functioning. Basically, these are not real attributes, in the sense that they do not really exist, but are calculated by AD when being queried. They contain very useful info (for example well known primaryGroupToken and modifyTimeStamp) but they obviously have a few limitations such as not being “settable” or not available for filtering, so knowing which are which is quite useful!

Here’s how you get a list of all computed attributes in your AD:

Get-QADObject -SearchRoot CN=Schema,CN=Configuration,dc=MyDomain,dc=COM -Type attributeSchema -IncludedProperties systemFlags -SizeLimit 0 | where {$_.SystemFlags -band 4}

Basically, this one-liner retrieves all (-SizeLimit 0) attributes (-type attributeSchema) from the Schema partition (-SearchRoot "CN=Schema,CN=Configuration,dc=MyDomain,dc=COM"), together with their system flags (-IncludedProperties systemFlags), and leaves just the ones with FLAG_ATTR_IS_CONSTRUCTED (where {$_.SystemFlags -band 4}).

Thanks to Andrey Moiseev who shared this with me recently!

[UPDATE] Check out Aleksandar’s post on making this oneliner run 40 times faster. 😉

Tags: , , , , , , ,

Finding the latest logon time

How do you find out when was the last time a particular user logged on?

(Get-QADUser username).lastLogon looks like an obvious answer but there are a few gotchas to be aware of.

The main of them: lastLogon attribute is actually not replicated between domain controllers so if you have more than one DC (which I am sure you do) you need to get it from all of them and get the latest of them.

Here’s the PowerShell code which does that:

Get-QADComputer -ComputerRole DomainController | foreach {
(Get-QADUser -Service $_.Name -SamAccountName username).LastLogon
} | Measure-Latest

Basically, we are getting a list of all DCs in the company, then prompting each of them for the user’s lastLogon time, and then picking the latest of the values (I am using my Measure-Latest function – just copy/paste if before executing this command or put in your script.)

Note that there are utilities which can do that querying and comparison for you. NetWrix guys even have a PowerShell cmdlet described here, so you can do something like:

Get-NCInactiveUsers -domain -days 15

You should also keep in mind that if your users do not log off and simply lock their workstations they do not log on either – Kuma is describing here how he has a script logging off users every night to avoid this.

Another alternative is using lastLogonTimeStamp attribute instead. This one does indeed get replicated. It was introduced in Windows 2003 (make sure your schema is 2003-level or later). But keep in mind that this one is not real-time as it is only replicated every 9-14 days.

So as long as you are looking for users who have not logged on for something bigger than 2 weeks you should be good using Shay’s script for locating inactive users:


Get-QADUser -sizeLimit 0 | where {
  $_.lastlogontimestamp -and 
    (($now-$_.lastlogontimestamp).days -gt $daysSinceLastLogon)
} | Format-Table Name, LastLogonTimeStamp

Finally, you can speed things up considerably by constructing an LDAP query and thus doing all the filtering on the server side:

# calculate a deadline date. (now minus 60 days)
$deadline = (Get-Date).AddDays(-60).ToFileTimeUtc()

#construct a ldap query
$ldapQuery = '(|(!(lastLogonTimeStamp=*))(lastLogonTimeStamp<=' + $deadline + '))'

#run this query
Get-QADUser -Enabled -SizeLimit 0 -LdapFilter $ldapQuery

Tags: , , , , ,

AD undelete cmdlets

Darren has just posted a couple of cmdlets that let you list recently deleted AD objects and restore the ones you want back.

Get-SDMADTombstones -Filter Evans | Restore-SDMADTombstones

Very cool! You can download them from SDM Software freeware page.

And if you are still not sure about using this in a command line, I have hacked together a simple PowerGUI pack on top of Darren’s snapin:

AD Tombstone Reanimation cmdlets inside PowerGUI

The AD tombstone reanimation pack is available for download from the PowerGUI library. Now you have free command line and free admin UI to handle AD tombstone reanimation!

Tags: , , , , , , , , , ,

My Recent Tweets


The posts on this blog are provided “as is” with no warranties and confer no rights. The opinions expressed on this site are mine and mine alone, and do not necessarily represent those of my employer - WSO2 or anyone else for that matter. All trademarks acknowledged.

© 2007-2014 Dmitry Sotnikov

March 2023

%d bloggers like this: