I always get asked about reporting from my customers, and specifically around SLA’s. SLA’s are very important to most companies as this is part of the tracking mechanism of employees and vendors and the like.

SMLETS is needed for this, SMLets, it is built to be run from the server, if you need to run from your local machine, please install SMLets, copy the SDK Binaries folder and use the -computername where applicable with the SMLets commands.

I have customers that are “multi-sourced” and the vendors are also using the System Centre Service Manager (SCSM) environment. As such, the request came from my customer to create an easily readable and “exportable” SLA report. The requirements were as follow.

  1. All Incidents, Service Request, Change Requests and Problem Requests
  2. Assigned To Information
  3. Created By Information
  4. ID
  5. Impact
  6. Urgency
  7. Priority
  8. Classification / Area
  9. Created Date
  10. Resolved (yes / no), if yes, provide the resolution detail
  11. Last Modified Date
  12. Last but not least SLA Information (if there was an SLO / SLA assigned)
    1. SLA Name
    2. SLA Status
    3. Target End Date

As you can see the list is extensive, yes I know I could have built an SSRS Report, however my SQL skills are not the best and I LOVE PowerShell. So, I decided to do the following with PowerShell and with the use of SMLets I decided to build this report purely in PowerShell and write the content to an HTML file and then make the content of the HTML file the body of the email.

The full code can be found here, I will highlight the main components / challenges, please feel free to use/abuse my code. Please note that this code is used at your own risk as always. PLEASE TEST!!!

The customer wanted to get the file as an attachment and as the body of email, for this I used a switch statement based on the “WorkItemType”, I then changed the class for the get-scsmobject criteria based upon the workitemtype. Once all the information was gathered, I joined all the files to create a final file containing all the information, all I can say here, is that you are going to spend a fair amount of time looking at HTML code (or at least I did), I highly recommend both BlueGriffon and NotePad++ to assist with this. To get the SLA information, I used the “System.WorkItemHasSLAInstanceInformation$” class to get the SLA information with another switch to cater for an item that has no SLA. I also looked at the history to retrieve the “Last Modified Date”.

To get all the information I needed into a manageable format, I used a custom PowerShell Object and added all the information into the object. From an object the data can be easily manipulated into the required format. Basically I write the information from each object out into individual files to meet the customer’s needs and then combine these HTML files (hence spending a lot of time ensuring all my HTML Tags were properly closed) into one “complete HTML file as well.

For the emailing of the information, you need to specify the “TO”, the rest I gather from the system itself, as we know the relay that the server is using can send messages and the “From” address will be correct.

Follow me,

Twitter (Personal & System Centre)

Twitter (System Centre Focused)

So, here is the scenario, we managed a lot of customer’s System Centre Operations Manager (SCOM) environments. One of the most common issues we run into, it is the “Grey Agent” issue, where an agent is no longer reporting into SCOM. There might be a few reasons for this, however one of the most common and effective ways to fix this to clear the agent cache. By this, we simply mean connecting to the agent, stopping the “SCOM” service, deleting the content of the “Health Service State” folder and then restarting the “SCOM” service.

Yes, this is a perfect candidate for PowerShell and their a quite a few scripts that do this in numerous ways using PowerShell, I have a script for this, but they are usually dependant upon a list of some and then loop through this, I decided to use my friend, System Centre Orchestrator (SCO) to facilitate this is in a time manner, with more flexibility and log building as well as inputting the results into a database. With SCO, we also have more avenues available to us for error handling, like logging a call within SCSM or “richer” email or the like.

So, I have learnt with SCO, the best thing to do is to actually sit down and whiteboard you solution, simply draw out the steps you want to follow and think of some error handling. With my example, my logic was as follows. I have added a VIsio diagram as my handwriting is barely legible even to me :)

1. Query Database for grey agents, there is a SQL Script for this.

2. Create Folder for logging

3. Read SQL results into a file for “’looping”

4. DNS Test

5. Ping Test

