Configuration Manager Application Request: Sample Notification and Approval Automation Solution

Update: I have released an installed, configuration instruction, as well as source code for an application similar to the one demonstrated in this blog. Find the information at the folloing site - 

Introduction -

During my last blog post I detailed some of the internal components of the System Center 2012 Application Request and Approval system. Included was a look into the views created in the CM Database, WMI specific data and methods, and finally I’ve shown how to approve or deny an application request using PowerShell. In this post I will be walking through a sample end-to-end application request notification and approval system. This solution is only a sample of what is possible. This blog post is meant to generate ideas and provide sample code that may help fulfill those ideas. There may be items included in this solution that would not work well in your environment. However as you will see, the sample Runbooks are easily modifiable and can be used as a starting point and can be crafted into just about any environment.

The sample solution detailed in this post consists of three Orchestrator Runbooks, a simple custom ASP.NET application, and many of the elements (PowerShell and Data) previously discussed. The goal of this solution is quite simply to provide an email alert to the appropriate approver each time a new application request has been entered into the Configuration Manager system. With this email, the approver will have the ability to approve or deny the application request without having access or the need to access the Configuration Manager console.

All Reference Material for this Blog (Orchestrator Runbook Exports) can be found at the following location – Download. 

Solution High Level Overview –

  • An Orchestrator Runbooks monitors the application approval system (WMI) checking for new requests every two minutes.
  • When a new request is detected, information about the request including the Request UID is placed into an email. Included in this email is a link to the ASP.NET application page on which the application can be approved or denied. This email is sent to the requesting users Manager as defined in Active Directory.
  • Once received, the approver can follow the embedded URL to the approval tool. In this tool the application request can be approved or denied.
  • Once the application has been approved or denied, an email is generated and sent to the requesting user with the approval/denial details.
  • Additionally there is workflow in the solution that will send a follow up email in the event an application request has not been acted upon in a configurable amount days. The solution will also auto deny any request that has not been acted upon in a configurable amount of days.

As you can see, this is a very simple solution in terms of what is being performed, however very nicely builds onto the new Configuration Manager Application Approval System. Without a solution such as this, Configuration Manager provides no email notification of pending application approvals and likewise requires access to the console for all approval activity. 

Solution In Action –

Before digging into the Runbooks and application code, let me show the full end-to-end execution of this solution. This will provide context as we look at the Orchestrator Runbooks, scripts, and .NET code.

Client Side logged in as user –

User navigates to the application portal and selects an application to request.


 Comments are added to the request and the request is submitted.

On the Application Approvers side –

An email alert is auto generated and sent to the requesting user’s manager –


The manager can then follow the embedded URL to the approval application. From this application the approver can approve or deny the request and also add a comment.


Back on the requesting user's end an email will be received notifying of the approval decision. If the application has been approved the installation will begin momentarily .


Additionally if the application request has not been acted upon in a specified number of days a second email (not shown) will be sent to the requesting user’s manager. This email is almost identical to the first however indicates that the request is ageing. Finally if the application request is not acted upon after a configurable amount of days, the request will be auto denied due to inactivity and an email will be sent to the user indicating this (also not shown).


Sample Solution Deep Dive –

Components –

  • Data Manipulation and Active Directory Integration Packs (thes must deployed to the Runbook Designer before importing the Runbook samples).
  • Application Request Gather Runbook.
  • Application Request Action Runbook.
  • Get Email Address Runbook.
  • Approval ASP Application.

Application Request Gather Runbook -

Monitor Date/Time – is configured to execute this Runbook every two minutes.

Get All Application Requests – PowerShell that gathers each application request with a CurrentState of 1 (See Previous Blog for explination of Current State), publishes the Requests GUID.


$app = Get-WmiObject -Class SMS_UserApplicationRequest -Namespace root/SMS/site_<Published Data Site Code > -ComputerName <Published Data Computer Name> | where-object -FilterScript {$_.CurrentState -eq "1"}

foreach ($appr in $app)


$a += $appr.RequestGuid


Gather Data for Each Request – PowerShell that loops through each application request (CurrentState = 1) by Request ID and pulls back information to be placed into the email and also does math on the last modified date in order to determine the next move (First Email, Second Email, Cancel, etc.).

$app = Get-WmiObject -Class SMS_UserApplicationRequest -Namespace root/SMS/site_<Published Data Site Code> -ComputerName <Published Data Site Server> | where-object -FilterScript {$_.RequestGuid -eq “<Published Data Request UID>”}

foreach ($appr in $app) {$comment = $appr.Comments; $user = $appr.User; $appName = $appr.Application; $date = $appr.ConvertToDateTime($appr.LastModifiedDate)}

$today = get-date

$diffd = ($today - $date).days

$diffh = ($today - $date).hours

