The MDT Toolkit is great!

One very useful feature is the “Execute Runbook” Step, which can execute a runbook in Orchestrator.

Unfortunately Orchestrator has a little quirk, when moving to new environment, such as moving from Test to Prod.

All runbooks get a new GUID, and runbook parameters might get a new GUID.  Besides this, the Server names usually needs to be changed too!

This can be a trivial task, which an automation guy like me hate to do! Everytime Server name is updated, all parameters has to be setup again.
This also makes the task prone to errors!

So lets automate it! Below is a script that you can use at your own risk!

Remember to update the configuration in the top of the script.

It does the following:

  1. Open Task sequence using WMI
  2. Read each runbook steps
  3. Replace Server URL
  4. Replace Runbook ID and Parameter IDs by connecting to new web service to pickup new values.
  5. Save TS back into ConfigMgr.

Please make a copy of your TS to make sure you have the original if something fails!

 

# //***************************************************************************
# // Solution:  Configuration Manager MDT
# // Author:	Jakob Gottlieb Svendsen , CTGlobal. http://www.ctglobalservices.com
# // Purpose:   Update runbook steps in TS to use new GUIDs when moving TS
# // Note: This script is setup to use integrated security, run it as an account that has access to SCCM and SCO.
# // If you need to use a seperate credential for accessing SCO, change the config in line 17-27
# //***************************************************************************

$SiteServer = "localhost"
$SiteCode = "HQ1"
$TSPackageId = "HQ100047"
 
$NewServerURL = "http://or01.cloud.local:81"

# uncomment this to use specific cred for new server
<#$Cred = Get-Credential $PSDefaultParameterValues = @{ "Invoke-WebRequest:Credential" = $Cred "Invoke-WebRequest:UseDefaultCredentials" = $false }#>

#Use current user
$PSDefaultParameterValues = @{
    "Invoke-WebRequest:UseDefaultCredentials" = $true
}#>
Function Get-SCORunbook($SCOURL, $RunbookName) {
    $responseContent = [XML] (Invoke-WebRequest -Uri "$SCOURL/Orchestrator2012/Orchestrator.svc/Runbooks?`$filter=Name eq '$RunbookName'" ).Content #-UseDefaultCredentials

    if ($responseContent.feed.entry -eq $null) {
        throw "runbook not found on name $RunbookName"
    }
    if ($responseContent.feed.entry.count -gt 1) {
        throw "more than one runbook found on name $RunbookName"
    }

    $RunbookGUID = $responseContent.feed.entry.content.properties.Id.'#text'
    
    #Get parameters
    $parametersInput = @()
    $parametersOutput = @()
    $responseContent = [XML] (Invoke-WebRequest -Uri "$SCOURL/Orchestrator2012/Orchestrator.svc/Runbooks(guid'$RunbookGUID')/Parameters").Content # -UseDefaultCredentials
    foreach ($parameter in $responseContent.feed.entry.content.properties) {
        if ($parameter.Direction -eq "Out") {
            $parametersOutput += [pscustomobject]@{
                Name = $parameter.Name    
                Id   = $parameter.Id.'#text'
            }
        }
        else {
            $parametersInput += [pscustomobject]@{
                Name = $parameter.Name    
                Id   = $parameter.Id.'#text'
            }
        }
    }
        
    return [pscustomobject]@{
        Name    = $RunbookName
        Id      = $RunbookGUID
        Inputs  = $parametersInput
        Outputs = $parametersOutput
    }
}


# Get SMS_TaskSequencePackage WMI object
$TaskSequencePackage = Get-WmiObject -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_TaskSequencePackage -ComputerName $SiteServer -Filter "PackageID like '$TSPackageId'"
$TaskSequencePackage.Get()
 
# Get SMS_TaskSequence WMI object from TaskSequencePackage
$TaskSequence = Invoke-WmiMethod -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_TaskSequencePackage -ComputerName $SiteServer -Name "GetSequence" -ArgumentList $TaskSequencePackage
 
# Convert WMI object to XML
$TaskSequenceResult = Invoke-WmiMethod -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_TaskSequence -ComputerName $SiteServer -Name "SaveToXml" -ArgumentList $TaskSequence.TaskSequence
$TaskSequenceXML = $TaskSequenceResult.ReturnValue
 