6. Determine Service Name and folder path (Remember we might be dealing with multiple versions of SCOM here

7. Check Service status, to determine if a stop of the service is needed

8. Stop if needed

9. Delete files

10. Wait 10 Seconds

11. Start Service

12. Write log to Database

SCOM_GreyAgentFix

The SQL query will be part of the Runbook file, it can be found here, please change the extension to .ois_export.

Have fun automating.

(E-Mail me)

Follow me,

Twitter (Personal & System Centre)

Twitter (System Centre Focused)

So, it has been a while.

SO, the requirement for this project was as follow.

1. Use Service Manager

2. Provide a portal for logging a VM Creation request.

3. Build the computername based on a predetermined pattern.

4. Determine first available name

5. Perform a capacity check.

6. Deploy the set number of VMs.

I am going to skip over the first 2 Points, there are numerous topics covering this. So, onto point 3, I created a Service Request Extension, if anyone would like some info on this, also plenty of articles, please let me know and I can do a blog post on the Extension, or I can make the extension available for you to seal yourselves. Anyways, I mapped all the prompts required within the Request Offering and published it to SharePoint Service Manager Portal.

So, now it is onto the Computername Pattern, for the sake of my customer’s privacy, I will not use there exact naming pattern, but rather use XX-YY-Z type of naming, to give you the idea. Of course, Loving PowerShell the way I do, I turned to old faithful.

I will provide the basic PowerShell code in snippets and allow you to expand onto it as you see fit, I built in a fair amount of specific error checking for my customer which will NOT be included in this post.

The Quest Commandlets will be needed for these scripts. The code is being re-formatted due to the blog hoster. Please change the required values.

#================================================================================
#build computer name

$businessApplication = <"value"> #now from ORC as part of SR
$function = <"value">  #now from ORC as part of SR
$location = <"value"> #now from ORC as part of SR
$affinity = <"value">  #now from ORC as part of SR
$role = <"value">  #now from ORC as part of SR
$businessUnit = <"value">  #now from ORC as part of SR

#naming convention
#1 letter - BusinessUnit
$businessUnit = $businessUnit.Substring(0,1)
$businessApplication
#3 letters - location
$location = $location.Substring(0,3)
$location

#placecholder (-)

#1 letter - role
$role = $role.Substring(0,1)
$role

#1 letter - Function
$function = $function.Substring(0,1)
$function

#tiebreaker (XXX)

#3 Letters - Business Application
$businessApplication = $businessApplication.Substring(0,3)
$businessApplication

#1 letter - Affinity
$affinity = $affinity.Substring(0,1)
$affinity

$computernamepattern = $businessUnit+$location+"-"+$role+$function+"XXX"+$businessApplication+$affinity
$computernamepattern

$computernametocheck = $computernamepattern.Replace("XXX&","001")
$computernametocheck

$part1 = $computernamepattern.Substring(0,7)
$part3 = $computernamepattern.Substring(10,4)
$part2 = $computernamepattern.Substring(7,3)

#==============================================================
#Check if computer name exists

Add-PSSnapin quest.ActiveRoles.ADManagement
$i = 1
do
{
  $computername = $part1 + "{0:D3}" -f $i + $part3
  "testing $computername"
  $test = get-qadcomputer $computername
  if ($test)
  {"Computer Exists"}
  Else
  {$computerstartname = $computername}
  $i++
}
until ($computerstartname -ne $null)

#==========================================================
#create computers

$part1 = $computerstartname.Substring(0,7)
$part3 = $computerstartname.Substring(10,4)
$part2 = $computerstartname.Substring(7,3)
[int]$partnumber = $part2.Substring(2,1)
$computerstobeCreated = ''
$computersRequested = "<Value_from_Orc>";

$computersCreated = 0
$filepath = 'C:\Tools\testing.txt'
New-Item -Path $filepath -ItemType file

do
{
  $newcomputer = $part1 + "{0:D3}" -f $partnumber + $part3
  #New-QADComputer -Name $newcomputer -ParentContainer "OU=Test Computer Accounts,OU=System Accounts,DC=bui,DC=co,DC=za"
  write-host $newcomputer
  write-host $computersCreated
  Add-Content -Path $filepath -Value $newcomputer
  $computersCreated++
  $partnumber++
  $computerstobeCreated = $computerstobeCreated + "" + $newcomputer
}
while ($computersCreated -le ($computersRequested-1))

$computerstobeCreated = $computerstobeCreated.Substring(1)

#======================================================================================= 

I  check the nodes within the Cluster and then find the node with the least amount of Virtual Machines on it. Then use this node information for the creation of the VM. Now time for the free space, since this was a Cluster, I simply used the free space attribute within PowerShell and Virtual Machine Commandlets. I get all the CSV information and then sort by the free space and select the first object as this one would have the most amount of free space.

This is a basic capacity check as per the customer’s requirement, as part of this a field within Service Manager is updated to allow some more information to be shared within the members of the team working on this request.

#==========================================================
#Check for placement issues

$VMCluster = <"value">

$VMMServer = <"value">

$numberOfVMS = <"value">

$hostmachinedomain = (gwmi WIN32_ComputerSystem -ComputerName $VMMServer).Domain

$ClusterFQDN = $VMCluster +"."+$hostmachinedomain

$nodes = (get-scvmhostcluster -Name $VMCluster).nodes 

$colPlacementInfo = @()

#$placementInfo = New-Object system.object

foreach ($node in $nodes)
{
  $placementInfo = New-Object system.object

  $placement = (Get-SCVMHost $node).AvailableForPlacement

  switch($placement)
  {
    "True"
    {
      $placementInfo | Add-Member NoteProperty -name Placement -value "True";
    }
    "False"
    {
      $placementInfo | Add-Member NoteProperty -name Placement -value "False"
    }
  }
  $colPlacementInfo += $placementInfo
} 

If ($colPlacementInfo.placement -ccontains "False")
{$Proceed="No"}
else
{$Proceed="Yes"}

#=========================================================================

#capacity check

$VMCluster = "<value_from_orc>"

$VMMServer = "<value_from_orc>"

$numberOfVMS = "<value_from_orc>"

$hostmachinedomain = (gwmi WIN32_ComputerSystem -ComputerName $VMMServer).Domain

$ClusterFQDN = $VMCluster +"."+$hostmachinedomain

$nodes = (get-scvmhostcluster -Name $VMCluster).nodes 

foreach ($node in $nodes)
  {
    #get Memory Information
    $memoryAvailable = (Get-SCVMHost $node.name).AvailableMemory # MB
    $memoryAvailableCluster = $memoryAvailableCluster + $memoryAvailable

    [int]$memoryTotal = ((Get-SCVMHost $node.name).TotalMemory) /1mb #bytes "{0:D3}" -f
    $memoryTotalCluster = $memoryTotalCluster + $memoryTotal

    #get CPU Information
    $CpuCoreCount = (Get-SCVMHost $node.name).CoresPerCpu
    $CpuCoreTotalCluster = $CpuCoreTotalCluster + $CPUCoreCount
    $CpuCoreTotalCluster

    $CpuCount = (Get-SCVMHost -ComputerName $node.name).PhysicalCPUCount
    $CpuTotalClusterCount = $CpuTotalClusterCount + $CpuCount
    $CpuTotalClusterCount

}
#$memoryAvailableCluster = ($memoryAvailableCluster *1024*1024) /1GB
#$memoryTotalCluster = ($memoryTotalCluster *1024*1024) /1GB
$memoryAvailableClusterdisplay = $memoryAvailableCluster *1024 *1024 /1GB
#$memoryAvailableCluster = ($memoryAvailableCluster) /1GB
$memoryTotalClusterdisplay = $memoryTotalCluster *1024 *1024 /1GB
#$memoryTotalCluster = ($memoryTotalCluster) /1GB

  $VMTemplate = Get-SCVMTemplate -Name '<Name>'

  $TemplateMemory =  $vmtemplate.Memory * $numberOfVMS

  $TemplateCPU =  $vmtemplate.CPUCount * $numberOfVMS

  #Memory Calculation

  $memoryAvailbleAfterVm = $memoryAvailableCluster - $TemplateMemory
  $memoryAvailbleAfterVmdisplay = $memoryAvailbleAfterVm *1024 *1024 /1GB
  #$memoryAvailbleAfterVm = $memoryAvailbleAfterVm /1GB
  $memoryAvailbleAfterVm
  $memoryAvailbleAfterVmdisplay
  #$memoryAvailbleAfterVm = $memoryAvailbleAfterVm.tostring() + "GB" 

$Storage = (get-scvmhostcluster $VMCluster).SharedVolumes
$StorageCapacity = ($Storage | Measure-Object -Property Capacity -Sum).sum
$StorageFreeSpace = ($Storage | Measure-Object -Property FreeSpace -Sum).sum
$StorageUsed = $StorageCapacity - $StorageFreeSpace

$VMVHDUsedSpace = $VMTemplate.TotalVHDCapacity *$numberOfVMS
$freeSpaceAfterVMS = $StorageFreeSpace - $VMVHDUsedSpace

#=============================================

So, I have been using bits and pieces of Orchestrator to string these activities together. However the real power comes in now after using all the pieces from other steps to now, the ACTUAL Deployment. For the sake of simplicity, I am attaching a screenshot of the runbook. Please feel free to contact me (details below) should you want any additional information.

Most of the PowerShell within the Runbook is as a result of unique constraints within this environment, and most cannot be shared. However, like I said, should you want specifics, feel free to contact me and will provide what I can.

The runbook is attached as well, please use at your own discretion, PROVIDED AS IS. DeployVMRunbook

 

2014-07-31_14-11-46

(E-Mail me)

BlogEmailIcon

Follow me,

Twitter (Personal & System Centre)

 Twitter (System Centre Focused)

So, Cireson have been investing into System Centre Service Manager (SCSM) very heavily and the end results are WELL worth it.

The Cireson Outlook Console has been out a little while, however it just keeps getting better and better. The Console is super easy to install. The Install instructions are provided by Cireson. There are a few steps to follow as well as the installation of an Outlook Plugin.

Yes, as you may have guessed from the name, this allows you to connect to Service Manager with almost a full experience directly from OUTLOOK, how great is that. It simply sits in a corner and connects automatically or it can be set not to, if you are like me and always traveling and do not always have connection to your SCSM Environment. I have tested with extensively, it works VERY WELL over Mobile Broadband (please note that I am in South Africa, the broadband here is NOT great) with a VPN Connection.

Yes, you read that correctly, it is configured in such a way to be light enough to use or a mobile connection with a VPN connection to your environment. Like I said, well worth the wait.

So, once the installation is complete and the Management Packs have been imported and the Outlook Plugin has been installed, the fun can start.

Ok, so onto configuring the Outlook Client,

Click Settings

2014-06-17_07-04-42

Configure as needed, you will notice that I have configured some of the features, like “When Outlook starts, disable features and don’t connect”, i have done purely because i am NOT domain joined and do not always want the Outlook Console to always try and connect especially when I am NOT connected to my corporate environment in any way, this can be easily set and configured to meet your needs. I also enable the the “Prompt for Credentials when connecting”, if I do not do this, it will try to connect using NON DOMAIN credentials. Cireson have clearly thought of this scenario. :)

 

