$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.

ActiveRoles Migration: Deprovisioning/Undoing Deprovisions, or, The Article I Wish I’d Read Before We Started Our Migration

If you read nothing else before you start an ActiveRoles Server upgrade, read Matt Hitchcock’s post about migrating deprovision information: http://sgitpro.com/2011/07/10/migrating-deprovision-information-with-activeroles-server/

Matt discusses an ActiveRoles Server 6.1 to 6.5 migration, but it would apply equally to 6.5 to 6.7 (our situation). This applies to migration scenarios where you are setting up a new database for the new version of ARS. If you are doing an in-place upgrade, it does not. As Matt says in his post, PLEASE try this in your test environment before doing it in production.

Because neither I nor my colleagues had read this, we are stuck keeping a version 6.5 server around for the foreseeable future to allow deprovision/undo deprovision operations on accounts that got caught in the gap between when the first 6.7 server was put in place and when we started having the help desk and local administrators use it.

Our Management History was never imported; it was something our consultant probably intended to do at a later date or to advise us to do, but it never happened, and I’m quite hesitant to do it now that 6.7 has been used for deprovisioning/undoing deprovisions. Here’s what I’ve told the help desk and administrators around the world:

  • If “Undo Deprovision” is not available for a deprovisioned account, that means it was done in 6.5 after 6.7 was installed. Undo the deprovision in 6.5.
  • If “Deprovisioning Results” is available, but clicking it gives you a blank page, that means the deprovision was done in 6.5 before data was imported to 6.7. Undo the deprovision in 6.5.
  • If “Deprovisioning Results” is available, and clicking it gives you a lot of information (“User Account Deprovisioning”, “Exchange Mailbox Deprovisioning”, etc), then it was deprovisioned in 6.7. Undo the deprovision in 6.7.

Lessons that you can learn from Matt’s post and our hard experience:

1) Make sure you have a test environment – ideally, use snapshots of your current real data, but in a sandbox (separate from your live network).

2) You want to import the Management History using Quest’s nifty tool ONCE. That ONCE should be right before you start having the help desk and others with administrative rights on user objects use the new version of ARS for deprovisioning/undoing deprovisions.

3) Once you have decided that user object management will occur in the new version, disable Access Template Links for the help desk and others in the old version. Because the databases are separate in this scenario, a change to an Access Template Link in one version will have no effect on the other, as long as you haven’t been propogating those permissions to Active Directory (which would defeat a lot of the purpose of using ARS – only changes that happen via ARS are captured in Change History!)

It is possible to get the user objects in inconsistent Deprovision/Undo Deprovision states back to rights; however, I’m still working on that – it is going to probably involve finding the affected user objects and figuring out how to parse the ActiveRoles Management History database. Once I figure it out, naturally, I’ll let you know all about it. I will also go into more detail on how to recognize a user object with Deprovision/Undo Deprovision state issues.

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)

Sweet!

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.