$diffm = ($today - $date).minutes

if ($diffd -gt 2)


$action = "Cancel"


if ($diffd -lt 1 -and $diffh -lt 1 -and $diffm -lt 2)


$action = "FirstEmail"


if ($diffd -eq 1 -and $diffh -gt 1 -and $diffm -lt 2 )


$action = "SecondEmail"


Get Email Address 1 and 2 – This calls a Runbook that will run a series of data manipulation and Get AD User lookups against the requesting user name. The outcome is an email address for both the requesting user and the user’s manager. I will not detail this Runbook in this blog posting, but the Runbook is provided at the download link.

First Email and Second Email – These two activities send out a very basic email. The content of these emails is made of data from the previous activity. Included in this email is a URL to the application request approve / deny application. This URL is made up of the name of the website plus a parameter of the Application Request UID (Notice the ?UID=) . We will discuss how this application works and the significance of the Request UID later in this post.

Email Body section of the send email activities.

Auto Deny the Application Request – this activity calls the Application Request Action Runbook (See next group for an explanation).


Application Request Action Runbook –

Initialize Data – consumes the Request UID, The approval or denial decision, and comments from the ASP.Net Application or from the Request Gather Runbook (in the event of an auto deny).

Approve / Deny – this activity triggers the WMI method to approve or deny each application request. This script was detailed in my last blog posting.

$wmi = Get-WmiObject -Class sms_userapplicationrequest -Filter 'requestguid = "<Published Data Request UID>"' -ComputerName "<Published Data Site Server>" -Namespace "root\sms\site_<Published Data Site Code>"

if ($wmi)


$rtn = $wmi.<Published Data Approve/Deny>(‘<Published Data Description>’);


Gather Data for Each Request – this is more or less similar to the gather activity of the same name in the first Runbook. Here we are re-gathering the data for the end user Approve/Deny email. I will not paste the code in here, refer back to the last section or download the sample Runbooks and inspect there for more information.

Get Email Address – Gets email address for both requesting user and users manager.

Send Email – Finally once the application has been approved or Denied an email is sent to the requesting user with request status.


Approval ASP.NET Application -

The final piece to this sample solution is the ASP.NET application. There is nothing fancy happening with this application. It quite simply performs the following tasks

  • Consumes the Request UID from the passed URL (recall this was constructed from the Orchestrator Send Email Activity).
  • Queries WMI on the site server for information about the request and displays this on the Web APP.
  • Takes the Approved/Denied value and the entered comments, executes the Application Request Action Runbook, passing to it these two values as parameters.

So putting it even more simply, the application is basically a ‘fancy’ Runbook interface.  This application could easily be replaced with a script, SharePoint, or many other types of interfaces. The value in this form is that it is dynamic (based on the Request UID). Because of this we do not have to store any additional data anywhere. If you think through the process, between the time a user requests access to an application and the time it takes an approval administrator to actually perform the approval, the request is in an idle state. How do we store the request in a format that can be accessible at any time? In this solution it is stored in the form of a URL embedded inside of an email and a dynamic application that consumes the Request ID from the embedded URL.

I will not be providing an installer for this application at this time, however here is some sample code. If there is interest in having an installer package please let me know. Given enough interest I will complete a few remaining items and make it available for download.

