Last Update: Sep 04, 2024 | Published: Apr 16, 2014
Recently I worked on a project that had a requirement to determine who reviews a review action flow in Service Manager, and then communicate where those reviewers were in terms of action approval. In essence, we needed to know who could review the actions and what their status was in making those actions. A simple task, and one I assumed which would only take a few minutes to accomplish in System Center 2012 – Orchestrator. Man was I ever wrong!
Why? Well, for reasons best answered by the gremlins, under no scenario was I able to get a set of activities to link up and return the Active Directory details of my reviewers. Instead, the best I could accomplish was an alien reviewer number, which was totally useless as I had no way of reverse engineering this with the activities offered. Getting the status of the review actions for these “numbers” was easy, but half a story is worth nothing. Today I’ll show you how to use PowerShell to get reviewer details from Service Manager.
Without overthinking my issue, I stopped and considered that at some point I will move over to the Service Management Automation platform anyway, which is pure PowerShell. With this in mind, I crafted a function that leveraged the SMLets module from codeplex so that I can pass in the ID of the Review Activity, which I need to get the data on. Cobbling my first version of a function, I did not have the normal error handling addressed, as you can see below.
Set-ExecutionPolicy -ExecutionPolicy Unrestricted function Get-SCSMReviewers { param( [string]$ReviewActivityID=$(Throw “Parameter ‘Mailbox’ cannot be empty”) ) begin { Import-Module ActiveDirectory $smdefaultcomputer = "FQDN OF THE SCSM MANAGEMENT SERVER" Import-Module SMLets } process { $RA = Get-SCSMObject (Get-SCSMClass System.WorkItem.Activity.ReviewActivity$) -Filter "Id -eq $ReviewActivityID" $relRev = Get-SCSMRelationshipClass System.ReviewActivityHasReviewer$ $relRevUser = Get-SCSMRelationshipClass System.ReviewerIsUser$ foreach ($Reviewer in Get-SCSMRelatedObject -SMObject $RA -Relationship $relRev) { $ReviewerUser = Get-SCSMRelatedObject -SMObject $Reviewer -Relationship $relRevUser $ReviewerUPN = $ReviewerUser.UPN $UserDetails = get-aduser -filter {(UserPrincipalName -eq $ReviewerUPN)} -Properties mail | select Mail, GivenName $ReviewerProperties = @{ Veto = $Reviewer.Veto MustVote = $Reviewer.MustVote Decision = $Reviewer.Decision Comments = $Reviewer.Comments DecisionDate = $Reviewer.DecisionDate Class = $ReviewerUser.ClassName UPN = $ReviewerUser.UPN FirstName = $ReviewerUser.FirstName LastName = $ReviewerUser.LastName Mail = $UserDetails.Mail ReviewerGUID = $Reviewer.ID UserGUID = $ReviewerUser.ID } New-Object PSObject -Property $ReviewerProperties } } }
With this module loaded you can easily get the details which I needed to learn, by simply issuing the command
Get-SCSMReviewers -ReviewActivityID RA123
Now, you will notice that I also exposed two GUID in the return of the query. This serves the purpose of exposing the hooks, which I can then use to connect any of the remaining in box activities, including update reviewer.
So, using the .NET Script activity in Orchestrator to get a nice clean set of results on the pipeline, I used the code block shown below. One thing you will notice is that I am loading up the Active Directory module, which drops us directly in the x86 vs x64 problems of Orchestrator. So to work around this, I spanned a new PS session to get directly into x64 mode and then passed back the results to the calling shell.
Note: Keeping the sample short, I have not included the full function from above. Again, you will need to merge this in your pasting.
#Define the Variables $SCSMVeto = @() $SCSMMustVote = @() $SCSMDecision = @() $SCSMComments = @() $SCSMDecisionDate = @() $SCSMClass = @() $SCSMUPN = @() $SCSMFirstName = @() $SCSMLastName = @() $SCSMMail = @() $SCSMUserGUID = @() $SCSMReviewerGUID = @() #Define the Functions $ReviewerDetails = Powershell { function Get-SCSMReviewers { param( [string]$ReviewActivityID=$(Throw “Parameter ‘Mailbox’ cannot be empty”) ) .... CUT TO SAVE REPEATING FUNCTION ... } #Get the Reviewers $ReviewerInfo = Get-SCSMReviewers -ReviewActivityID {INSERT ORCHESTRATOR VARIABLE} return $ReviewerInfo } #Prepare the results foreach ($Reviewer in $ReviewerDetails) { $SCSMVeto += $Reviewer.Veto $SCSMMustVote += $Reviewer.MustVote $SCSMDecision += $Reviewer.Decision $SCSMComments += $Reviewer.Comments $SCSMDecisionDate += $Reviewer.DecisionDate $SCSMClass += $Reviewer.Class $SCSMUPN += $Reviewer.UPN $SCSMFirstName += $Reviewer.FirstName $SCSMLastName += $Reviewer.LastName $SCSMMail += $Reviewer.Mail $SCSMUserGUID += $Reviewer.UserGUID $SCSMReviewerGUID += $Reviewer.ReviewerGUID } #Echo the results to the console for pipleline pickup (not required) $SCSMVeto $SCSMMustVote $SCSMDecision $SCSMComments $SCSMDecisionDate $SCSMClass $SCSMUPN $SCSMFirstName $SCSMLastName $SCSMMail $SCSMUserGUID $SCSMReviewerGUID
With the extra work for the wrapper complete, we now just need to configure the Publishing tab on the .Net Script activity, offering a nice name for the pipeline and then referencing the associated variable from shell.
Now all you need to do is drop this new activity onto your flow, and you can easily start constructing some procedures to remind reviewers that they are holding up progress.
On a final note, as the commands above are to be run on the Runbook server, you need to ensure that your copy of SMLets is installed and working on the node before this flow will actually work! Yes, sounds totally obvious, but I had two hours of grief not checking the module was working correctly!