Archive for the ‘Powershell’ Category

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


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)
#3 letters - location
$location = $location.Substring(0,3)

#placecholder (-)

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

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

#tiebreaker (XXX)

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

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

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

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

$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
  $computername = $part1 + "{0:D3}" -f $i + $part3
  "testing $computername"
  $test = get-qadcomputer $computername
  if ($test)
  {"Computer Exists"}
  {$computerstartname = $computername}
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

  $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
  $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

      $placementInfo | Add-Member NoteProperty -name Placement -value "True";
      $placementInfo | Add-Member NoteProperty -name Placement -value "False"
  $colPlacementInfo += $placementInfo

If ($colPlacementInfo.placement -ccontains "False")


#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 $ # MB
    $memoryAvailableCluster = $memoryAvailableCluster + $memoryAvailable

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

    #get CPU Information
    $CpuCoreCount = (Get-SCVMHost $
    $CpuCoreTotalCluster = $CpuCoreTotalCluster + $CPUCoreCount

    $CpuCount = (Get-SCVMHost -ComputerName $
    $CpuTotalClusterCount = $CpuTotalClusterCount + $CpuCount

#$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 = $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



(E-Mail me)


Follow me,

Twitter (Personal & System Centre)

 Twitter (System Centre Focused)

So, one of the consultants in the company I work at came to me with a strange request.

The request from the customer he was helping was the following. They wanted a way to connect to all the switches within their environment and then run some commands against the switch after connecting to the switch on port 23. Once the connection has been made, then some commands are run to get the current running configuration. Then export this to a text file.

So I found a basic script here. I have since taken this and modified and extended the script. I have added an array for the IPs to be checked. I have also added some checking prior to running any commands. I have added some testing.

First, we test the connection and see if the device is responding to pings. If the device is responding to pings, then test and see if the device is configured for telnet. So basically I am looking to see if port 23 is open. If port 23 is not opened, a log file is updated with the IP Address. If the device is not responding to pings, a log file is updated stating the IP of the “non-responding” device.

As an addition to the script, the files are then added to an e-mail which is sent to whomever you want to add. As part of the email process, a check is done and if an error is thrown, there is more information presented in the console to point you in the correct direction.

## PowerShell: Script To Telnet To Remote Hosts And Run Commands Against Them With Output To A File ##
## Overview: Useful for Telnet connections to Cisco Switches and other devices. Can add additional command strings
## Usage Examples: Add your environment specific details into the parameters below, or include when calling the script:
## ./PowerShellTelnetRemoteSession.ps1 "" "23" "admin" "password" "term len 0" "en" "enablepassword" "show interface"
    #[string] $remoteHost = "", 
    #[int] $port = 23,
    [string] $username = "admin",
    [string] $password = "",
    #[string] $termlength = "term len 0", #Useful for older consoles that have line display limitations
    [string] $enable = "en", #Useful for appliances like Cisco switches that have an 'enable' command mode
    [string] $enablepassword = "",
    [string] $command1 = "show run", #You can add additional commands below here with additonal strings if you want
    [string] $command2 = " ",
    [string] $command3 = " ",
    [string] $command4 = " ",
    [string] $command5 = " ",
    [int] $commandDelay = 1000
[string] $output = ""
## Read output from a remote host
function GetOutput
  ## Create a buffer to receive the response
  $buffer = New-Object System.Byte[] 4096
  $encoding = New-Object System.Text.AsciiEncoding
  $outputBuffer = ""
  $foundMore = $false
  ## Read all the data available from the stream, writing it to the
  ## output buffer when done.
    ## Allow data to buffer for a bit
    Start-Sleep -m 1000
    ## Read what data is available
    $foundmore = $false
    $stream.ReadTimeout = 1000
        $read = $stream.Read($buffer, 0, 1024)
        if($read -gt 0)
          $foundmore = $true
          $outputBuffer += ($encoding.GetString($buffer, 0, $read))
      } catch { $foundMore = $false; $read = 0 }
    } while($read -gt 0)
  } while($foundmore)