2014-06-17_07-11-13

So, now we can connect to the Environment.

2014-06-17_07-13-00

Provide the required username, password and domain.

2014-06-17_07-14-00

The connection is usually made quite quickly and you can easily see when the connection has been made as a few more icons will now appear and allow you to start using the real power of the Outlook Connector.

2014-06-17_07-16-44

Very quickly, you can see that you can easily Create, Edit and see you Active Work Items. The connector is very intuitive, and easy to use. Simply click one the buttons above or right click on an e-mail, this allows you to create or update a Work Item (yes, you can do this for Problems, Incidents, Changes and Service Requests). This outlook connector really is a ONE-STOP shop for everything Service Manager related.

Creation is easy, and the subsequent menu are easy to understand

2014-06-17_07-20-49

As is editing an incident,

2014-06-17_07-22-08

With the Edit, it allows to search for the Work Item and then modify the required Work item.

2014-06-17_07-23-42

The Outlook Console has a very familiar look and feel to it, allowing pretty much all the same functionality as the Native SCSM Console. When it comes to tasks and the like, such as resolving, you will notice that there is NO context pane for these tasks. However, this is solved by Cireson, with the use of a “Tasks drop down”, allowing for the simplest tasks do to completed as efficiently as possible.

2014-06-17_07-24-37

