Get Reviewer Details from System Center Service Manager

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.

SMLets Powershell

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

System Center 2012 – Orchestrator

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.

get PowerShell reviewer details from service manager
A look at the PowerShell variables published to the pipeline.

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!