Wednesday, June 27, 2012

Getting AD object metadata via powershell

Occasionally I receive requests in my organization to see when was a user changed, when was someone added removed from a group, etc etc.  I thought it would be nice to get away from repadmin with this and come up with something that can provide enough information, be somewhat easy to use, and not require any special rights or tools.  So I put together this script to pull metadata (either attribute changes, or multivalue changes) on computers, users, or group objects.  In the script, you provide the common name of the object and the type of object.  From here it searches the global catalog for it, pulls the metadata, cuts down the attributes and outputs it in pre-sorted columns.  From there it can be searched or further formated using typical powershell commandlets to manipulate objects.  For those that want to take this further, you can follow the example of how to pull the metadata via ldap and manipulate the XML to include the attributes you want.  Some caveats with this which you won't find in repadmin /showobjmeta is that the times are in Z time, and recording domain controller data is using the domain controller GUID.  So there are some opportunities for expansion and improvement of this script for a more tech oriented audience.




#requires -version 2

param(
 [parameter(mandatory=$true)][alias('samaccountname','cn','username','groupname')]$name,
 [parameter(mandatory=$true)][ValidateSet("Group","Computer","User")]
  [alias('object','objecttype')]$type,
 [switch][alias("members","member")]$valuemeta
)

#Set up connection to forest
$de = New-Object directoryservices.DirectoryEntry("GC://dc=contoso,dc=com")
$ds = new-object directoryservices.directorysearcher($de)

#set an appropriate search filter for each type of object
switch ($type) {
  "group" {$ds.filter = "(&(objectclass=group)(|(samaccountname=$name)(cn=$name)))" }
  "computer" { $ds.filter = "(&(objectclass=computer)(cn=$name))" }
  "user" { $ds.filter = "(&(objectclass=user)(samaccountname=$name))" }
} 

#load up metadata attribs and search
$ds.propertiestoload.add("distinguishedname") > $null
$fu = $ds.findone()
if ($fu -ne $null) {
 $de = New-Object directoryservices.DirectoryEntry("LDAP://" + $fu.properties.distinguishedname[0])
} else {
 Write-Error "Object not found in AD"
 exit 1
}
$ds.searchroot = $de
$ds.propertiestoload.add("msDS-ReplAttributeMetaData") > $null
$ds.propertiestoload.add("msDS-ReplValueMetaData") > $Null
$fu = $ds.findone()

#display the requested type of data
if ($valuemeta) {
 $xml = "<root>" + $fu.properties."msds-replvaluemetadata" + "</root>"
 $xml = [xml]$xml
 $xml.root.DS_REPL_VALUE_META_DATA | 
  Select-Object @{name="Attribute"; expression={$_.pszAttributeName}},@{name="objectDN";expression={$_.pszObjectDN}},ftimeDeleted,ftimeCreated |
  Sort-Object attribute
} else {
 $xml = "" + $fu.properties."msds-replattributemetadata" + ""
 $xml = [xml]$xml
 $xml.root.DS_REPL_ATTR_META_DATA |
  select-object @{name="Attribute";expression={$_.pszAttributeName}},@{name="ChangeTime";expression={$_.ftimeLastOriginatingChange}}|
  Sort-Object attribute
}

<#
.DESCRIPTION
 Show-ADObjMeta will show the attributes and last time written on the object.
 
.PARAMETER Name
 The name of the user/computer/group that you want to pull the metadata for.  This should be the logon
 id if it is a user, the computer name for computers, and the groupname (cn or samaccountname) for groups.

.PARAMETER ValueMeta
 Use this parameter if you want to view multivalue item metadata, like Group Member add/remove details
 
.PARAMETER Type
 Specify the type of object: User, Group, Computer
 
.EXAMPLE
 Show-ADObjMeta -type user -name myuser

 Get the metadata for attributes of myuser
 
#>

2 comments:

  1. Thanks for this! It did take me a bit to figure it out after looking at a few other examples online, but your code above stripped off the "< root >" and "< /root >" so it doesn't work as is. I had to add spaces for it to show up also. Not sure if its my browser or everyone's, but I thought i'd point it out.

    Thanks!

    ReplyDelete
  2. Thanks for pointing that out. I forgot to HTML escape the LT and GT symbols when posting to the site, so the browsers made it disappear. Should be fixed now.

    ReplyDelete