Wednesday, July 29, 2015

Microsoft Patches Biggest "Feature Request" with Service Manager 2012r2 UR7

9:03 AM Posted by A No comments
I could not resist using this image

Here we are at UR7 for Service Manager and for better or worse, sarcasm, and negativity aside - it looks like Microsoft has finally seen fit to improve the core product and not focus on just the data warehouse. To what am I referring? "Click Apply and Die".

If you've been working in Service Manager, no doubt you've eventually run into the issue where you create some type of Work Item, hit apply, make some changes, hit apply again and then Service Manager vomits...

 
Just reading the sentence is simple enough, expanding for more information and you may feel you need as though you need to be working on the development team for SCSM to understand what's going on. What's more, if you've never seen the error (or as I'm assuming, you've seen it repeatedly) - eventually you start to realize that the error occurs when you've made a change, out of box SCSM workflows engage altering the state of the work item, and when you try to update the error occurs.

Starting with UR7 for SCSM 2012 R2 - the error is no more! Well. Sort of. I'll be honest, I'm fine with the error so long as I know just what exactly changed...

Which you do now! Way to go UR7! Want to know how I really feel? Scroll to the top and stare at the image longer. Ok. But that's just a text box. It tells me what exactly changed which is useful. I wish I had a better idea that it was happening...


WABAM!!! THAT'S HOW YOU MAKE SERVICE MANAGER ROCK MICROSOFT!

Alright. That...that is pretty cool. To be fair, it should have just been there on day 1.

Hey. Easy there. You sound more cynical than me. Only kidding. I'm with you! If you said the above while witnessing the new UR7 functionality you are not alone! This is one of those things that seems like it should have just been there since release. At least this is something they saw fit to just up and resolve (no less at the SDK level!) and not eschew to vNext. As a result, this doesn't jeopardize any custom workflows you may have created, that you may have purchased from 3rd parties, so in other words...brilliant!

Also an interesting really minor update they made in UR7 -

If a User changes from having a manager in AD to NOT having a manager, the relationship is not updated in the CMDB. With UR7, SM will sync these changes too.

As you may recall, I published a post some time ago about creating Direct Report style requests and in it apart from the two to three custom management packs you'll have to develop to achieve it the one that now I technically have to recount is Travis Wright's blogpost from 2009 and using that as a reference I said "this is how you can get the enabled property of users into Service Manager." Technically speaking, with the above fix you don't have to leverage the Enabled property on said Service Requests anymore. HOWEVER! It doesn't mean that the enabled property within Service Manager can't be useful elsewhere! Maybe reactivate disabled accounts? Ehhh? Ehhh?!?

Seriously. Microsoft. Guys. Girls. SCSM Product Team. Whoever on that development team over there. Way to go and knock out what only can be referred to as an "essential." If this is any indication of your new CEO's company then I politely ask...

Please do not stop

Monday, June 29, 2015

Hello Affected User - I Fixed Your Incident is it OK if I resolve? Hello? Are You There? Anyone?!

9:38 PM Posted by A , 1 comment

I'm not even going to waste time with an introduction, let's just get to the scenario.

You're an incredibly customer service oriented manager/individual/analyst. You follow up with all of your Affected User's once you've resolved their Incident. But before you mark it as "Resolved" in Service Manager you may want their sign-off either via Email or verbal. As such, you may spend an unreasonable amount of time trying to get a hold of the Affected User once you've solved their issue for said confirmation. 


Now I know what some of you are thinking, "Whatever. I'm marking the Incident as Resolved and moving on. I'm not going to waste my time on contacting them. They'll call back if they are really having an issue." Which, sure. That is a valid approach. The cynic in me absolutely agrees with you. However the half of me obsessed with customer service says otherwise. Because if anything, I feel as though I'm being arrogant in my "resolution" I'm assuming that since the Affected User isn't talking I can just mark it as resolved. I really want to show the employee community a lot of love and care. After all they are my customers and I do have to work with them. Plus, I especially don't like this from a reporting stand point either. If anything I'm building some "false" data. Sure I could select the Resolution Category as maybe something more custom like "No Response from Employee" but that the only puts further onus on analyst making a new correct decision and not possibly skewing data again. Blehhh...