function Main
    param ($ip,$port)
  ## Open the socket, and connect to the computer on the specified port
  Write-Host "Connecting to $ip on port $port"

  $socket = New-Object System.Net.Sockets.TcpClient($ip, $port)
  Write-Host "Connected. Press ^D followed by [ENTER] to exit.`n"
  $stream = $socket.GetStream()
  $writer = New-Object System.IO.StreamWriter $stream
    ## Receive the output that has buffered so far
    $SCRIPT:output += GetOutput
        Start-Sleep -m $commandDelay
        #Start-Sleep -m $commandDelay
        Start-Sleep -m $commandDelay
        Start-Sleep -m $commandDelay
        Start-Sleep -m $commandDelay
                $writer.WriteLine($command1) #Add additional entries below here for additional 'strings' you created above
        Start-Sleep -m $commandDelay
                $writer.WriteLine($command2) #Add additional entries below here for additional 'strings' you created above
                Start-Sleep -m $commandDelay
                $writer.WriteLine($command3) #Add additional entries below here for additional 'strings' you created above
                Start-Sleep -m $commandDelay
                $writer.WriteLine($command4) #Add additional entries below here for additional 'strings' you created above
                Start-Sleep -m $commandDelay
                $writer.WriteLine($command5) #Add additional entries below here for additional 'strings' you created above
        Start-Sleep -m $commandDelay
        $SCRIPT:output += GetOutput
  ## Close the streams

  #building file name
  $filename = "c:\switch\$ip - " + $timestamp + ".txt"
  $output | Out-File $filename  #Change this to suit your environment

#build the list of ips to be interegated 
$ips = "","",""

#building a file path
$timestamp = get-date -Format g | foreach {$_ -replace ":","."}

#building different file paths for different functions
$errortimestamp = Get-Date -Format o | foreach {$_ -replace ":", "."}
$errorfilename = "c:\switch\" + $timestamp + " - ERROR.txt"

#building different file paths for different functions
$blockedtimestamp = Get-Date -Format o | foreach {$_ -replace ":", "."}
$blockedfilename = "c:\switch\" + $timestamp + " - blocked.txt"

#looping through each ip in ip list
foreach ($ip in $ips)
    Write-host "Testing $ip"
    #test to see if device is responding to pings
	if (Test-Connection $ip -Quiet)
        #creating connection on port 23
		$t = New-Object Net.Sockets.TcpClient
		$t.Connect($ip, 23)

        #if it connects, runs the required function with the ip
		if ($t.Connected)
			. Main $ip "23"
        #script block for device responding to ping, but port 23 is NOT open
			$portblocked = "Port 23 on $ip is closed , You may need to contact your IT team to open it. "
            Add-Content $blockedfilename "`n$portblocked"
    #script block for NO RESPONSE
    	$errorfilename = "c:\switch\" + $timestamp + " - ERROR.txt" 
        Add-Content $errorfilename "`nCould not ping $ip" 

#displaying information on console
Write-Host "Build file list" -NoNewline
#getting file list to be emailed
$files = Get-ChildItem C:\Switch\ | Where {-NOT $_.PSIsContainer} | foreach {$_.fullname}
#pausing script
Start-Sleep 3
Write-Host "`t" [File List Built] -ForegroundColor "Green"

Write-Host "Sending Email" -NoNewline

#building checks for sending emails

#no error

#replace as needed
$to = "<to>"
$from = "<from>"
$smtpserver = "<smtpserver>"

    Send-MailMessage -Attachments $files -to $to -from $from -Subject "Network Config backup - $timestamp" -SmtpServer $smtpserver -ErrorAction Stop
    Write-Host "`t [Email Sent]" -ForegroundColor "Green"
    $ErrorMessage = $_.Exception.Message
    if ($ErrorMessage -ne $null)
        Write-Host "`t [Unable to send Mail]" -ForegroundColor "Red"
        Write-Host "There was an error: $ErrorMessage" -ForegroundColor "Yellow"

Start-Sleep 3
Write-Host "Removing Files" -NoNewline
$files | Remove-Item
Write-Host "`t [Files removed]" -ForegroundColor "Green"

(E-Mail me)

Follow me.

Facebook (Personal)

Twitter (Personal & System Centre)

Twitter (System Centre Focused)

Just recently I was looking for a way to notify users about Inactive incidents as I have some departments that tend to ignore their work items and an e-mail about their “untouched” incidents seems to motivate them. So after some searching I found this script from Andreas Baumgarten

Please note : I only modified this script to extend its use to other Statuses to be monitored. All credit for the script goes entirely to Andreas Baumgarten

Code is below

# Configure Last Modified Days Before
$ModifiedBefore = 3

#Configure Incident Status
$IncidentStatus = 'Active'

# Configure your mail server, the recipient and the sender of the mail
# $smtphost=”mailserver.yourdomain.local”
# $from=”mail@yourdomain.local”


# Send-Mail function
function Send-Mail
$smtp = new-object$smtphost)
$mail = new-object System.Net.Mail.MailMessage
$mail.from= $From
$mail.subject= $Subject
$mail.body= $Body