Notice the tasks,

2014-06-17_07-27-58

All tasks like re-assignment work in much the same way as the Native SCSM Console, also allowing for searching as you type.

2014-06-17_07-29-19

Once all the required updates and/or tasks have been completed, simply click apply or OK, whichever you normal use.

More Functionality

You can also use email received by you to log calls.

So, here is the scenario, you normally allow people to send email and then the call gets logged, or you get an e-mail directly from a user. This should be a new call or perhaps an update to an existing call, the Cireson Outlook Console handles this with ease. The Cireson Outlook Console allows you to update or log Work Items directly from Outlook.

What is also very nice and handy is that the linking of the Affected user happens automatically, the “From” is used for the “Affected User”, in the same way that the Exchange Connector for SCSM works.

2014-06-17_07-36-44

2014-06-17_07-37-38

2014-06-17_07-38-33

All required Fields completed, OK button is now available.

2014-06-17_07-42-10

Updates to work Items are handled in pretty much the same way, select the e-mail, Right Click -> Service Manager -> Choose to Update or add to Work Item. Search for Work Item and and Click OK.

2014-06-17_07-47-56

2014-06-17_07-51-47

OK, so you clicked “OK” and t disappeared, how do I check?

Very easy, you can use the “Edit” option and search for Incident and you can check it was added as a log.