Ok, here's my idea. Create a new Status like "Pending User Confirmation to Resolve" underneath your "Pending" status (sure it's a bit wordy, but I'm just trying to be descriptive here). Once an Incident is set to that status, have Orchestrator scour Incidents every day at some specific time in that specific status daily looking to see the last person to update the Incident. If it's anyone but the Affected User, send the Affected User an email asking if the Incident can be resolved. After 5 days of inactivity, begin emailing the Affected User and the Affected User's manager (as defined by Active Directory). Perhaps after 10 days of inactivity, it goes to the Affected User, the Affected User's manager, and then their manager or maybe your IT department's Service Desk manager, etc. etc..

Wow. That seems a bit email spammy. I mean...I get it...but...hrm.

Make no mistake, I'm not saying you should do this. I'm not saying you should try to convince your organization adopt this policy. But what I am saying is "Here's exactly how to do this with Orchestrator and PowerShell if you were the least bit curious so follow along and modify to your needs if you'd like!"


Step 1 - Create the Orchestrator Runbook
As per usual, I'm the first to admit that I'd rather do everything with PowerShell. I know Orchestrator is awesome n all, but the "looping" of activities based on how many times the last one ran...it just gets annoying sometimes. Not only that, this is a scenario where that is going to happen a lot and an unknown amount of times. So I'll do what I can in Orchestrator and then off to PowerShell!


 As I said, the idea here is that...
  1. Everyday at 10am
  2. Get All Incidents with a status of "Pending User Confirmation"
  3. Get the Relationship between the Incident and the Affected user
  4. Get the Affected User
  5. Get the Relationship between the Incident and the Assigned To User
  6. Get the Assigned To User
  7. Create a text file on the Orchestrator server in something like c:\scsm\automation\requestResolutionConfirmation\$irNumber-$affectedUserUserName
  8. Get the Relationship between the Incident and the Trouble Ticket Action Log
  9. As long as the Action Log has items...
  10. Get the Entire Trouble Ticket Action Log
  11. Format the Trouble Ticket Action Log "Entered Date" to a friendlier format like "05-21-2015"
  12. Append lines to the text files that were created using commas to separate values. Each line will look like...
    1. EnteredDate,LogGUID,EnteredBy,AssignedToUserName
      1. You don't have to use the GUID, but I am for the sake of building so you can see you are in fact generating unique Action Log items within the entirety of the Action Log text file. Not to mention, you'll just ignore them in the downstream PowerShell parsing.
  13. Using a PowerShell script file, we're going to...
    1. Read the entire directory of Action Logs
    2. Sort the Action Log's text file's contents by most recently entered date (when they get appended they aren't in order. I can't figure out the reason why Orchestrator picks the order it does). When sorted the most recently entered item will be the first line of the text file.
    3. Parse each Action Log text file's first line (which would be the most recent Action Log item and will get you the last entered date and who entered it)
    4. Use a Get-ADPrincipalGroupMember to enumerate the Enter By user's groups and figure out if any of them are a match to a SCSM analyst group as defined in your Active Directory
      1. If they are (which means the last comment was left by an analyst) then email the Affected User
  14. Finally, delete all the text files created several steps ago
 
Alright. Lay out your Activities
Get all the activities out on your runbook canvas and wire them up in the following order like the above picture
1. Monitor Date/Time
    a. optional: Check Schedule
2. Get Object
3. Get Relationship
4. Get Object
5. Get Relationship
6. Get Object
7. Run .NET Script (PowerShell)
8. Get Relationship
9. Get Object
10. Format Date/Time
11. Append Line
12. Run .NET Script
13. Delete File
 
Deep Breath. Build Time.
 
 
So the first activity is the Monitor Date/Time object and I've set it to 10am. That way every day this runbook will kickoff at said time. Simple.
 
I don't want every day. I just need Monday through Friday or some custom defined set of days for my organization.

No problem and fair point! If you want to do this, we'll need to make the step immediately following this a Check Schedule activity. This activity will then validate if it's running within an acceptable time frame. If you're new to Orchestrator...yes. This does seem like a very roundabout way of scheduling. Just keep spending time in the product and this seeming disconnect of activities will make a great deal more sense.

