Building a Better Task Sequence

Be sure to check out the sequel to this post Building an Even Better Task Sequence.

I’ve had this post in the queue for a while now and have been working on a script to help with some of this, but with the release of System Center Configuration Manager 1810 I don’t have to hack something together anymore! One of the best new features which allows us to capture the name of the last action using the new variable _SMSTSLastActionName. I’m so excited about this new variable! Let’s get to it.

Failure is Ineveitable

No matter how well you build your ConfigMgr Task Sequences, you will encounter failures. When you are testing in your lab, no big deal, but what about failures at a user’s desk during an In-Place Upgrade? Adding structure to your Task Sequences that can properly handle the failures will add an extra layer of protection against incomplete deployments going unnoticed.

Try – Catch – Finally

If you’ve ever done any programming, you will likely be familiar with concept of Try-Catch-Finally. The general idea is that Try is your block of code. As it executes, if an error occurs, you can allow the code to continue to execute (non-fatal error) or you can Catch the error (fatal-error). In the Catch block, you can execute additional code to process the error. Then, regardless of what else happens, the Finally block will run to process any additonal code that you ALWAYS want to run, no matter the outcome of the previous code. If you structure your Task Sequence using similar logic, you can improve the chances of capturing and remiating failures and reduce the number of failed deployments that make it out into production.

Basic Framework

Inside your Task Sequence, always create a top level group. I like doing this so it’s easier to copy and paste the entire task sequence. Inside this group, create 4 groups at the same level. Main, Failure, Success, Cleanup.

On the Main, Failure and Success groups, check the Continue on error box.


All of your task sequence logic will go into the Main section. If you already have an existing task sequence, you can just add a Run Task Sequence step and reference it! The biggest thing to keep in mind is that you should never enable Contiue on error for any step that is critical or required for a deployment to be considered a success. In fact, if you have a step that occasionally fails, try to add logic to detect whether you need to run the step, before attempting it, just to eliminate any unncessary errors from always showing up in the logs. Additionally, failures fail up the the parent group, so you could have steps fail inside a group, but have the group continue using Continue on error

As the last step in Main, add:

By setting this variable, we will know whether we made it to the end without any fatal errors.


Next, select the Failure group and select Options and add the following Condition: Task Sequence Variable _SMSTSLastActionSucceeded equals False

This will ensure that the Failure group only gets processed if the previous action failed.

Add a Set Dynamic Variables step and set the following:

It’s important that this is the first step that you run after a failed step or else you will lose the values. Now that you’ve captured them, you can process any additional steps that you need to inside the Failure group.


Next, select the Success group and select Options and add the following Condition: Task Sequence Variable AllStepsSucceeded equals True. This will ensure that Success will only run if the task sequence made it to the end without failure. You can add any steps inside here that you would only want to run if the Task Sequence was successful.


Finally, on the Cleanup group, add steps like Copy Logs or Remove from Provisioning Mode or any other steps that will help make it easier to triage failed deployments. No matter what you add here, be sure that the final step is this one:

This last step is the one made possible with ConfigMgr 1810. Now, when my Task Sequence fails and the error dialog is still on the screen, it will display the name of the last step that ran before the error occurred using the _SMSTSLastActionName build-in variable.

The result that a user will see (and likely send you a screenshot of) will show the name of the step that caused the failure now, even though you have already processed all of your cleanup steps, like copying logs. At least at my site, this is a HUGE feature that will make triage much simpler.


If you build a better task sequence, you will build a better deployment experience for your users and your first line workers who have to troubleshoot issues. Next steps to consider would be adding things like splash screens or login blocking policies (lots of great community blogs about these concepts). You could even get fancy and hide the progress dialog box and show a custom one, including the error dialog. There are so many great ways to customize your Task Sequences, I am just really excited about the _SMSTSLastActionName variable!