2014-06-17_07-55-47

2014-06-17_07-56-30

2014-06-17_07-57-18

A lot of though has gone into this product, I ALWAYS recommend this product to my customers, as most of us spend the majority of our time within Outlook as it is, this simply adds the immense power of System Centre Service Manager into Outlook as well, allowing you to further empower your IT Staff.

(E-Mail me)

 

Follow me,

Twitter (Personal & System Centre)

 Twitter (System Centre Focused)

Hi All,

It has been a little while, i have been quite involved with an Integration Project. With this project there was a requirement to add comments to a Work Item. The information is passed on from “System A” to “System B” via XML. Using PowerShell, extracting the XML contents is not too difficult, if anyone would like to dive into that a little bit, please let me know with Comments.

I decided not to re-invent the wheel, so some searching was in order, and I found the following post, this post gave the basics. However every time I tried to add additional comments, the comments were over-written and NOT replaced. Not quite the desired effect. So after some more checking and research and tinkering within the Service Manager, I discovered the following about comments.

When adding a Comment, there is adding of a relationship class, already mentioned in this post, however it also uses a GUID.

2014-04-03_07-51-37

There is also another trick to adding comments within Orchestrator, this is discovered by trying to add a comment and then pulling all the available fields and looking at them. It is a small component which can be easily missed. The “Display Name” must also be the same GUID. So you might be asking how do we get the GUID?

Well, PowerShell can easily handle this for you.

$guid = [System.Guid]::NewGuid().ToString()

You simply use this a pre-cursor step and publish this data from “Run .Net Script”, so a sample would look like this.

2014-04-03_07-58-27

Get-Object Properties

I pass on the ID Value I want to modify from another Runbook

2014-04-03_07-58-58

Create Related Object Properties

I use an “Extended” class of comments needed for this project, principal remains the same.