Optional Steps, Adding a Check Schedule Activity to Ensure this Runbook only runs certain days of the week

 
 
 
Whoa whoa whoa. Where did you get Monday through Friday!? I don't have that.

 
 
 
 
 Finally, when you wire it up to the next activity (Get Object/Get Incidents to Resolve). You'll need to double click the arrow/link between them and set the following.

 
 
In doing this, we are in fact verifying the Check Schedule activity actually conforms to the schedule we care about. This is a hugely necessary step, otherwise you might as well not have the Check Schedule activity there in the first place!

Next, we need to use Get Object which I'll name to "Get Incidents to Resolve". We'll connect to our Service Manager instance and filter incidents whose status is "Pending User Confirmation to Resolve". This activity will run once for every incident it finds. So if there are 12 Incidents in this status it will run 12 times.



Next, let's get our Affected User of the Incident. We'll do this by using a Get Relationship activity and another Get Object (renamed Get Affected User) immediately afterwards.

 
 

In our "Object Guid" text field for this Get Relationship activity, we'll right click and select Published Data. Then we'll select SC Object Guid from "Get Incidents to Resolve" in our previous step.


 
 

Now in our Get Affected User (Get Object) activity, we'll select the following. Our Class is Active Directory User (i.e. the Related Class of our Get Relationship activity). For our filter's we'll add one for SC Object Guid and set it equal to the Related Object Guid of the previous step. I put that in bold letters, because I want to draw attention to the very fine distinction between it and other similar sounding things in that last.


 
 

Finally, we need to return only Affected User from those Incidents. To ensure we'll only get the Affected Users and not "Created by" or "Assigned To" double click the arrow between Get Relationship and our Get Affected User activity. Then go to "Exclude" and hit the Add button.


 
 
 Now click on the text that was just added to the list and select Relationship Class.

 
Now change equals to does not equal and change value to Affected User. Then hit Finish.



So before we keep just hauling along, what have we done here exactly? Why was this step important? If you're new to Service Manager or Orchestrator, you may not frequently think about all the types of things stored in just an Incident. There is an Affected User (Active Directory User), there is an Assigned To user (Active Directory User), there is a...and the list goes on. Had we not added this step, we'd return all the related Active Directory User's as they relate to a single instance of an Incident. By using the Exclude tab, we can throw out all the users/relationships we don't want to appear downstream. This is important for the following step...

Our Get Object activity (renamed Get Affected User) will use a filter of SC Object Guid from the previous step. BUT! Since we told the previous step to only return user's whose class as it relates to the Incident is the Affected User - we know confidently that this activity, regardless of how many times it runs will always be the Affected User object's of the Incidents and nothing else.



Next, we'll do almost the same exact thing but instead for the Assigned To user. So grab a Get Relationship and Get Object and wire them up after Get Affected User. When you are wiring up this Get Relationship don't forget to get the SC Object Guid from the Get Incidents to Resolve step and not the previous step!



The only difference between the following and above steps is the Link between our new Get Relationship and Get Assigned To user, will be an exclude condition for "Relationship Class does not equal Assigned To User"

 
 

Again, immediately following our Get Relationship activity we'll have a Get Object that will be renamed Get Assigned To.



Next, we need to create a Text File for each one of the Incidents we need to evaluate to alert on. To do this, grab a Run .NET Script activity from System Activities. These text files will be created on the Orchestrator server so you may want to go create a directory for SCSM Automation tasks such as this one on Orchestrator's C: drive.

Ugh. Text files? Are you kidding me?

No. I'm not kidding you. This is one of those "Come on Orchestrator!" jabs I can't help but have because we'll be using this as a crutch for two things...
  1. SMLets while documented working within Orchestrator aren't perfect. I'm a huge fan of them, but since they are open source, it means you're on your own in terms of support and troubleshooting. Specifically, I tried them about 78 different ways in the eventual PowerShell script that is going to do the notification but the "-smobject" parameter always passes null. As a result we had to do all the building up until this point to get Assigned To, Affected User, etc.
  2. We need a way to store the Action Log (temporarily), sort, parse, and evaluate it. If this can be done in Orchestrator it is beyond me how it could be accomplished. So I'm moving to simply building the data I need, store it, do all my logic in a PowerShell script, and then delete files as I go within the script before a final "clean up" activity.
  3. Alright. I really seriously hate that it's 2015 and I've had to resort to text files for this. Also, it means this list 3 things instead of 2. Just...ugh. You know what. It's fine. It's fine. I'm moving on.

 Our Run .NET Script activity is a PowerShell file one liner.