I know it’s not much, but you can download the sample Task Sequence here.


  • Reply
    December 14, 2018 at 2:48 pm

    Before I sound like a condescending jerk… I love the information and your entire blog. There is a ton of really good information based on real world experience.

    Error handling is already provided by Microsoft when integrating MDT and creating/using an MDT task sequence. It does require that you use the wizard to get the full advantage of MDT, but there is a lot of really good error handling built-in and wouldn’t require creating the error handling from scratch. Now, that does mean integrating MDT with ConfigMgr. There are lots of really good reasons to do the integration, and honestly, until MDT is retired (doesn’t appear to be any time soon), every ConfigMgr environment that uses OSD should integrate MDT.

    • Reply
      Adam Gross
      December 14, 2018 at 4:27 pm

      First, glad you like the blog.

      Second, nothing condescending about your statement.

      Third, I personally don’t like the MDT TS structure and all of the “bloat” that doesn’t add any value for my environment, so we don’t use anything other than Gather, and even that has a reasonable PowerShell replacement that does a lot of the same things. While an MDT TS May have error handling structure, the main point of my post was to reinforce 2 things – 1) there’s no reason to let the TS fail without proper handling and 2) the _SMSTSLastStepName is new and changes the way that we can provide support to our users and quickly get information about what failed before going into the logs.

      Using MDT is great if that works for you and it provides you with the needed structure to capture errors. If that works well enough for someone’s environment, I certainly would discourage its use. It’s just not what I use and I believe many others are in the same boat and needed a refresher on error handling if they weren’t familiar with MDT.

  • Reply
    January 11, 2019 at 3:57 pm

    Maybe Im missing something but it seems that the _SMSTSLastActionName variable does not get populated until after the Setup Windows and Configuration Manager step. In testing, failing the OSD immediately after partitioning the HDD and anywhere before the Setup Win and CM step, the Custom Error Dialog shows Failed Step Name: “%_SMSTSLastActionName%”. Failed Step Error Code however does populate properly based on the exit code.

    • Reply
      Adam Gross
      January 11, 2019 at 3:58 pm

      Have you upgraded SCCM to version 1810? Otherwise the variable doesn’t exist yet.

      • Reply
        January 11, 2019 at 4:02 pm

        Yes running 1810. And if the failure happens after the Setup Win and CM step, it lists the failed step name properly. Using powershell in the active OSD, the getvariable() does not list a _SMSTSLastActionName variable. Is the variable not active in the WinPE maybe; since after Setup Win/CM step its in the main OS.

        • Reply
          Adam Gross
          January 11, 2019 at 4:14 pm

          I’ve only done some basic testing – what you see on the blog – at this point. We will be upgrading production to 1810 within the next week and I hope to implement this solution then and may have better info.

          One thing to consider – are you installing the latest SCCM client in your TS? I wonder if that could be the issue. Any time I have seen variables display as %variable% it generally means that the variable doesn’t exist. The underscored variable names are readonly as well. You should be able to pause your TS or at least run a dump variables script at various points to see all of the variables listed out.

          Also, what PowerShell are you using to check the values?

  • Reply
    February 25, 2019 at 3:36 pm

    Hi Adam,

    I have some general issues with these steps unfortunately. The methodology seems sound, but I’ve tried to duplicate this process in my own environment, and found several problems.

    1st – Several times there are typos in your variables above, mostly the word “succeed” is spelled with 1 ‘C’ in some places, and in others, its spelled with 2 ‘C’s. Please fix this.

    2nd – Your Cleanup group has no condition on it, so it will run regardless of weather or not the task sequence fails. and the copy logs step will actually run twice as in my environment since I have a copy logs at the end of my main section. To fix this issue, I’ve ended up just moving the Cleanup Group to the end of the Failure group so that it only runs as part of the failure section.

    I do like the idea of a custom error dialog, so I’ve ended up creating a simple HTA that runs that shows it a bit more defined.

    • Reply
      Adam Gross
      February 25, 2019 at 7:36 pm

      Thanks for the feedback. I’ve got several site edits to make soon and will try to incorporate some edits for the typos.

      As for the cleanup step, it is intentionally built with no conditions. Since I copy logs on success or failure, as well as perform other cleanup actions like deleting some temps folders and such, I use the cleanup group as a catchall for common tasks that I always want to run.

      For example, you say that you copy logs at the end of main. Do you also run it in the failed group? If not, why? If so, why run it in 2 places?

      Hope this makes sense. Thanks for your comments and I hope that it helps give you ideas for things that will work in your environment.

    • Reply
      Adam Gross
      February 25, 2019 at 7:37 pm

      I also should have mentioned – please check out the Building An Even Better Task Sequence that was a follow up to this post and added new functionality with SSCM 1810.

  • Reply
    October 10, 2019 at 5:13 am

    Adam, I’m using this type of task sequence for IPUs.

    Would you recommend including the var ‘_SMSTSSetupRollback’ in the ‘failure’ section or keep it in the main section as part of the upgrade steps?

    At the moment I have it in the main section, but would like to shorten my task sequence steps if I can. Obviously it’s very difficult to force a rollback so I’m unable to test this logic really, unless you somehow know of a way to force a rollback by sabotaging the upgrade somehow?

  • Reply
    June 8, 2020 at 8:39 am

    hi adam
    I did find some type with the ‘succeeded’ word. Sometimes it appears like ‘suceeded’ and I got it wrong with my TS using copy/paste

  • Reply
    February 15, 2021 at 1:24 pm

    Set Dynamic Variables is not available step in my MDT… How did you add this step?

    • Reply
      Adam Gross
      February 15, 2021 at 1:41 pm

      You need to use ConfigMgr. This isn’t designed for MDT.

  • Reply
    March 29, 2021 at 7:27 pm

    Did ConfigMgr stop allowing for task sequence step names to be dynamically populated from task sequence variable values at some point (if it ever worked)? We’re seeing that in this example, the step named %FailedStepName% in the Cleanup group always has its name being treated as a literal string “%FailedStepName%”, not as the interpolated task sequence variable value.

    Not the end of the world … but means a bit more custom error handling (especially for error propagation in nested task sequences).

    • Reply
      Adam Gross
      March 29, 2021 at 8:20 pm

      In my experience, whenever you see this, it’s generally because the variable isn’t getting populated. You can test that using a Run Command Line step and use cmd /c ECHO “%FailedStepName%” and check the logs to see what it shows.


    This site uses Akismet to reduce spam. Learn how your comment data is processed.