2014-04-03_08-01-08

I hope this saves  you some time and add some value.

 

(E-Mail me)

 

Follow me,

 

Twitter (Personal & System Centre)

 Twitter (System Centre Focused)

So recently, I had a customer ask me for the following as their previous incident management system had this functionality.

The customer wanted to be able to send an “Update Email” to a 3rd party from the SCSM Console with automatically placing the reference number into said email. They needed the functionality of sending to any email address. This was a requirement for the type of business they are in.

Please remember that I am by no means a developer. I was thinking of using System Centre Orchestrator, however for this simple requirement, I thought that it might be overkill. I am sure that in time, as the requirements grows and/or changes, System Centre Orchestrator will become a better fit. For this solution, I turned to my friend, PowerShell

I simply wanted to provide a clean interface for the customer to use. I follow a strict rule of KISS (Keep It Straight and Simple). With the PowerShell script, I provide two input fields.

  1. Email address of user for update to go to
  2. Update to be sent to customer.

The screenshot of what the window looks like

All of this was built in PowerShell with some from Sapien PrimalForms Community Edition to assist with the GUI part. The GUI is fully functional and tested. “Send Update” is responsible for sending the update to the specified person and the “Cancel” simply closes the form nicely and allows you to continue as normal.

PowerShell Code Below (SendEmail – Technet Gallery Download)


#region Script Settings
#<ScriptSettings xmlns="http://tempuri.org/ScriptSettings.xsd">
#  <ScriptPackager>
#    <process>powershell.exe</process>
#    <arguments />
#    <extractdir>%TEMP%</extractdir>
#    <files />
#    <usedefaulticon>true</usedefaulticon>
#    <showinsystray>false</showinsystray>
#    <altcreds>false</altcreds>
#    <efs>true</efs>
#    <ntfs>true</ntfs>
#    <local>false</local>
#    <abortonfail>true</abortonfail>
#    <product />
#    <version>1.0.0.1</version>
#    <versionstring />
#    <comments />
#    <company />
#    <includeinterpreter>false</includeinterpreter>
#    <forcecomregistration>false</forcecomregistration>
#    <consolemode>false</consolemode>
#    <EnableChangelog>false</EnableChangelog>
#    <AutoBackup>false</AutoBackup>
#    <snapinforce>false</snapinforce>
#    <snapinshowprogress>false</snapinshowprogress>
#    <snapinautoadd>2</snapinautoadd>
#    <snapinpermanentpath />
#    <cpumode>1</cpumode>
#    <hidepsconsole>false</hidepsconsole>
#  </ScriptPackager>
#</ScriptSettings>
#endregion

 param($ID)
Import-Module 'C:\Program Files\Common Files\SMLets\SMLets.psd1' -Force

 #Generated Form Function
function GenerateForm {
########################################################################
# Code Generated By: SAPIEN Technologies PrimalForms (Community Edition) v1.0.10.0
# Generated On: 2013-11-14 09:08 AM
# Generated By: Fletcher
########################################################################

 #region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

 #region Generated Form Objects
$SendUpdateForm = New-Object System.Windows.Forms.Form
$CancelButton = New-Object System.Windows.Forms.Button
$SendUpdateButton = New-Object System.Windows.Forms.Button
$UpdateTextBox = New-Object System.Windows.Forms.TextBox
$UpdateLabel = New-Object System.Windows.Forms.Label
$EmailToTextBox = New-Object System.Windows.Forms.TextBox
$EMailToLabel = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

 #----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$SendUpdateButton_OnClick=
{
        Write-Host "Send Update"
        $to = $EmailToTextBox.Text
        Write-Host $to
        $from = "Servicedesk@bui.co.za"
        $emailbody = $UpdateTextBox.Text
$subject = @"
Update [ID]
"@
$body = @"
$emailbody
"@
        #$subject = "Update [ID]"
        #Write-Host $subject
        #Write-Host $body
        $smtpserver = "buiexc20.bui.co.za"
        #[string]$body = $UpdateTextBox.Text
        #$testcommand = "Send-MailMessage -To $to -From $from -Subject $messagencontent -Body '$body' -SmtpServer $smtpserver"
        Send-MailMessage -To $to -From $from -Subject $subject -Body $body -SmtpServer $smtpserver
        #Write-Host $testcommand
        $SendUpdateForm.Close()

 }

 $CancelButton_OnClick=
{
#TODO: Place custom script here
$SendUpdateForm.Close()
}

 $OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
    $SendUpdateForm.WindowState = $InitialFormWindowState
}

 #----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 323