Since I can't resize those windows, the PowerShell line I have is...
new-item c:\scsm\automation\requestResolutionConfirmation\{ID from "Get Incidents to Resolve"}-{UserName from "Get Affected User"} -ItemType file

Which means our file once created will have a file name like IR25083-dzaka.txt

So now we have text files, for every incident in this status, with the affected user's username in the title of the file separated by a hyphen. Next let's start writing the Action Log into the text files to do that it's time to Get Relationship.

Are you getting the hang of this yet?
 
Again, wire up to your Service Manager instance, define your Object Class as Incident, set the SC Object Guid equal to your "Get Incidents to Resolve" step from the beginning. Then set the Related Class to Trouble Ticket Action Log.

Then grab your Get Object next (renamed to "Get Action Log Items")

 


And of course once again, grab a filter property, set the SC Object Guid equal to the Related Object Guid from your previous Get Relationship (IR to Action Log) step.

Holy crap when is this over...

Don't worry, we're really close. That was step 9 out of 13 or 14 depending on if you had the extra Schedule activity at the beginning. Onto step 10! Format the Entered Date date of the Action Log.


Using the Format Date/Time Activity, we just take in the Entered Date as published data from the previous step of Get Action Log Items and change the Output Format to be MM-dd-yyyy.

NOTE: Do not change this output format unless you plan on also changing the format in the final PowerShell script!

Now in our penultimate step (Append Line), we're going to format the order of the data that is going to go into our text files we created a few steps back.


As you can see the order in the append line is...

1. Format Result from "Format Date/Time"
2. SC Object Guid from "Get Action Log Items"
3. Entered by from "Get Action Log Items"
4. Username from "Get Assigned To"

This text files contains NO SPACES and has comma separated values for the final step of PowerShell parsing. Ready? Because here's the script...


PowerShell Parsing, Just a Bit of Lead In
Again, as I opened this post I'm doing what I can in Orchestrator (setting up all my data) and then going to do the actual parsing/logic/notifying with raw PowerShell code. I've tried formatting this code the last several days now and it's...it's just really frustrating. So here's a link to the PS1 file on my TechNet page.

Since the TechNet article doesn't do much in the way of a description it's worth pointing out the following in the script...

Line 1: Edit to be your Orchestrator's server name
Lines 58-72: Service Manager stores the entered by value as domain\username. 3rd party companies such as Cireson store it as the display name. If you are leveraging multiple technologies I draw attention to this section so you can continue to do so!
Line 78: You will have to have your Support Tier groups as actual Active Directory groups in order to the match.
Line 81 + 87: This is the actual "Days Past" logic in action. Get creative here! 0 days past I did nothing. 1 day past I emailed...and then two days past you could email...
Line 105: Change to use your SMTP server

In summary, the script is parsing your Action Log text files trying to figure out the following...
1. Who was the last person to update the Action Log?
2. Was that person an Analyst or the Affected User?
3. If it was the Affected User, I won't take any action because they must have said something and the analyst didn't take it out of this special status yet
4. If it was an Analyst, I will take action because I'm assuming the analyst must be asking something since it's still in this status


The other thing that I'm personally divided on in this solution is who the email should come from? It could come from the scsm workflow account's email address that is used by your Exchange connector so when the Affected User hits reply it updates the Incident. Then again, it could be spoofed to come from the analyst so it looks like more of a personal touch/communication. In either scenario, the Exchange Connector would process the email assuming you put your scsm workflow account's email address in the CC field. Since the only match it does is the FROM SMTP address field it's your call. Get creative!


In Closing...
I hope SOMEONE found this helpful!

SQL Reporting - A Tip on "Affected User" Reports

8:16 PM Posted by A No comments
 


I previously published a blogpost detailing how to get started with an Affected User report and it struck me as I was working the other day that there was arguably vital step I had missed. So if you haven't noticed it, corrected my work, or possibly using it in your own reporting this is your heads up!

There are some cases where an Incident in the report will return itself multiple times. It may not be obvious, but you will see every Affected User the Incident has had.

