Social

tirsdag den 22. juli 2014

Restarting a workflow - Scripted

In my previous post I showed a way to restart a stuck Service Request workflow. Now, detecting SRs that are stuck can be quite tedious using the console. I wrote a script that can detect a possibly stuck workflow. It is actually rather simple, looping all relevant SRs and testing if there is no active activity and one or more pending activities.

Import-Module SMLets

# Activity statuses
$ContainsActivity = Get-SCSMRelationshipClass System.WorkItemContainsActivity
$InProgressStatus = Get-SCSMEnumeration ActivityStatusEnum.Active
$PendingStatus = Get-SCSMEnumeration ActivityStatusEnum.Ready
# SR in progress statuses
$SRStatusInProgressId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress$).Id
$SRStatusInProgressPendingId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress.PendingUserResponse).Id
$SRStatusInProgressUpdatedId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress.UpdatedByUser).Id

$Now = Get-Date
$Then = $Now.AddHours(-2)
# Get SRs with active status that has not been modified since X hours ago
$sCriteria = "(Status = '$SRStatusInProgressId' or Status = '$SRStatusInProgressPendingId' or Status = '$SRStatusInProgressUpdatedId') and LastModified < '$Then'"
$SRClass = Get-SCSMClass system.workitem.servicerequest$

$Criteria = New-Object "Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria" $sCriteria, $SRClass
# Get all SRs matching the critera
$SRs = Get-SCSMObject -Criteria $Criteria

foreach($SR in $SRs)
{
    $HasActivityInProgress = $false
    $HasPendingActivity = $false
    foreach($Activity in Get-SCSMRelatedObject -SMObject $SR -Relationship $ContainsActivity)
    {
        if($Activity.Status -eq $InProgressStatus)
        {
            $HasActivityInProgress = $true            
        }

        elseif($Activity.Status -eq $PendingStatus)
        {
            $HasPendingActivity = $true
        }
    }

    # If true then the SR is possibly stuck with a pending activity
    if(-not $HasActivityInProgress -and $HasPendingActivity)
    {
        Write-Host $($SR.DisplayName)
    }
}

Next up is trying to get the workflow started again. One approach is to put the SR on hold, wait abit (10-20 seconds), activate the SR, and optionally restore the original SR status (typically some custom status like "pending user response").

Import-Module SMLets

$SRID = 'SRxxxx';
$SR = Get-SCSMObject -Class (Get-SCSMClass system.workitem.servicerequest$) -Filter "DisplayName -like '$SRID*'"
$PrevStatus = $SR.Status
$StatusInProgress = Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress$

# set on hold
$SR | Set-SCSMObject -PropertyHashtable @{Status = (Get-SCSMEnumeration ServiceRequestStatusEnum.OnHold)}

# wait for activites to go on hold
Start-Sleep -s 20

# resume SR
$SR | Set-SCSMObject -PropertyHashtable @{Status = $StatusInProgress}

if($PrevStatus -ne $StatusInProgress)
{
    # wait for activites to "reset"
    Start-Sleep -s 20
    #restore previous status
    Write-Host "Setting status to: $($PrevStatus.DisplayName)"
    $SR | Set-SCSMObject -PropertyHashtable @{Status = $PrevStatus}
}

Leave in a comment below how many stuck workflows you found ;)

3 kommentarer:

  1. Thanks for the script. I got the same problem. Our SR stuck intermittently after RB activities. We have put them on hold and resume to workaround the problem.

    I have to change your script a bit to make it work on our environment (SCSM 2012 R2)

    From:
    $sCriteria = "(Status = '$SRStatusInProgressId' or Status = '$SRStatusInProgressPendingId' or Status = '$SRStatusInProgressUpdatedId') and LastModified < '$Then'"
    $SRClass = Get-SCSMClass system.workitem.servicerequest$

    $Criteria = New-Object "Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria" $sCriteria, $SRClass

    To:

    $sCriteria = "(Status = '$SRStatusInProgressId') and LastModified < '$Then'"
    $SRClass = Get-SCSMClass -Name system.workitem.servicerequest
    $Criteria = New-Object -TypeName "Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria" -ArgumentList $sCriteria,$SRClass

    SvarSlet
    Svar
    1. Cheers. Feel free to change the script however you like to suit your needs. I left in the option of having custom statuses in the original script as it is easier to remove than to add.

      Slet
  2. Hi Team,
    I Have followed the above script and it works perfect,
    but in some cases, I am getting SR names in which Activities are not completed .

    *I want only the SR Names which are in Progress having all Activities completed.

    Here is the script:


    import-module smlets

    $ContainsActivity = Get-SCSMRelationshipClass System.WorkItemContainsActivity
    $InProgressStatus = Get-SCSMEnumeration ActivityStatusEnum.Active
    $PendingStatus = Get-SCSMEnumeration ActivityStatusEnum.Ready
    # SR in progress statuses
    $SRStatusInProgressId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress$).Id
    $SRStatusInProgressPendingId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress.PendingUserResponse).Id
    $SRStatusInProgressUpdatedId = (Get-SCSMEnumeration ServiceRequestStatusEnum.InProgress.UpdatedByUser).Id

    # Get SRs with active status that has not been modified since X hours ago
    $sCriteria = "(Status = '$SRStatusInProgressId')"
    $SRClass = Get-SCSMClass system.workitem.servicerequest$

    $Criteria = New-Object -TypeName "Microsoft.EnterpriseManagement.Common.EnterpriseManagementObjectCriteria" -ArgumentList $sCriteria,$SRClass
    # Get all SRs matching the critera
    $SRs = Get-SCSMObject -Criteria $Criteria

    foreach($SR in $SRs)
    {
    $HasActivityInProgress = $false
    $HasPendingActivity = $false
    foreach($Activity in Get-SCSMRelatedObject -SMObject $SR -Relationship $ContainsActivity)
    {
    if($Activity.Status -eq $InProgressStatus)
    {
    $HasActivityInProgress = $true
    }

    elseif($Activity.Status -eq $PendingStatus)
    {
    $HasPendingActivity = $true
    }
    }

    # If true then the SR is possibly stuck with a pending activity
    if(-not $HasActivityInProgress -and $HasPendingActivity)
    {
    Write-Host $($SR.DisplayName)
    }
    }

    SvarSlet

Søg i denne blog