$System_Drawing_Size.Width = 409
$SendUpdateForm.ClientSize = $System_Drawing_Size
$SendUpdateForm.DataBindings.DefaultDataSourceUpdateMode = 0
$SendUpdateForm.Name = "SendUpdateForm"
$SendUpdateForm.Text = "Send Update"

 
 $CancelButton.DataBindings.DefaultDataSourceUpdateMode = 0

 $System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 182
$System_Drawing_Point.Y = 264
$CancelButton.Location = $System_Drawing_Point
$CancelButton.Name = "CancelButton"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 124
$CancelButton.Size = $System_Drawing_Size
$CancelButton.TabIndex = 5
$CancelButton.Text = "Cancel"
$CancelButton.UseVisualStyleBackColor = $True
$CancelButton.add_Click($CancelButton_OnClick)

 $SendUpdateForm.Controls.Add($CancelButton)

 
 $SendUpdateButton.DataBindings.DefaultDataSourceUpdateMode = 0

 $System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 35
$System_Drawing_Point.Y = 264
$SendUpdateButton.Location = $System_Drawing_Point
$SendUpdateButton.Name = "SendUpdateButton"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 23
$System_Drawing_Size.Width = 116
$SendUpdateButton.Size = $System_Drawing_Size
$SendUpdateButton.TabIndex = 4
$SendUpdateButton.Text = "Send Update"
$SendUpdateButton.UseVisualStyleBackColor = $True
$SendUpdateButton.add_Click($SendUpdateButton_OnClick)

 $SendUpdateForm.Controls.Add($SendUpdateButton)

 $UpdateTextBox.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 35
$System_Drawing_Point.Y = 135
$UpdateTextBox.Location = $System_Drawing_Point
$UpdateTextBox.Multiline = $True
$UpdateTextBox.Name = "UpdateTextBox"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 103
$System_Drawing_Size.Width = 290
$UpdateTextBox.Size = $System_Drawing_Size
$UpdateTextBox.TabIndex = 3

 $SendUpdateForm.Controls.Add($UpdateTextBox)

 $UpdateLabel.DataBindings.DefaultDataSourceUpdateMode = 0

 $System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 35
$System_Drawing_Point.Y = 110
$UpdateLabel.Location = $System_Drawing_Point
$UpdateLabel.Name = "UpdateLabel"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 22
$System_Drawing_Size.Width = 359
$UpdateLabel.Size = $System_Drawing_Size
$UpdateLabel.TabIndex = 2
$UpdateLabel.Text = "Please enter the information to be sent to intended recipient:"

 $SendUpdateForm.Controls.Add($UpdateLabel)

 $EmailToTextBox.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 35
$System_Drawing_Point.Y = 54
$EmailToTextBox.Location = $System_Drawing_Point
$EmailToTextBox.Name = "EmailToTextBox"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 20
$System_Drawing_Size.Width = 290
$EmailToTextBox.Size = $System_Drawing_Size
$EmailToTextBox.TabIndex = 1

 $SendUpdateForm.Controls.Add($EmailToTextBox)

 $EMailToLabel.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 35
$System_Drawing_Point.Y = 27
$EMailToLabel.Location = $System_Drawing_Point
$EMailToLabel.Name = "EMailToLabel"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 24
$System_Drawing_Size.Width = 439
$EMailToLabel.Size = $System_Drawing_Size
$EMailToLabel.TabIndex = 0
$EMailToLabel.Text = "Please enter the email address of the intended recipient:"

 $SendUpdateForm.Controls.Add($EMailToLabel)

 #endregion Generated Form Code

 #Save the initial state of the form