What? How is that possible? I want to yell at you.

Alright. I welcome the criticism in this case, so before you go on a tirade let me explain why that happens. The WorkItemAffectedUserVw table contains a property called DeletedDate. This date will generally be null, but when you flip the Affected User of an Incident the field has value. Needless to say, this only takes an extra step in the WHERE clause to make sure you grabbing the current Affected User.

WHERE user.DeletedDate is null

WITH THIS said. I've already updated my TechNet posting to calling out in the comments how to quickly turn this on/off for yourself. The query has had nothing altered with the exception of the single extra WHERE statement. The link hasn't change so feel free to get the updated version here.

Saturday, May 9, 2015

Service Manager - Employee Management, Part 3

3:51 PM Posted by A 4 comments

NOTE: Times have changed and so have my opinions. Please read this first - http://scsmmercenary.blogspot.com/2016/02/in-defense-of-class-extension-vs.html


I've been working on this post for awhile, because the first two posts are relatively straight forward in comparison (here's Part 1 and Part 2). In addition, there are a few posts out there that while walking you through this (new) employee scenario don't answer some fundamental issues such as...
  • Dynamically placing a user in an Organizational Unit within Active Directory
  • Dynamically creating a username based on username availability
  • Add the new user to multiple groups
To be fair I don't think the points are addressed for two reasons...
  1. The post would be crazily lengthy (like this one is about to be) because it can't possibly cover all the variables you'd want to take advantage of in your respective organization
  2. With point one made, for the sake of brevity the posts are addressing the core question of - How do you create a user through Service Manager and Orchestrator?
So, no one's fault really. Makes sense to me. But you will undoubtedly ask the same questions once some kind of unique scenario comes along and you're forced to re-think it all through. I'll try to get through as many as I can so hopefully what I'm about to get into will save you those future headaches, give you some new ideas, and possibly ways to alter other requests you already have.

