$Request vs. $DirObj vs. QADObject, or, The Article I Wish I’d Read Before I Started Messing with ARS Policy Scripts

Quest publishes a guide to ActiveRoles Server script development in the form of a CHM (Microsoft compiled HTML help file), the ActiveRoles Server SDK (Software Development Kit). It comes with the ARS installation package, or you can download it separately from here: http://communities.quest.com/docs/DOC-10017/. Make sure you get the one for your version of ARS, but even if you’re using an earlier version, I recommend also getting the 6.7 one – more PowerShell examples. Even so, get ready to comprehend some VBScript, because that’s what most of the examples are in. It is a reference, not a step-by-step tutorial, and as a newbie to ARS development, I had a hard time getting started with it.

Fortunately, Greg Montoya has distilled the bits about $Request and $DirObj, along with how they stack up to the QAD cmdlets in the article that I insist you read before you do anything to an ARS Policy Script: Working with Data Sets in ARS Policy Scripts – $Request vs. $DirObj vs. QAD Cmdlets

There’s plenty of other wonderful ARS and PowerShell stuff on his site, but this is the article I keep coming back to. Greg explains not only what the intrinsic differences are between $Request, $DirObj and what Get-QADObject (or Get-QADUser or Get-QADGroup or …) each give back to you, but he also discusses performance reasons for choosing one or the other.

“Why won’t it read that attribute? Why isn’t it changing that attribute? I said ‘$Request.edsvaMySpecialAttribute = ($Request.City + $Request.St)‘ – isn’t that clear enough?”

No, it’s not, for several reasons I’ll discuss in my next few posts covering what the beginning ARS scripter needs to know about $Request and $DirObj.


Fun Fact: EDMS:// is to ARS as LDAP:// (or GC://) is to Active Directory

If your organization is anything like mine, you would have a rebellion on your hands if you said that you were taking native AD privileges away, and that any old scripts that relied on ADSI wouldn’t work anymore, but, hey, look – PowerShell awesomeness in the Quest Active Directory Management Shell!

Yeah. Don’t do that. There’s no reason to – ARS has an ADSI provider that works enough like the native AD one that it can be used pretty much the same way.

Here’s a peace offering to accompany the announcement that native AD privileges will be a thing of the past: they can simply do a find on LDAP://whateverserver and replace it with EDMS://yourARSloadbalancer. If their scripts have it in the form of LDAP://distinguishednameonly, it’s simply a matter of replacing LDAP:// with EDMS://. Same with GC:// (uses a global catalog server instead of any old domain controller like LDAP:// will) – just replace it with EDMS://.

I can’t guarantee that this will work 100% of the time, but my colleagues who have tried it report that it has for them, and they are heartily grateful that I’m not making them learn PowerShell yet.

Make sure the script is run on a machine with the ADSI provider for the correct version of ARS installed. Which is installed when you install the Quest AD Management Shell. Which they might later discover is awesome for quick things they used to write nasty VBScripts for.

Related Fun Fact: if you know the DN of an object, referring to it by [adsi]"EDMS://distinguishedname" is usually WAY faster than Get-QADObject -Identity distinguishedname. In my environment, from the interactive shell in PowerGUI, the ADSI way consistently takes less than 0.1 ms, while the nifty cmdlet way takes about 150 ms (YIKES!). The convenience of QAD cmdlets has its price. For command-line one-offs, though, they’re a whole lot of wonderful.

A Mystery Solved with ActiveRoles Change History

This post is a tutorial on both how to look at ActiveRoles change History and User Activity in Quest Active Directory Management Shell (QADMS) and using PowerShell to discover and extract data hidden in objects. Get-QARSOperation is the cmdlet at the heart of this.

Users are mysteriously disappearing from Active Directory, and people are casting suspicious glances your way. Whodunnit?

Fortunately for you, ActiveRoles Server keeps track of that sort of thing, as long as you’ve got Change History turned on. User object deletion is something that ARS tracks by default.

When using an initial, exploratory “Get-” in QADMS, I recommend setting a low return set size limit; here, I’ve used 5. That’s enough to pick up varied results to get an idea of what data is available, but low enough to be quick.

Get-QARSOperation -OperationType Delete -TargetObjectType User -SizeLimit 5

ID InitiatedOn InitiatedBy Status Type Target
-- ----------- ----------- ------ ---- ------

(Loads of info I don’t feel like sanitizing, so I’m just leaving it off)


Get-QARSOperation -OperationType delete -TargetObjectType User -SizeLimit 5 | Select-Object InitiatedBy, Target

InitiatedBy Target
----------- ------


(aaaand… nothing.)

Try again, this time with Format-List:

Get-QARSOperation -OperationType delete -TargetObjectType User | Format-List *

Controls : {13, AllowApproval}
ID : 1-734056
OperationGuid : 87c6ac52-07ec-43e8-abb7-1f7050ae7918
Type : Delete
Status : Completed
Initiated : 10/4/2012 12:22:30 PM
Completed : 10/4/2012 12:22:30 PM
InitiatorInfo : Quest.ActiveRoles.ArsPowerShellSnapIn.BusinessLogic.ManagementHistory.PrincipalInformationImpl
TargetObjectInfo : Quest.ActiveRoles.ArsPowerShellSnapIn.BusinessLogic.ManagementHistory.ObjectInformationImpl
TasksCount : 0

This tells us that the InitiatorInfo and TargetObjectInfo is really inside some objects. What’s in those objects?

Get-QARSOperation -OperationType delete -TargetObjectType User -SizeLimit 5 | foreach { $_.initiatorinfo | fl *; $_.targetobjectinfo | fl * }

Host : <<some pc name>>
Site : <<AD Site pc is in>>
IsDSAdmin : False
DN : <<the distinguished name of the guilty party>>
Guid : <<their GUID>>
Sid : <<their SID>>
NTAccountName : <<their NT account name in domain\username format>>
ObjectClass : user

DN : <<the distinguished name of the victim>>
Guid : <<their GUID>>
Sid : <<their SID>>
NTAccountName : (blank – ActiveRoles Server does not save this by default)
ObjectClass : user

Ok, now we’re getting somewhere. Use some calculated properties with Select-Object to pull the parts out that you want, making new PSObjects with Perp, Victim and Date properties

Get-QARSOperation -OperationType Delete -TargetObjectType User | Select-Object @{ name="Perp"; expression= {$_.InitiatorInfo.NTAccountName }}, @{ name="Victim"; expression={ $_.TargetObjectInfo.DN }}, @{ name="Date"; expression={ $_.Initiated }}

You can then write this to a CSV for future reference and Excel viewing by piping it into Export-CSV:

Get-QARSOperation -OperationType Delete -TargetObjectType User | Select-Object @{ name="Perp"; expression= {$_.InitiatorInfo.NTAccountName }}, @{ name="Victim"; expression={ $_.TargetObjectInfo.DN }}, @{ name="Date"; expression={ $_.Initiated }} | Export-CSV -Path "C:\Logs\UserDeletes-2012Oct04.csv" -NoTypeInformation

Mystery solved.