App Approval Code
  1. using System;
  2. using System.Management;
  3. using System.Text;
  4. using AppApproval.SCOService;
  5. using System.Data.Services.Client;
  6. using System.Linq;
  7. using System.Configuration;
  9. namespace AppApproval
  10. {
  11.     public partial class _Default : System.Web.UI.Page
  12.     {
  14.         string strUser;
  15.         string strAppR;
  16.         string strAppC;
  18.         string sSiteServer = ConfigurationManager.AppSettings["SiteSever"];
  19.         string sSiteCode = ConfigurationManager.AppSettings["SiteCode"];
  20.         string sSCORCH = ConfigurationManager.AppSettings["SCORCHWS"];
  21.         string sRBUID = ConfigurationManager.AppSettings["RBUID"];
  23.         string sUID;
  25.         protected void Page_Load(object sender, EventArgs e)
  26.         {
  28.             Uri MyUrl = Request.Url;
  29.             string URL = MyUrl.AbsoluteUri.ToString();
  30.             sUID = Request.QueryString.Get("UID");
  32.             ConnectionOptions options = new ConnectionOptions();
  34.             ManagementScope scope = new ManagementScope("\\\\" + sSiteServer + "\\root\\sms\\Site_" + sSiteCode);
  36.             scope.Connect();
  38.             ObjectQuery query = new ObjectQuery("SELECT * FROM SMS_UserApplicationRequest WHERE RequestGuid ='" + sUID + "'");
  39.             ManagementObjectSearcher search = new ManagementObjectSearcher(scope, query);
  41.             ManagementObjectCollection queryCollection = search.Get();
  43.             foreach (ManagementObject User in search.Get())
  44.             {
  45.                 strUser = User["User"].ToString();
  46.                 strAppR = User["Application"].ToString();
  47.                 strAppC = User["Comments"].ToString();
  48.             }
  50.             lblUser.Text = strUser;
  51.             lblApplication.Text = strAppR;
  52.             lblComment.Text = strAppC;
  54.         }
  56.         protected void btnSubmit_Click(object sender, EventArgs e)
  57.         {
  58.             string approve = ddlApprove.SelectedItem.ToString();
  60.             Guid runbookId = new Guid(sRBUID);
  61.             string serviceRoot = sSCORCH;
  63.             SCOService.OrchestratorContext context = new SCOService.OrchestratorContext(new Uri(serviceRoot));
  65.             context.Credentials = System.Net.CredentialCache.DefaultCredentials;
  67.             var runbookParams = context.RunbookParameters.Where(runbookParam => runbookParam.RunbookId == runbookId && runbookParam.Direction == "In");
  69.             // Configure the XML for the parameters
  70.             StringBuilder parametersXml = new StringBuilder();
  71.             if (runbookParams != null && runbookParams.Count() > 0)
  72.             {
  74.                 parametersXml.Append("<Data>");
  75.                 foreach (var param in runbookParams)
  76.                 {
  77.                     if (param.Name == "RUID:")
  78.                     {
  79.                         parametersXml.AppendFormat("<Parameter><ID>{0}</ID><Value>{1}</Value></Parameter>", param.Id.ToString("B"), sUID);
  80.                     }
  82.                     if (param.Name == "Approve/Deny:")
  83.                     {
  84.                         parametersXml.AppendFormat("<Parameter><ID>{0}</ID><Value>{1}</Value></Parameter>", param.Id.ToString("B"), approve);
  85.                     }
  87.                     if (param.Name == "Description:")
  88.                     {
  89.                         parametersXml.AppendFormat("<Parameter><ID>{0}</ID><Value>{1}</Value></Parameter>", param.Id.ToString("B"), txtComments.Text);
  90.                     }
  92.                 }
  93.                 parametersXml.Append("</Data>");
  94.             }
  96.             try
  97.             {
  98.                 // Create new job and assign runbook Id and parameters.
  99.                 Job job = new Job();
  100.                 job.RunbookId = runbookId;
  101.                 job.Parameters = parametersXml.ToString();
  103.                 // Add newly created job.
  104.                 context.AddToJobs(job);
  105.                 context.SaveChanges();
  107.             }
  109.             catch (DataServiceQueryException ex)
  110.             {
  111.                 throw new ApplicationException("Error starting runbook.", ex);
  112.             }
  114.         }
  116.         protected void ddlApprove_SelectedIndexChanged(object sender, EventArgs e)
  117.         {
  119.         }
  121.     }
  122. }

Additionally the following has been added to the <appSettings> section of Web.config file.

Web.config File
  1. <appSettings>
  2.   <addkey="SiteSever"value="Site Server" />
  3.   <addkey="SiteCode"value="Site Code" />
  4.   <addkey="SCORCHWS"value="SCORCH Web Service URL" />
  5.   <addkey="RBUID"value="UID of the Application Request Action Runbook" />
  6.   </appSettings>

Conclusion -

So there we have it, my own custom application request notification and approval add on solution for Configuration Manager. The benefit to a solution such as this is that no longer will there be a need for manual investigation into the current list of applications requiring approval, nor will access to the console be required for the approval to take place. I hope that this post has provided you with an idea on how you would accomplish something similar were you to have the need.

As a reminder all Runbooks detailed in this post can be found on my connect site – Download Site.




