Social

onsdag den 28. januar 2015

Personal Update

This blog just broke the 10.000 pageviews, I just broke 1.000 points on Technet, and I am starting a new job at Lumagate as Senior System Center Consultant!

So thing are going pretty well in my professional career. I will be taking a bunch of certifications over the next few months (being autodidact doesn't count for much in this regard), and therefore I doubt there will be much time for blogging and helping the poor unfortunate souls on Technet.

Also summer is coming.... And I am quite the garden enthusiast, and looking forward to spending lots of time out in the sun, tending my precious plants :D Yes, I have way too many hobbies, and just can't find time for it all.

Anyways, thanks for reading.

onsdag den 21. januar 2015

Submitting a SCSM Request Offering Programmatically

As part of the employee onboarding process there is a request offering on the portal that HR fills out and submits. But recent automation has made a file available with the same information as was entered into the portal. Next step is reading the file and submitting the same request offering programatically (and 100% autonomous).

Using the script I just wrote one can do:

Import-Csv -Path \newemployees.txt -Delimiter ';' | 
    % {\Submit-SCSMRequestOffering.ps1  -RequestOffering $RequestOffering `
                                        -MyInput @($_.firstname, $_.surname, $_.salary)}

Imports a csv-file and submits as many request offerings as there are lines (excluding headers) in the file. One could also just submit a single request offering:


\Submit-SCSMRequestOffering.ps1  -RequestOffering $RequestOffering -MyInput @(1,2,3)

The input corresponds to the questions given in the request offering, and the answer mapping is retained. This is especially useful in flows with many activities where the input to the request offering must be available. Coupled with another script i wrote (Including extension properties in the description field) the activities become a breeze to complete, everything you need right there in the description in a nice prose.

Download the script from Technet Gallery. Remember to rate!

tirsdag den 20. januar 2015

Service Manager Management Pack Backup Script

Are you doing Management Pack backups? Well, you should. Schedule the script to run daily (during off-hours).

I have had this lying around for a while now, and thought I would share. Script as follows (Download here - please rate):


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
###############################################################
# Backup service manager management packs
#
# Authored by:
# Anders Spælling, [email protected]
#
###############################################################

# EVENT IDs
# 800 - Warning     - Backup completed with errors
# 700 - Error       - Unable to import module
# 701 - Error       - Failed to backup unsealed MPs
# 702 - Error       - Failed to backup sealed MPs
# 703 - Error       - Failed to create new backup folder
# 600 - Information - Succesfully backed up unsealed MPs
# 601 - Information - Succesfully backed up sealed MPs
# 602 - Information - Removed old backup (unsealed MPs)
# 603 - Information - Removed old backup (sealed MPs)
# 604 - Information - Backup done
# 605 - Information - Starting MP backup job

# CONSTANTS
# Write to event log on this computer
$EventLogComputerName = ''
$EventLogName = "SCSM backup task"
$Date = Get-Date 

# user defined #
# definde rootpath to save managemen packs. Should be UNC format
$RootPath = '\SCSM_MP\'
# Define service manager management server
$SMMS = $EventLogComputerName

# keep MP backups for this many days
$BACKUP_RETAIN_IN_DAYS = 28

# increase if failed to backup MPs
$ErrorCount = 0

# used to write to event log
# Example use, create event with event ID 702 and type Error: CreateEventLog "Error description" 702 "Error"
Function CreateEventLog
{
    Param($EventDescription,$EventID,$Type)
    $EventlogExists = Get-EventLog -ComputerName $EventLogComputerName -List | Where-Object {$_.LogDisplayName -eq $EventLogName}
    If(-not $EventlogExists) 
    {
        New-EventLog -LogName $EventLogName -Source AlertUpdate -ComputerName $EventLogComputerName 
    }
    Write-EventLog -ComputerName $EventLogComputerName -LogName $EventLogName -Source AlertUpdate -Message "$EventDescription" -EventId $EventID -EntryType $Type
}

# remove SMLets module (from session) if loaded  - needed to load the System.Center.Service.Manager module as command names overlap
if(Get-Module -Name SMLets)
{
    Remove-Module 'SMLets' 
}

# find module in '%SMinstalldir%\Powershell\System.Center.Service.Manager.psd1'
$SMInstallDir = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\System Center\2010\Service Manager\Setup').InstallDirectory
$ModuleDir = $SMInstallDir + 'Powershell\System.Center.Service.Manager.psd1'

Import-Module $ModuleDir

if(-not (Get-Module -Name System.Center.Service.Manager))
{
    CreateEventLog "Unable to import module System.Center.Service.Manager`nException message: $($_.Exception.Message)" 700 "Error"
    Exit
}

#######################
# BACKUP UNSEALED MPS #
#######################

CreateEventLog "Starting MP backup job" 605 "Information"

# Define path to save todays backup to
$Path = $RootPath + $Date.ToString('yyyy-MM-dd')

# create path if it does not exists
If (-not (Test-Path $Path -ErrorAction Stop)) 
{
    try
    {
        $CreateOutput = New-Item -ItemType Directory $Path
    }
    catch [System.Exception]
    {
        CreateEventLog "Unable to create new backup folder $Path`nException message: $($_.Exception.Message)" 703 "Error"
        $ErrorCount++
    }
}

try
{
    # get unsealed MPs and export to disk
    Get-SCManagementPack -ComputerName $SMMS | where{$_.sealed -eq $False} | Export-SCManagementPack -Path $Path
    CreateEventLog "Succesfully backed up unsealed MPs" 600 "Information"
}
catch [System.Exception]
{
    CreateEventLog "Failed to backup unsealed MPs`nException message: $($_.Exception.Message)" 701 "Error"
    $ErrorCount++
}
finally
{
    #
}

#####################
# BACKUP SEALED MPS #
#####################

# Define path to save todays backup to
$Path = $RootPath  +  $Date.ToString('yyyy-MM-dd') + "\sealed"

# create path if it does not exists
If (-not (Test-Path $Path)) 
{
    $CreateOutput = New-Item -ItemType Directory $Path
}
try
{
    # get sealed MPs and export to disk
    Get-SCManagementPack -ComputerName $SMMS | where{$_.sealed -eq $True -and $_.Name -like "XX*"} | Export-SCManagementPack -Path $Path
    CreateEventLog "Succesfully backed up sealed MPs" 601 "Information"
}
catch [System.Exception]
{
    CreateEventLog "Failed to backup sealed MPs`nException message: $($_.Exception.Message)" 702 "Error"   
    $ErrorCount++
}
finally
{
   #
}

###########
# CLEANUP #
###########

# remove backup folder from $BACKUP_RETAIN_IN_DAYS days ago
$DeleteFolder = $Date.AddDays(-$BACKUP_RETAIN_IN_DAYS)
$DeletePath = $RootPath + $DeleteFolder.ToString('yyyy-MM-dd')

# remove folder if it exists
If (Test-Path $DeletePath)
{
    $RemoveOutput = Remove-Item $DeletePath -Recurse
    CreateEventLog "Removed old backup of MPs in `"$DeletePath`"" 602 "Information"
}

# remove module (from session)
if(Get-Module -Name System.Center.Service.Manager)
{
    Remove-Module 'System.Center.Service.Manager' 
}

if($ErrorCount -gt 0)
{
    CreateEventLog "Backup completed with $ErrorCount errors" 800 "Warning"     
}
else
{
    CreateEventLog "Backup done" 604 "Information"
}

tirsdag den 13. januar 2015

Scripting Service Manager Documentation - Views and Request Offerings

No one likes writing documentation. Even less so updating existing documentation. But it is nice to have when you need it. Also don't just write documentation for the sake of documentation. Write it down if you need it later and is not inherently obvious from the code (or whatever). But good documentation practice is a can of worms I am not going to open here.

In the following I will present a script that helps with something as tedious as documenting views in Service Manager. Are you going to do that manually?


Also views change, and you would then have to update your documentation. You really need this script!


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# Author: Anders Spælling, [email protected]
#
# This script can assist in documenting Service Manager views. Extracts SCSM view information to csv and html
# View description should include what the view is supposed to show (that is not obvious from the view title)
#
# Requirements: SMLets installed

# enter your service manager management server below
$SCSM_MANAGEMENT_SERVER =  "SM1"

# start of script

# remove this module if loaded
$SMModule = Get-Module -Name System.Center.Service.Manager
if($SMModule)
{
    Remove-Module $SMModule
}

Import-Module 'SMLets'
if(-not (Get-Module -Name SMLets))
{
    Write-Host "Unable to import module SMLets"
    Exit
}

# try and get it from global variable - SMLets will look for this if ComputerName is not supplied
$ComputerName = $Global:smdefaultcomputer
if(-not $ComputerName)
{
    $ComputerName = $SCSM_MANAGEMENT_SERVER
}

#get views and folders
$Views = Get-SCSMView -ComputerName $ComputerName
$Folders = Get-SCSMFolder -ComputerName $ComputerName

# target only subclasses of this class
$BaseClass = Get-SCSMClass -ComputerName $ComputerName -Name System.WorkItem$

# store output in list
$Out = @()
# progress counter
$i = 1;
# iterate over all views
foreach($View in $Views)
{

    Write-Progress -Activity "Processing views..." -Status "Processing ($i of $($Views.Count)): `"$($View.DisplayName)`"" -PercentComplete (100*$i/($Views.Count))

    if($View.DisplayName -eq $null -or $View.DisplayName.Length -eq 0)
    {
        # not sure what these are...
        # Write-Host $View.Name, has no displayname
        continue;
    }

    $ManagementPack = $View.GetManagementPack()
    $TargetClass = Get-SCSMClass -ComputerName $ComputerName -Id ($View.Target.Id)
    
    # we only want targetclasses that inherits specific baseclass
    if($TargetClass.IsSubClassOf($BaseClass))
    {
        $ParentFolders = $Folders | ? {$_.Id -in ($View.ParentFolderIds| select -ExpandProperty Guid)} | select -ExpandProperty DisplayName
        # if based on a combination class we want to know which
        # first convert to xml so that we can easily traverse the xml-string
        [xml]$Configuration = [xml]("<xmlroot>$($View.Configuration)</xmlroot>")
        # traverse...
        $Value = $Configuration.xmlroot.Data.ItemsSource.AdvancedListSupportClass.'AdvancedListSupportClass.Parameters'.QueryParameter.Value
        $TypeProjectionName = $Value.Replace('$MPElement[Name=','').Replace(']$','').Replace("'","")
        # if defined in another MP we must remove the alias
        if($TypeProjectionName.Contains('!'))
        {
            $TypeProjectionName = $TypeProjectionName.Split('!')[1]
        }

        # we now have the Id of the type projection
        $TypeProjection = Get-SCSMTypeProjection -ComputerName $ComputerName -Name $TypeProjectionName

        # if based on a basic class
        $TypeProjectionDisplayName = 'N/A'

        if($TypeProjection)
        {

            # typeprojections can share the same name. If more than one is found we use the one with a displayname
            if(([array]$TypeProjection | ? {$_.DisplayName}).Count -gt 0)
            { # select first one with a displayname
                $TypeProjection = [array]$TypeProjection | ? {$_.DisplayName} | select -First 1
            }
            else 
            { # no displaynames, select first 1
                $TypeProjection = [array]$TypeProjection | select -First 1
            }

            $TypeProjectionDisplayName = $TypeProjection.DisplayName

            # if there was no displayname we use the name
            if(-not $TypeProjectionDisplayName)
            {
                $TypeProjectionDisplayName = $TypeProjection.Name
            }
        }

        $Out += New-Object PSObject -Property @{
            Title = $View.DisplayName;
            Description = $View.Description;
            TargetClass = $TargetClass.DisplayName;
            TypeProjection = $TypeProjectionDisplayName;
            ManagementPack = $ManagementPack.DisplayName;
            ParentFolder = $ParentFolders;
            VisibleInUI = $View.Visible;
        };
    }
    
    # update progress counter - used in Write-Progress
    $i++
}

# adding some style to the table
$head = @'
<style>
TABLE{border-width: 1px; border-style: solid; border-color: black;}
TH{border-width: 1px; border-style: solid; border-color: black; padding: 1px;}
TD{border-width: 1px; border-style: solid; border-color: black; padding: 1px;}
</style>
'@
# adding a title
$body = '<H2>Request Offerings</H2>'

# sort using this order
$SortOrder = 'ParentFolder', 'Title'
# select the order of properties (to output)
$Properties = 'Title', 'Description', 'TargetClass', 'TypeProjection', 'ManagementPack', 'ParentFolder', 'VisibleInUI'
# convert to html and csv
$Out | Sort-Object $SortOrder | Select-Object -Property $Properties | ConvertTo-Html -Head $head -Body $body > C:\temp\viewdoc.html
$Out | Sort-Object $SortOrder | Select-Object -Property $Properties | Export-Csv -Path C:\temp\viewdoc.csv -NoTypeInformation

You can download the code from Technet gallery. It also includes code on how to do the same with Request Offerings.

I also found this: http://www.buchatech.com/2015/03/service-manager-discovery-report/ - check it out.

tirsdag den 6. januar 2015

Automated Lab

I just joined Automated Lab (AL) on Codeplex and wanted to give a shoutout to this great open source project.

I am joining to write the part of Service Manager, and I almost have something working, so hopefully I can share that soon.

They are looking for awesome scripting dudes, or as they wrote it: We are looking for people with PowerShell and optionally C# skills for development and code optimizations.

Join up if you want to contribute. I am in no way awesome at powershell or C# for that matter, but you really do not need to be a PS-wiz to write something up that can deploy a favorite SC product of yours. I got by with a lot of copy-pasta and researching how to do a silent install of Service Manager.
Would be cool to have something deploy a Sharepoint server to build the SM portal on...

If I get the time I may write up something on how to approach this as a newbie, because I did have alot of trial and error before getting a hang of how to get things rolling.

Scripting Guy did a series on how to use Automated Lab which I strongly suggest reading before trying it out yourself (part 4 and 5 not that exciting, so optionally skip those).
Even though AL cannot yet install what you need it can still get a few servers up and running faster than you can say Jack Robinson, and then install what you need manually (or use PowerShell and do it silently, awesome...).

Søg i denne blog