# Some other variables
$BeforeDate = (Get-Date).AddDays(-$ModifiedBefore).ToString("MM/dd/yyy HH:mm:ss")
$Status = Get-SCSMEnumeration IncidentStatusEnum.$IncidentStatus$
$AssignedUserObjectRelClass = Get-SCSMRelationshipClass System.WorkItemAssignedToUser
$IncidentClass = Get-SCSMClass -name System.WorkItem.Incident$

#Get all incidents last modfied xy days before
$Incidents= @(Get-SCSMObject -Class $IncidentClass | Where {($_.Status -eq $Status -AND $_.LastModified -lt $BeforeDate)})

If ($Incidents.count -gt 0)

#Get all assigned incidents from list
foreach ($Incident in $Incidents)
# Get AssignedToUser
$AssignedUser = Get-SCSMRelatedObject -SMObject $Incident -Relationship $AssignedUserObjectRelClass

# Incidents AssignedTo is not NULL
If ($AssignedUser.Displayname -ne $NULL)
#Get email adress of AssignedToUser
$EndPoint = Get-SCSMRelatedObject -SMObject $assignedUser -Relationship $UserPref|?{$_.ChannelName -like '*SMTP'}
$Sendto = $Endpoint.Targetaddress

#Create Output
$Output = 'This Incident has been inactive for ' + $ModifiedBefore + ' day(s): <br>' + $Incident.ID + ' - ' + $Incident.Title + ' - Last Modified: ' + $Incident.Lastmodified
#Send email
$To = $Sendto
$Subject = 'Inactive incident for ' + $ModifiedBefore + ' day(s): ' + $Incident.Id + ' ' + $Incident.Title
$Body = $Output
Send-Mail $From $to $Subject $Body

Remove-Module SMlets -force 

Okay, so now that the code is there, I had to make some modifications in order for the Code to work with “NON-DEFAULT” Incident Statuses. I have created some additional Pending statuses.

The key line in this code is

Configure Incident Status
$IncidentStatus = 'Active'


$Status = Get-SCSMEnumeration IncidentStatusEnum.$IncidentStatus$

This allows you specify the Status. However if you use additional “NON-DEFAULT” statuses, this would need to be modified to suit your needs. You would need to modify the line of code to read as follows.

$IncidentStatus = 'Enum.847741a452db4d529741005ea73aead8'


$Status = Get-SCSMEnumeration $IncidentStatus$

You will notice the change of $IncidentStatus to a “ENUM” Value as this is a “NON-DEFAULT” value, you need to use the ENUM value. This can be gotten by using the following with SMLets

Get-SCSMEnumeration | Format-list | out-file

Below, is a screenshot to help illustrate this further.


Once you have a list of all your Enumerations, then search for the required value, for example “Pending – Waiting for 3rd Party”, you will then see a “Name” value and that whole string is your ENUM value.

You will also see that the $Status line has been changed to cater for the ENUM value.

Modify to meet your needs and create a workflow if you want to.

Follow me.




I have recently started keeping a track of all my PowerShell.

Just a nice simple update.

So, I decided to create a “simple” PowerShell script that would keep a track of all my transcripts. The script would create a file name based on date and place the transcript file in a folder of your choice, this is hard-coded in the script and can be easily modified.

Hope you like it and find it useful.

$date =Get-Date
$filepath = "C:\PSTranscripts"
$hour = ($date.Hour).tostring()
$minute = $date.Minute
$file = $hour + "H" + $minute + "M" +  ".txt"
$newpath = $filepath + "\" + $date.Day + "-" + $date.Month +"-" + $date.year
$fullpath = $filepath + "\" + $date.Day + "-" + $date.Month +"-" + $date.year +"\" + $file
New-Item -ItemType Directory -Path $newpath -ErrorAction SilentlyContinue
Start-Transcript -Path $fullpath

I had this as part of my admin PowerShell Profile, more info on the PowerShell Profile here

I am using the script above as .ps1 script for my day to day account.

Follow me

facebook-small32225222 twitter-small32225222



I believe that the best way to improve your skill is to test and push yourself. I am currently on a mission to get a lot more comfortable with PowerShell ( as it lives up to its name, it is very POWERful).

I need to check a few domains up and running and like to keep an eye on my Domain Controllers as they are obviously the base of Active Directory. So, I decided that i needed to brush on my PowerShell skills, the easiest way to do this is to use it. Hence, I created a PowerShell script to do this for me. It has been uploaded to the Microsoft TechNet Gallery.

The real key is that all the information is built automatically by PowerShell and no modification to the script should be required.

Code below, I would recommend you download it though


Snap 2012-01-24 at 13.00.13

Snap 2012-01-24 at 13.00.39

Hope this helps,

Follow me

facebook-small3222522 twitter-small3222522