Comments (40)
  1. Anonymous says:

    This was a really great post I need a little help getting the web service started as I am new to creating these. Do you have any pointers you can provide. please. thank you.

  2. JamesAvery says:

    Neil, Great Article!!! I’m wondering since this has been over a year now, do you have the ASP.NET code for the web application and any instructions how to configure it in IIS?

  3. Anonymous says:

    Hello,  I am having the same issue as Mats.  It looks like the Get email Address runbook relies on a integration pack that I do have have.  I downloaded the Data Manipulation IP as described above but that does not seem to be the missing integration pack.  It shows as all question marks and cannot display the properties.

  4. Anonymous says:

    That worked for me as well.  Thanks.

  5. Sam, I do not have an installer at this time but will try and get one together shortly. I will post it to this blog if and when I get it completed.



  6. Anonymous says:

    Hei Neil,

    Trying out RunBook, but hav esom e problems with approval site. Any chance to provide your code for "Approval.SCOService" ?



  7. Thanks for the feedback, I have updated this blog to indicate that both the Data Manipulation and Active Director Integration packs must be deployed to the Runbook Designer before importing the sample Runbooks.

    Mats – if you are still having issues with this can you email me offline, I will assist.

    I have also received multiple requests for an installer that will install the Approval application. I have limited cycles at the moment but am working on one and hope to have it published within the next two weeks.


  8. Anonymous says:

    How do you create the program and where do I put it?

  9. I apologize but I am not going to be able to provide a sample installer for this application. All of the code is included in this posing and can be used to piece together the application.



  10. sam says:

    This is Awesome! exactly what I was looking for.Could you please include the installer for the ASP.NET application.Please!!1 my email address is or u can upload it

  11. sam says:

    Thanks Neil.Just a quick question. I am using the Application Approval workflow accelerator so far so good,but when the Reviewer approves the activity on the self service portal the status still remains requested in ConfigMgr,is there a workflow that should set the status to approve?


  12. Liam says:

    Hi Neil, good article, helped me out heaps. I am new to Orchestrator. i am running 2012 SP1 and part of your runbook is not recognised, what can i do about this. and could you also please upload the application. thanks

  13. Mats Nijman says:

    Hi Neil, same here.

    I imported the export in Orchestrator and the run book "get email address" does not work.

    Every icon shows a question mark.

    Hope you can help me with that.



  14. neilnuc says:

    Thanks Mats and Liam, I will look into this today and report back.


  15. Liam says:

    Hi Neil,

    i think i worked it out, i may have been using a newer version of the "Data Manipulation" activity. i worked out what you had and replaced it so im all good now. i would really love that application though



  16. Mats says:

    Hi Liam,

    Wich version did you download and do you have a link?



  17. Mats says:


    I installed the data manipulation pack.

    It shows in SCO, but i still have the question marks.

    and an error that says: the property for this activity cannot be viewed.

    I have data manipulation IP and AD IP.

    Hope to hear from you



  18. Mats says:

    Hi Neal,

    Thanks for your response.

    I fixed it by deleting the runbooks and importing them again.

    I didn't do that after installing the new IP's.

    The application i will try to install myself.

    If i haven't succeeded in 2 weeks i will come back 😉



  19. Neodolphin says:

    Hi Neil,

    First a big thank you for your post, it put me n the right way to code a real approval portal 🙂

    In the "Gather Data For Each Request" part you should add an IF $app is not null because if there is no approval demand with the status pending the script will fail with the error "You cannot call a method on a null-valued expression." and so the runbook

    Like this :

    if ($app -ne $null)


         foreach ($appr in $app) {$comment = $appr.Comments; $user = $appr.User; $appName = $appr.Application; $date = $appr.ConvertToDateTime($appr.LastModifiedDate)}


         $action = "SecondEmail"








  20. pergtron says:

    -If there is interest in having an installer package please let me know.

    I'll let you know that there is massive interest of having an installer package. Im not experienced with at all and would very much appreciate if you could make this guide complete for dummies.


  21. ileal says:

    has anyone been able to figure out the ASP portion?

  22. skyhawk12 says:

    Hey CG! were you able to figure out the approval.scoservice?

  23. ErikH says:

    I would very much like to get the complete picture or installer for ASP side of things. This solution is very elegant and meets my needs perfectly.  



  24. Skyahwk12 says:

    I made some progress on the service. Please read the link below…/60bb3efc-4174-4262-a98f-4f02104c28f8

  25. Maxime77 says:

    Hi Neil and thanks for your great article. I’m not very familiar with ASP.NET, may i ask you an installer for it ? I’ve seen MS solution (SCCM Approval Worflow) but we have to install all System Center’s products before tryint it :/.

  26. ximenjq says:

    This is Awesome! exactly what I was looking for.Could you please include the installer for the ASP.NET application.Please!!1 my email address is or u can upload it thank you!

  27. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  28. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  29. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  30. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  31. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  32. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  33. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  34. Anonymous says:

    Pingback from Liste des outils pour Configuration Manager 2012 | D??ploiement Windows

  35. Huddos says:

    Hi Neil, Nice solution. I am having problem accessing the download link you provided. It states its not published. I’m also wondering if there is a way to update the app request comment when an email is sent so I can append something to it and use it for
    tracking. Seems that when using appr.put() after updating appr.comment it displays invalid method. Thanks Hudson

  36. neilnuc says:

    Please see the updated link at the very beginning of this blog post.

  37. Huddos says:

    Nice, Thanks Neil

  38. Todd says:

    Download link says it has not been published yet.

  39. Anon says:

    Getting the following message when clicking on the link in the e-mail: No application request ID was specified or this application request has already been approved / denied….
    You may have reached this page in error.

Comments are closed.

Skip to main content