Let's Go Get that Service Request in Orchestrator
First thing's first. We need to start building the runbook that is going to parse our custom Service Request class we've been building so as to create an employee within Active Directory. To do this we'll start with three core activities.
  1. Initialize Data (runbook control activity)
  2. Get Relationship (service manager activity)
  3. Get Object (service manager activity
Again, you're free to call these whatever you'd like. But I'm going to rename those activities in my runbook too...
  1. Initialize Data
  2. Get Relationship (Runbook to Service Request)
  3. Get New Hire Account SR
Wire them up and then let's get started.




Here's how we'll configure each of the activities:

Initialize Data
Change Parameter 1 to "ActivityGUID"


Get Relationship (Runbook to Service Request)
 
  1.  Change your Connection to your Service Manager system. This is defined through Orchestrator -> Options -> SC 2012 Service Manager. Mine is just called Service Manager, if you manage multiple environment you have/want multiple connectors like "Production" and/or "Development"
  2. The Object Class will be set to Runbook Automation Activity
  3. The Object GUID is published data from the previous step. Right click in this text area, select Published Data and pick ActivityGUID from the previous step
  4. Related Class is the class we've been creating. I called mine "Service Request, Human Resources". Now you may see why! Because I know in the possibly giant list of class to pick from exactly where to find the class I made. It's a normal Service Request + my HR customizations. Just easy for alphabetical sorting is all.

When it comes to Service Manager and Orchestrator (if you've never done this before), is we keep bouncing back n forth between one object in the system to another. This is commonly expressed through the use of the "Get Relationship" activity which we'll be using quite a bit. Another way to think about this is an Incident. An incident has a title, but it has relationships to Active Directory users. Like Created By, Affected User, Assigned To, Related Configuration Items, etc. The use of the "Get Relationship" activity will become increasingly clearer as we move through this and other requests.

Alright so we have the basis for this thing setup. When the runbook executes from within Service Manager, it will call Orchestrator and figure out the relationship between itself and it's parent Service Request. So right now we're just querying data. That's all it will do!


 Let's Go Get an Available Username
 Next, we'll need to build a username for our new user. But I want to get a little creative and scour Active Directory first for availability before continuing on in my runbook and possibly shooting myself in the foot downstream. To do so, we're going to turn to our trusty friend PowerShell so head over to System Activites and grab a "Run .NET Script"


 Once you open it up, change the Type to PowerShell. Then use the following code (forgive the formatting, blame Google):
$session = New-PSSession -ComputerName YOURORCHESTRATORSERVERHERE  
$result = Invoke-Command -session $session -ScriptBlock {
$firstName = "Published Data - NewHire First Name"
$firstName = (get-culture).TextInfo.ToTitleCase($firstName.ToLower())
$lastName = "Published Data - NewHire Last Name"
$lastName = (get-culture).TextInfo.ToTitleCase($lastName.ToLower())
$fnLength = $firstName.Length

if (($lastName.IndexOf("'") -ne -1)
{
  $lastName = $lastName.Replace("'", "")
 
}
elseif (($lastName.IndexOf("-") -ne -1))
{
  $lastName = $lastName.Replace("-", "")
 
}
elseif (($lastName.IndexOf(".") -ne -1))
{
  $lastName = $lastName.Replace(".", "")
}
else
{
  $lastName = $lastName
}
$x = 1
while (($x -le $fnLength))
{
  $username = $lastName + $firstName.Substring(0,$x)
try
{
  # A user was found. Lame.
$U = Get-ADUser $username -ErrorAction Stop
}
   
catch [Microsoft.ActiveDirectory.Management.ADIdentityNotFoundException]
{
  # The user was not found! We're using this one!
break
}
  $x++
}
  new-object pscustomobject –property @{
username = $username
}
 
}
 $availableUsername = $result.username


If you're new to using PowerShell within Orchestrator - there are a few issues you'll bump into that are not worth flipping tables over. Especially in the getting started phase! So let's clear something up first.

PowerShell through the eyes of Orchestrator is a 32bit process running PowerShell version 2 

That means things you probably take for granted like "Get-ADUser" and other necessary commands aren't available. BUT! There is a way around it and it's featured above. Since PowerShell v2, 32bit isn't capable of the above I just wrapped the entire script inside of another script. A script that runs on the local Orchestrator server running Server 2012r2 with 64 bit, PowerShell 4. Woot! Hence the funky bit on the end of the script where we take the available username we found, publish it from Orchestrator's Server, back onto the 32 bit Orchestrator databus, and thus in turn a variable we can make use of downstream in our runbook. Yes. It's annoying. That's all there is to say about that. Back to the script!


You'll have to change three variables in the above script. First, you'll have to change it to the name of your Orchestrator server. Next, you'll have select Published Data from your Get New Account SR for your first and last name. I also from the start of the script take into account possible grammar mistakes for someone typing the new hire's name in. So someone can't type ADAM DZAK and that's how the account get's created. It all gets formatted to lowercase, then uppercase the first letter in each word. In the lines following I account for the potential ridiculousness of naming consistency in an Active Directory environment by removing apostrophes, extra periods, hyphens, etc. Obviously you don't have to use these, but when it comes to usernames I wouldn't mind some consistency. Secondly, the username is getting formatted like Last Name + First Letter of First name. So if I ran this script against myself I'd get dzaka. On the next pass I'd get dzakad. Etc. Etc. As you can see it doesn't take much to rework this part to your needs.

Finally I make sure this Run .NET Script Publishes data to consume in the "Create User" activity for Active Directory:

Update our Service Request
I end up doing this a lot in my SR, but now that we have the username we can update the "Employee Username" property. It's really simple. Just use a "Update Object" activity. Select the Class as "Service Request, Human Resources" (or whatever you called your class) and grab the "Employee Username" property and update it with Published Data from "Get Available Username"


This may open up a few more ideas like changing the Title of the Service Request from your templates stock "New Hire" to "New Hire - Adam Dzak". We'll get to that step later (post Active Directory creation). But just a heads up this a great way to keep customizing your environment and improving user experience for not just your business but your IT department as well.

Let's Get the Manager
I know we haven't built the Request Offering yet, but here's how we'll configure our Runbook to get the manager from the Service Request. We'll use two activities to do this, Get Relationship and Get Object.


To configure these activities, let's start with Get Relationship (SR to AD Manager). Use your Service Manager Connection you used originally, define the Source Class as "Service Request, Human Resources", the Object GUID is the SC Object GUID of Get New Account SR. The Related Class is Active Directory User.



Next, the link between both will get the following exclude treatment. Just double click the arrow between both to bring up this menu.


In the Link properties, head to the "Exclude" menu and change it to contain the above. Relationship Class from Get Relationship (SR to AD Manager) does not equal Is Related to Configuration Item. What we've done here is say "Get me all Active Directory users that are related to the Service Request, but only get me the ones that are 'Is Related to Configuration Item'"

Let's dissect this a bit. A Service Request will have a few users associated to it upon submission. Created By and Affected User. When we build our Request Offering to allow the selection of a manager, we'll store that selection in the "Related Configuration Items" tab of the Service Request. Bringing the total Active Directory users related to the SR to 3. This above link lets us uniquely identify this Relationship and pass the singular object (user) into the next activity of Get Object. So instead of 3 users, we only get 1.

Finally, let's grab the Manager object. We do this simply using "Add" selecting "SC Object Guid" and using the published data of our previous "Get Relationship" step. We do this by selecting the "Related Object Guid"


I want to repeat that because it bears repeating. "Related Object Guid" not to be confused with the other ones.




If you've made it this far, here's what the runbook should look like by now.



When you think about it, we have pretty much everything we need to build our employee. We have the all the employee properties stored in the Get New Account SR, we have the username from our Get Available Username PowerShell script, and we have the manager stored away in the Get Manager object.

Neat. What about the OU?

I have one guess as to why the OU topic isn't tackled elsewhere, because it requires more PowerShell. Well I could be wrong. But it's the way that makes the most sense to me.

You'll need to create a custom PowerShell script that takes the selected "Department" value and translates that somehow into an OU match.

This is where you need to have some Active Directory planning in mind plus an idea of how you are going to add items to your Department's List in SCSM that you created in Part 1 of this blog series. Let's say you have a Department List in Service Manager that looks something like...

  • Administration
  • Accounting
  • Information Technology
    • Developers
  • Human Resources

Here's what I'm getting at. You'll need a PowerShell script that essentially does the following. So grab a .NET Script, wire it up after your Get Manager activity, and rename it to something descriptive. Such as Get OU to Place, then via its Published Data, you publish out the variable myOUPath. This variable is then ultimately used in the "Create User" Active Directory activity. Since we are just playing with strings in the script, we don't need to use 64bit PowerShell on our Orchestrator server.

$department = "Published Data - NewHire Department"
if ($department -eq "Accounting")
{
$myOUPath = "OU=Accounting,DC=domain,DC=com"
}
elseif ($department -eq "Developers")
{
$myOUPath = "OU=Developers,OU=Information Technology,DC=domain,DC=com"
}
However with the above said, this means all the departments in your Departments List must be uniquely named for the purposes of this Get OU to Place script. Personally I don't see the drawback to this because I can't envision where a company would have two departments with the same name. BUT! Even if they did, all you'd have to do is rename the department in the list to have a bit more clarity and then problem solved. For example, if you had two departments called "Developers" you just change the name in the list to "Developers for IT" and "Developers for Accounting" as child items underneath each. Whichever he case, I'm open to suggestion here. However it's how I'm going to continue along in this runbook building my employee for dynamic OU placement.

What about their password?

A few ways to accomplish this, but it has nothing to do with custom PowerShell code!
  1. Statically define it in the Create User activity.
    • Your security folks probably won't like this
    • If you need to change it, you need to check out the runbook. Not ideal either
  2. Statically define it in the Create User activity and add some dynamic value
  3. Dynamically define the whole thing
Options 2 or 3 are the most favorable. Plus it's really easy to do using the Generate Random Text activity from the Utilities area of Orchestrator.


When it comes to the Create User activity, we just use this activities Published Data to set the password. Now how you choose to share the password is up to you and all sorts of interpretation. Here's a really quick, no real extra work in Orchestrator thing you can do...
  • Use a "Send Email" activity to email the manager (which you have by now) the new user's password
  • Write it out to a file somewhere that only certain people have access to on your network
The point is - lot of options herethat you can/should tailor to your environment's needs and standards.

Finally, the moment you've been waiting for
Let's drop the Create User activity into our runbook. Wire it up and start pulling out the following properties:
  • Common Name
  • Department
  • First Name
  • Last Name
  • Manager
  • Container Distinguished Name
  • Password
  • Title
  • User Principal Name
  • Change Password at Next Logon
Values you set are probably obvious at this point - a whole lot of Published Data!
  • Common Name - CN={EmployeeFirstName from Get New Account SR EmployeeLastName from Get New Account SR}
  • Department - EmployeeDepartment  from Get New Account SR
  • First Name - EmployeeFirstName from Get New Account SR
  • Last Name - EmployeeLastName from Get New Account SR
  • Manager - Distinguished Name from Get Manager
  • Container Distinguished Name - myOUPath from Get OU to Place
  • Password - Published Data from Generate Random Text
  • Title - EmployeeTitle from Get New Account SR
  • Sam Account Name - availableUserName from Get Available UserName
  • Change Password at Next Logon - true
I want to note something here. I used FirstName space LastName as the Common Name. Maybe you want to use the AvailableUsername property here? Same thing goes for the UserPrincipalName - maybe I want to use the same? Maybe I to do FirstName.LastName - the point is you can get creative here and mix statically defined values plus Published Data. So no reason you couldn't just type a password and add the Published Data from the Generate Random Text value. This all depends on your environment! If you want to make sure you are adding spaces and other characters, right click in the area to input values and hit "Expand". This will give you a resizable window to drop values into. Purely a view thing worth bringing up.

The last step is to grab Enable User from the Active Directory activities and feed it the Distinguished Name published data from the Create User  activity.

BOOM! You got a user created.

Add the User to Groups...with an s
I know there is a "Add to Group" activity within the Active Directory activities, but it's only one group! I can only add a single group?! One group?! What good is that? What if they are in different departments? This will always be different! To PowerShell!

Much like the Find OU to Place PowerShell script, we need to do something similar with dynamically adding certain groups based on the...you guessed it... Department value as picked from the Department List.

$department = "Published Data - NewHire Department"
$samAccountName = "Publishd Data - Create User Sam Account Name"
if ($department -eq "Accounting")
{
Add-ADGroupMember -Identity "accounting group" -Members $samAccountName
Add-ADGroupMember -Identity "this other group" -Members $samAccountName
Add-ADGroupMember -Identity "some other group" -Members $samAccountName
}
elseif ($department -eq "Developers")
{
Add-ADGroupMember -Identity "accounting group" -Members $samAccountName
Add-ADGroupMember -Identity "this other group" -Members $samAccountName
Add-ADGroupMember -Identity "some other group" -Members $samAccountName
}

Now, this is messy. I'll grant you that. If you have a lot of departments, then you have a lot of PowerShell code to account for all the scenarios. It certainly gets the job done, but as you can see could become unmanageable.

BUT! I like it because it means I have a single place to edit the default groups that users get when they are created or switch departments (the Service Request, Human Resources request that we've be building here if you haven't already surmised would lend itself really well to the idea of automatically transferring departments. You could use the same lists, the same scripts, etc.) So there are a bit of two sides to this and you can probably guess where I fall.

Don't forget, if you go this route you'll have to wrap it inside a 64 bit PowerShell script. That said the above becomes the following:

$session = New-PSSession -ComputerName YOURORCHESTRATORSERVERHERE
$result = Invoke-Command -session $session -ScriptBlock {
$department = "Published Data - NewHire Department"
$samAccountName = "Publishd Data - Create User Sam Account Name"
if ($department -eq "Accounting")
{
Add-ADGroupMember -Identity "accounting group" -Members $samAccountName
Add-ADGroupMember -Identity "this other group" -Members $samAccountName
Add-ADGroupMember -Identity "some other group" -Members $samAccountName
}
elseif ($department -eq "Developers")
{
Add-ADGroupMember -Identity "accounting group" -Members $samAccountName
Add-ADGroupMember -Identity "this other group" -Members $samAccountName
Add-ADGroupMember -Identity "some other group" -Members $samAccountName
}
}

Again, replace the Orchestrator server with your Orchestrator server's name. However unlike Find OU to Place you'll notice we aren't publishing any data back onto Orchestrator's databus so that step isn't used.



Whew. Alright. That's that. Next post we'll wrap this entire thing by building the Request Offering that we'll present to end users on the Service Manager portal.

Any questions so far? Need help with something? Find me on TechNet or Twitter.

Part 4 is here