Locking the work item

john_doylejohn_doyle Cireson Support Ninja IT Monkey ✭✭✭✭
This is my attempt to prevent analysts from losing work because more than one of them has accessed the same work item. It won't stop work items being updated by e-mail or by work flows. It also will not stop someone from updating a work item through the SCSM Console.

What it does:

  • User opens workitem
  • Checks if there is an object with the same ID in the work item lock class
  • If there is none, a new entry is created for this workitem. The lock is then updated every 30 seconds.
  • If a lock is found, the code checks if the lock belongs to this user, or if it is older than 35 seconds. In this case the lock is updated with the current time and the details of the user. The lock is then updated every 30 seconds.
  • If the lock is found but the lock is held by a different user and was last updated less than 35 seconds ago, the user is alerted that the work item is being edited by the user holding the lock and the Save and Apply buttons are disabled.

Installation:

  1. Unzip the attached file.
  2. Import the Management Pack into the SCSM Console
  3. Run the PowerShell script to give End Users create/edit rights to the Work Item Lock class
  4. Add the JavaScript code in the custom.js file to the same file in C:\intepub\CiresonPortal\CustomSpace folder.


N.B. This has not been tested in a production environment. Please test it thoroughly before implementing it. I am sure it needs more error checking code before it is ready for use.

