Archive for June, 2010

Jun
10

Custom console tasks: Part 2

Posted by: | Comments (6)

In the first part of the “Custom console tasks” series i described a very simple but powerful way to use the “Tasks” functionality in the Service Manager console to reboot an affected computer of an incident. This time I’m going to show you how we can use PowerShell scripting and some custom Cmdlets I’ve published on Codeplex to create a task that can re-activate (open) a closed incident, something that isn’t possible to do in the console out-of-the-box. Before we go on, please note that according to most process frameworks you shouldn’t re-open a closed incident.

Updated 2011-01-04 since there was a typo in step 6, parameters argument

  1. The first thing you need is the custom Service Manager Cmdlets i published on Codeplex (download here). You can follow the instructions here to install the Cmdlets. Using these cmdlets you’re able to update some incident properties, most importantly for this scenario the “Status” property.
  2. Secondly you need a powershell script that uses the Cmdlets to do all the magic. I’ve written a script that forces the status of an incident to “Active” (no matter previous Status). Since this is kind of hardcore, and should be considered as an override, I wanted to prompt the user for a “reason”. The script accomplishes this by running some C# code that renders a dialog where the user can provide a reason for running the task on the incident. If the user click the “Cancel” button I abort the action and leave the status “as is”. If the user click the “OK” button I go ahead and change status to “Active” (the reason is logged in the action log). 
  3. 2010-11-19 Updated script to work with SMLets Beta 1 or later

    ?View Code POWERSHELL
    param($ID)
    Import-module smlets -Force
     
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
    [void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") 
     
    $objForm = New-Object System.Windows.Forms.Form
    $objForm.Text = "Force Incident Status"
    $objForm.Size = New-Object System.Drawing.Size(400,200)
    $objForm.StartPosition = "CenterScreen"
     
    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter")
        {$x=$objTextBox.Text;$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape")
        {$objForm.Close()}})
     
    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(125,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$x=$objTextBox.Text;$objForm.Close();$result="OK"})
    $objForm.Controls.Add($OKButton)
     
    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(200,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$objForm.Close()})
    $objForm.Controls.Add($CancelButton)
     
    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(10,20)
    $objLabel.Size = New-Object System.Drawing.Size(360,20)
    $objLabel.Text = "Please enter a reason for forcing the incident status to Active:"
    $objForm.Controls.Add($objLabel) 
     
    $objTextBox = New-Object System.Windows.Forms.TextBox
    $objTextBox.Location = New-Object System.Drawing.Size(10,40)
    $objTextBox.Size = New-Object System.Drawing.Size(360,60)
    $objTextBox.Multiline = "True"
    $objForm.Controls.Add($objTextBox) 
     
    $objForm.Topmost = $True
     
    $objForm.Add_Shown({$objForm.Activate()})
    [void] $objForm.ShowDialog()
     
    if($result -eq "OK")
    {
        Set-SCSMIncident -ID $ID -Status Active
        Write-Host "Incident status forced to Active"
        if($x -gt 0)
        {
        	Write-Host "Reason for action: $x"
        }
        else
        {
        	Write-Host "No reason provided"
        }
    }
    else
    {
        Write-Host "Force to active status aborted"
    }
  4. Place the script in a local folder, I use “C:\PowerShell Scripts”
  5. Create a new task in the Service Manager console: Administration – Library – Tasks
    1. Name: Force Activate
    2. Description: Used to force status of incident to active, can be used on closed incidents!
    3. Target Class: Incident
    4. Category: Incident Management Folder Tasks
    5. Command Line: powershell.exe
    6. Parameters: &'.\ForceActivate.ps1' $Context/Property[Type='WorkItem!System.WorkItem']/Id$
    7. Working Directory: C:\PowerShell Scripts\
    8. Log in action log when this task is run: True
    9. Show output when this task is run: True

You’re done! You’re now able to break all the rules and open closed incidents…

This was an example of how powerful tasks can be built using PowerShell and the Service Manager SDK (used by the Cmdlets) to customize the console functionality in Service Manager. I plan to write a final part of this series where we go all the way and use managed code only to create a custom task including a custom WPF form.