#Update SCO Data

    $SequenceXML = [XML]$TaskSequenceXML
    $RunbookSteps = $SequenceXML.sequence.SelectNodes("//step[@type='BDD_ExecuteRunbook']")
    $PRocessedRunbooks = @()


    foreach ($RunbookStep in $RunbookSteps) {
        #Set New Server URL
        $TaskSequenceXML = $TaskSequenceXML -replace $OldSCOURL, $NewServerURL
        
        #get runbook name
        $RunbookName = ($RunbookStep.defaultVarList.variable | ? Name -eq "RunbookName").'#text'
        $OldSCOUrl = ($RunbookStep.defaultVarList.variable | ? Name -eq "OrchestratorServer").'#text'
        
        if ($RunbookName -in $PRocessedRunbooks) {
            "$RunbookName has already been processed. Skipping"
            Continue
        }

        
        #Replace URL
        "Replace URL: $OldSCOUrl to $NewServerURL"
        $TaskSequenceXML = $TaskSequenceXML -replace $OldSCOUrl, $NewServerURL

        $PRocessedRunbooks += $RunbookName
        #Get New Runbook Info
        $RunbookInfoNew = . Get-SCORunbook -SCOURL $NewServerURL -RunbookName $RunbookName
        $RunbookID = ($RunbookStep.defaultVarList.variable | ? Name -eq "RunbookID").'#text'
    
        if ($RunbookID -ne $RunbookInfoNew.Id) {
            "$RunbookName has new Runbook ID: $($RunbookInfoNew.Id)"
            $TaskSequenceXML = $TaskSequenceXML -replace $RunbookID, $RunbookInfoNew.Id
        }

        #Get new Parameter IDs
        $ParameterCount = ($RunbookStep.defaultVarList.variable | ? Name -eq "RunbookParameters").'#text'
        for ($i = 0; $i -lt $ParameterCount; $i++) {
            $ParameterName = ($RunbookStep.defaultVarList.variable | ? Name -eq "RunbookParameters$($i)ParameterName").'#text'
            $ParameterID = ($RunbookStep.defaultVarList.variable | ? Name -eq "RunbookParameters$($i)ParameterID").'#text'

            $ParameterIDNew = $RunbookInfoNew.Inputs | ? Name -eq $ParameterName | Select -expand Id
            if ($ParameterID -ne $ParameterIDNew) {
                "$RunbookName - Parameter: $ParameterName has new ID: $ParameterIDNew"
                $TaskSequenceXML = $TaskSequenceXML -replace $ParameterID, $ParameterIDNew
            }
        }
    }  #Foreach runbook step

# Convert XML back to SMS_TaskSequencePackage WMI object
$TaskSequenceResult = Invoke-WmiMethod -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_TaskSequencePackage -ComputerName $SiteServer -Name "ImportSequence" -ArgumentList $TaskSequenceXML

# Update SMS_TaskSequencePackage WMI object
Invoke-WmiMethod -Namespace "rootSMSsite_$($SiteCode)" -Class SMS_TaskSequencePackage -ComputerName $SiteServer -Name "SetSequence" -ArgumentList @($TaskSequenceResult.TaskSequence, $TaskSequencePackage) -verbose

Merry xmas!

Previous articleThe Big Bang and how it changed my life as an IT Pro
Next articleIP address hostnames in SPN extending Kerberos usage
Jakob is a Microsoft System Center Cloud and Data center Management MVP. Working as Senior Consultant, trainer and Chief Developer at Coretech A/S, where he is one of the driving forces in keeping Coretech a System Center Gold Partner and member of the System Center Alliance. Since he started at Coretech in 2007, he has focused on Scripting and Development, primarily developing tools, extensions and scripts for the System Center Suite. His main product focus is System Center Orchestrator, the former Opalis, a product he has been invited to speak about at different summits and user group meetings, becoming a renowned voice in his field. He is passionately devoted to the community, for which he contributes to, by being a moderator at TechNet, member of the TechNet Influencers team and sharing his knowledge through hid blog.