Comments

  • john_doylejohn_doyle Cireson Support Ninja IT Monkey ✭✭✭✭
    Oops, I meant to credit Marcel Zehner for the PowerShell script. It is not mine I got it from his blog.

  • john_doylejohn_doyle Cireson Support Ninja IT Monkey ✭✭✭✭
    Has anyone implemented this in their Portal? Just curious to see if it has been beneficial to anyone.
  • Justin_WorkmanJustin_Workman Cireson Support Advanced IT Monkey ✭✭✭
    I put it in my lab.  It works well! :)
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    heh we have been discussing something similar here recently, but i had missed this being uploaded.

    now that i've seen this one here i will be putting it into our dev environment for testing, and if it works well moving to production
  • Oskar_PittersOskar_Pitters Customer IT Monkey ✭
    Hi,
    running the powershell script I get the following error:
    Can you please help me
    Exception calling "GetClass" with "1" argument(s): "An object of class ManagementPackClass with ID
    7e6f57b1-a805-182c-392c-f73a2f387c5d was not found."
    At C:\Users\cobpio0\Desktop\WorkItemLock\Give end users permissions to write a work item lock..ps1:10 char:1
    + $class_cwl = $emg.EntityTypes.GetClass("7e6f57b1-a805-182c-392c-f73a2f387c5d")
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : ObjectNotFoundExceptionNew-Object : Cannot find an overload for "OperationImplicitScope" and the argument count: "4".
    At C:\Users\cobpio0\Desktop\WorkItemLock\Give end users permissions to write a work item lock..ps1:18 char:13
    + $oiobject = New-Object $oiscope -ArgumentList @($class_cwl.id,$emptyguid,$emptyg ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodException
        + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommandException calling "Update" with "0" argument(s): "Object reference not set to an instance of an object."
    At C:\Users\cobpio0\Desktop\WorkItemLock\Give end users permissions to write a work item lock..ps1:20 char:1
    + $prof_eu.Update()
    + ~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : NullReferenceExceptionNew-Object : Cannot find an overload for "OperationImplicitScope" and the argument count: "4".
    At C:\Users\cobpio0\Desktop\WorkItemLock\Give end users permissions to write a work item lock..ps1:23 char:13
    + $oiobject = New-Object $oiscope -ArgumentList @($class_cwl.id,$emptyguid,$emptyg ...
    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        + CategoryInfo          : InvalidOperation: (:) [New-Object], MethodException
        + FullyQualifiedErrorId : ConstructorInvokedThrowException,Microsoft.PowerShell.Commands.NewObjectCommandException calling "Update" with "0" argument(s): "Object reference not set to an instance of an object."
    At C:\Users\cobpio0\Desktop\WorkItemLock\Give end users permissions to write a work item lock..ps1:25 char:1
    + $prof_eu.Update()
    + ~~~~~~~~~~~~~~~~~
        + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException
        + FullyQualifiedErrorId : NullReferenceException
  • Justin_WorkmanJustin_Workman Cireson Support Advanced IT Monkey ✭✭✭
    @Oskar_Pitters - this script is assuming SCSM 2016.  Are you in SCSM 2016 or 2012?
  • Oskar_PittersOskar_Pitters Customer IT Monkey ✭

    Okay, I have SCSM 2012 R2 installed.

    But the scripts seems to work in my Test environment. I get a flag that the ticket ist currently edited by User X, and I can not make any changes on the Ticket.

    That's great work. I will test it the next day in our live environment.

  • Justin_WorkmanJustin_Workman Cireson Support Advanced IT Monkey ✭✭✭
    @Oskar_Pitters Also, did you import the MP before running the Powershell?  I'm trying it in my 2012 lab now and if you run the script before importing the MP, the Cireson WorkItem Lock class doesn't exist which is the first failure you're seeing.
  • Oskar_PittersOskar_Pitters Customer IT Monkey ✭
    @Justin_Workman I did the installation step by step as it is described. Imported the *.mp then updated the path variable in the powershell script to my installation path of SCSM. Script runs and throws the exceptions I posted above.

    I think that the Class ID in SCSM 2012 is different to SCSM 2016. Maybe you can tell me the Class ID.

    $class_cwl = $emg.EntityTypes.GetClass("7e6f57b1-a805-182c-392c-f73a2f387c5d")

    But it seems to work properly in my TEST environment.

  • Tom_HendricksTom_Hendricks Customer Ninja IT Monkey ✭✭✭✭
    I get a different type of error when running the script (on 2016):
    Exception calling "Update" with "0" argument(s): "The operation 7d6e1092-6ddc-4da1-a947-18fe5d538a69 in the profile 
    523382b8-c524-4641-a2e7-cfdfb4b6eb34 is already restricted to the same type or its base type. Hence there is no need to restrict it to the specified
    type."
    At C:\[PATH]\Give end users permissions to write a work item lock.ps1:20 char:1
    + $prof_eu.Update()
    + ~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ProfileOperationImplicitScopeAlreadyExistsException

    Exception calling "Update" with "0" argument(s): "The operation 7d6e1092-6ddc-4da1-a947-18fe5d538a69 in the profile
    523382b8-c524-4641-a2e7-cfdfb4b6eb34 is already restricted to the same type or its base type. Hence there is no need to restrict it to the specified
    type."
    At C:\[PATH]\Give end users permissions to write a work item lock.ps1:25 char:1
    + $prof_eu.Update()
    + ~~~~~~~~~~~~~~~~~
    + CategoryInfo : NotSpecified: (:) [], MethodInvocationException
    + FullyQualifiedErrorId : ProfileOperationImplicitScopeAlreadyExistsException

    I am not quite sure how to interpret this message.
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    @Tom_Hendricks can you try running the script again, but output $prof_eu to check it has been set correctly, you should get output for it similar to the below
    >$prof_eu

    Name : EndUser
    DisplayName : End User
    Description : End Users can use the self-service portal to create incidents, request software installation,
    view announcements, and search the knowledge base.
    HasSingleUserRole : False
    IsImplicitProfile : False
    ImplicitRelationship : 00000000-0000-0000-0000-000000000000
    IsImplicitEndpointSource : False
    Operations : {TypeProjection__Get, TypeCache__Get, Image__Get, User_Identity__Get...}
    Scope : 515
    Id : 523382b8-c524-4641-a2e7-cfdfb4b6eb34
    ManagementGroup : XXXXXXXX
    ManagementGroupId : xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

  • Tom_HendricksTom_Hendricks Customer Ninja IT Monkey ✭✭✭✭
    I do get very similar output.  If I grab $prof_eu.Operations.ImplicitScopes, I do see two identical items that suggest that I already have this in place (maybe from what I thought was an unsuccessful run?):

    Shortcut to this: $prof_eu.Operations.ImplicitScopes | ? { $_.Class -eq '7e6f57b1-a805-182c-392c-f73a2f387c5d'}

    Class : 7e6f57b1-a805-182c-392c-f73a2f387c5d
    Property : 00000000-0000-0000-0000-000000000000
    Relationship : 00000000-0000-0000-0000-000000000000
    RelationshipEndpoint : 2
    IsCustomized : True
    ManagementGroup :
    ManagementGroupId : 00000000-0000-0000-0000-000000000000
    These are actual values, not sanitized.

    Does it matter that I use a custom End User role instead of the OOB one?  The OOB role does exist, obviously, but it has no explicit members.  I attempted to add the internal name of my role on line 8 (also by ID and display name) but I got a bunch of nulls throughout the script that caused different errors.  So I have reverted back to this, to keep troubleshooting simple for now.
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    @Tom_Hendricks ;  This should work if added to the OOB End User Role, i ran it myself again, and didn't get those errors, even with it already setup, did you change the where{$_.name -eq "EndUser"} or leave it as is?

    we also don't use the OOB End User Role, but one based off it, and running the script with the only change being the path to the dll works every time here (SCSM 2016, SQL 2016, Server 2012R2)

  • Tom_HendricksTom_Hendricks Customer Ninja IT Monkey ✭✭✭✭
    @Jeff_Lang I believe you are correct.  I am testing it with an end user and it is working out great.  Our test environments are identical in terms of SCSM / SQL / OS, for what that is worth.

    I had originally changed that line to match my end user role, then changed it back and ran again.  I will run it clean in the next environment.

    But the good news is that this appears to be working fine in spite of the errors.

    @john_doyleI absolutely love this! 

    I modified mine to have a persistent message at the top-right of the page, but I want to live with it for a while and get extra opinions before actually sharing it as a suggestion.  Your way might be the right one--my way is just more similar to the way our old system worked.

    I do plan to run a workflow to clean out "old" locks, potentially...but I want to test the usefulness of keeping them first.  I did create a CI view of them so that I can see where this goes.
  • Jeff_LangJeff_Lang Customer Advanced IT Monkey ✭✭✭
    @Tom_Hendricks glad to hear it is working now, have been testing this a bit, and made some slight modifications to suit our environment a bit more, hopefully we'll be able to add this to production within the next week or 2.

    Like you we'll also be adding something to clear out old items, not sure if we'll have it clear out items older than a day or week etc yet though
  • Tom_HendricksTom_Hendricks Customer Ninja IT Monkey ✭✭✭✭
    I just wanted to provide an update.  We have rolled a slightly modified version of this all the way through our environments to production, and it is working extremely well. 

    Although I am still testing this in lower environments, initial testing is showing that we can "safely" disable the concurrency check without losing updates made by the system account, as a result.  If my last batch of tests works out, that will be a HUGE win, as the "data conflict error" is one of the most-complained-about "features."  Even if that does not work out, this is still providing benefit.

    I have the success block of the lock object commit creating an object in the view model, so that other functions of mine can A.) know that there is a lock, B.) know whether it belongs to the current user or someone else, outside of the scope of this code, and C.) I can run other functions based on whether the current user is locked out, such as removing certain tasks.  I have a message right below the title that indicates if the current user has the lock, or if someone else does.  If someone else, their name is a clickable link that opens a Skype IM.

    You are a hero, @john_doyle
Sign In or Register to comment.