$InitialFormWindowState = $SendUpdateForm.WindowState
#Init the OnLoad event to correct the initial state of the form
$SendUpdateForm.add_Load($OnLoadForm_StateCorrection)
#Show the Form
$SendUpdateForm.ShowDialog()| Out-Null

 } #End Function

 #Call the Function
GenerateForm

[/code]

Ok, so that is the PowerShell side done. Now, it is time to create the console task. This is a fairly straight forward exercise. There are only a few tips I would like to share. I used a shared folder for the scripts and then mapped the console task to the shared folder. Netivia Consulting has a great idea as well, I will be changing to PowerShell Remoting soon, great idea!!!!!

I have configured the PowerShell script to use a parameter, the ID of the Work Item, this is very easy to configure and ensure that the parameter is passed on. See below.

You will see that I used the “Log in action log when this task is run”. That is where the Write-host in the PowerShell script becomes handy, the write-host lines are added to the Action Log.

Please feel free to use and modify to meet your needs.

(E-Mail me)

Follow me.

Facebook (Personal)

Twitter (Personal & System Centre)

Twitter (System Centre Focused)

So, I am quite a keen user of PowerShell and System Centre Orchestrator. Ok, so I recently had a request from a customer that went as follows “I need DPM to alert me when tapes are ready to  be taken off-site.”

DPM does not seen to have this functionality out of the box within the Graphical User Interface (GUI). All is NOT lost, Data Protection Manager has a PowerShell component and i was sure i could figure out a way to get this to work within PowerShell. Sure enough a solution in the form of PowerShell was found, so using this as a base, I modified the PowerShell script to suit my needs. It was also slightly modified to use with System Centre Orchestrator. The custoemr also wanted some colour and wanted the result formatted in HTML. primarily for reading purposes and auditing purposes. PowerShell code below and link here.

Import-Module DataProtectionManager
$date = Get-Date -Format "M-d-yyyy"
$path = "c:\DPMOffisteTapes\"
$filepath = $path + $date + ".html"
#creates the folder if it does not exist
New-Item -itemType file -Path $filepath
$AllLibraries = get-dpmlibrary 
$AllTapes = Get-Tape -DPMLibrary $AllLibraries
$offistereadytape = $AllTapes | Where-Object {$_.isoffsiteready -eq $true}
$a = "<style>"
$a = $a + "BODY{background-color:Green;}"
$a = $a + "TABLE{border-width: 1px;border-style: solid;border-color: black;border-collapse: collapse;}"
$a = $a + "TH{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:GreenYellow}"
$a = $a + "TD{border-width: 1px;padding: 0px;border-style: solid;border-color: black;background-color:palegoldenrod}"
$a = $a + "</style>"
$offistereadytape | Select-object location, barcode , isoffsiteready|ConvertTo-Html -Head $a -Body "<H2>Offsite Ready Tapes</H2>" | out-file -FilePath $filepath

OK, so now we have the data in decent format.

image

So, with the more tapes that are ready, the more rows of data will be within the HTML.

Ok, so now we need to schedule the task. I know i could have used Task Scheduler and the like, however we have System Centre Orchestrator and with Service Management Automation available, more and more tasks will be automated. With this example, i decided to use Orchestrator.

So, I simply use a Monitor/Date Time to run the required activity at set intervals

image

I then run a DPM Script from the Data Protection Manager Integration Pack.

image

image

The filepath Variable is where the html (the full path to the html file) is written, this is especially helpful when sending the Email Message. (I know this can be done with send-mailmessage directly within the PowerShell code)

image

So there you have it, Some Orchestrator Magic with PowerShell and DPM.

(E-Mail me)

Follow me.

Facebook (Personal)

Twitter (Personal & System Centre)

Twitter (System Centre Focused)