Showing posts with label OSD. Show all posts
Showing posts with label OSD. Show all posts

Thursday, 7 March 2013

Adding Action to Task Sequence via ConfigMgr SDK

Hello again!

I've been doing more work with the ConfigMgr 2012 SP1 SDK and quietly bashing my head against my keyboard...This is probably just due to me not being a coding genius, instead a coding pleb. So, I wanted to figure out how to add an action to a Task Sequence - took a look at the SDK and the code example is as follows:

public IResultObject AddTaskSequenceActionCommandLine(
    WqlConnectionManager connection, 
    IResultObject taskSequence,
    string name, 
    string description)
{
    try
    {
        // Create the new step.
        IResultObject ro;

        ro = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RunCommandLineAction");
        ro["CommandLine"].StringValue = @"cmd /c Echo Hello";

        ro["Name"].StringValue = name;
        ro["Description"].StringValue = description;
        ro["Enabled"].BooleanValue = true;
        ro["ContinueOnError"].BooleanValue = false;

        // Add the step to the task sequence.
        List array = taskSequence.GetArrayItems("Steps");

        array.Add(ro);

        taskSequence.SetArrayItems("Steps", array);

        return ro;
    }
    catch (SmsException e)
    {
        Console.WriteLine("Failed to add action: " + e.Message);
        throw;
    }
}




"Oh yeah - that looks pretty easy" I though to myself. But after a lo-o-o-ong time trying to get this working, I was hitting a brick wall. I could get the steps of the task sequence, I could add them to the list, and I could even set the steps to the updated array. Great! However this was not showing up in the Task Sequence. No exceptions were being raised, just nothing happening at all. It seemed like the changes just were not saving, and I guess this is actually what was happening.

So, in ConfigMgr SDK terms, a ConfigMGr Task Sequence (WMI Class: SMS_TaskSequence) and a ConfigMgr Task Sequence Package (WMI Class: SMS_TaskSequencePackage) are two separate items. Modifications to the SMS_TaskSequence object don't do anything UNLESS they are associated to the relevant SMS_TaskSequencePackage.
Now, this might be totally straightforward to you, but it took a bit of head scratching by me to get it. But, get it I did!

public IResultObject AddTaskSequenceActionCommandLine(
    WqlConnectionManager connection, 
    IResultObject taskSequence,
    string name, 
    string description)
{
    try
    {
        // Create the new step.
        IResultObject ro;

        ro = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RunCommandLineAction");
        ro["CommandLine"].StringValue = @"cmd /c Echo Hello";

        ro["Name"].StringValue = name;
        ro["Description"].StringValue = description;
        ro["Enabled"].BooleanValue = true;
        ro["ContinueOnError"].BooleanValue = false;

        // Add the step to the task sequence.
        List array = taskSequence.GetArrayItems("Steps");

        array.Add(ro);

        taskSequence.SetArrayItems("Steps", array);

        //Get the relevant Task Sequence Package
        IResultObject tsPackage = connection.GetInstance("SMS_TaskSequencePackage.PackageID='" +
                 pkgID + "'");
        
                Dictionary inParams = new Dictionary();
                inParams.Add("TaskSequence", taskSequence);
                inParams.Add("TaskSequencePackage", tsPackage);

                // Associate the task sequence with the package. 
                IResultObject result = connection.ExecuteMethod("SMS_TaskSequencePackage", "SetSequence", inParams);

        return ro;
    }
    catch (SmsException e)
    {
        Console.WriteLine("Failed to add action: " + e.Message);
        throw;
    }
}




So, I just had to run the SetSequence method on the SMS_TaskSequencePackage class. This method takes parameters of the Task Sequence object, and the Task Sequence package object.Once this was done, the action added without any dramas. Huzzah!

I stress again, this is probably clearly explained somewhere, but pretty hard to find out, hence me sharing this. Hopefully it helps! Let me know in the comments if I've been daft and missed the article that explains this :)

Tuesday, 5 March 2013

PreCaching Task Sequence on Client Machine

One of the most annoying things i've found about ConfigMgr is the inability to preload contents on the client - either by preloading the client cache, or any other method.
I have found a way to preload Task Sequence components, so you can run an OS deployment off a client machine, reducing network load and increasing the amount of machines you can potentially build at one time.
You will need TSENV2.EXE to do this, you can get this here - its the Advanced Task Sequence Environment tool - used to overwrite normally readonly TS Variables (those starting with_)

So the idea here is to override the TS variables pointing to network locations and redirect them to a local folder. The other part of this is ensuring your local content does not get removed by a format or wipe when the OS is applied.

Part 1 : Overriding content location

The content location is stored in the _SMSTSPackageID task sequence variable
To override this, use TSENV2 like so:
tsenv2.exe set _SMSTSPackageID =sNewLocation

For example:
tsenv2.exe set _SMSTSA0100012 = sC:\Cache\A0100012\

This points the package source locally. The lowercase s above is actually very important, and not a typo!

Part 2 : Protecting Cache folder

Obviously we want our cache folder to not be deleted or otherwise removed until the build has completed - there are a couple of ways of doing this.
Firstly you need to ensure your TS has no Format and Partition steps, as this will remove the cached packages.
1. Set the cache folder to be the Local State Store directory, this will ensure its protected
2. Add the cache folder to the protected folders list (this contains such folders as the Task Sequence local folder and the state store folder. This list is stored in the variable : _SMSTSProtectedPaths

You can choose the option that best suits you, I prefer the local state store method as its very easy (just set the OSDStateStore variable and you are done).
To use mthod 2, you will need a script that reads the _SMSTSProtectedPaths variable, and then uses TSENV2 to overwrite it with the existing content, plus the new folder.

Step 3 - Implementation
To use this method to build your machine locally, you need to do the following:
1. Copy the package content to the client machines (up to you how you want to do this, robocopy, usb, use sccm) As long as all the packages are in the same folder and clearly identified with the package ID it doesnt matter how they get there.
2. Create a script to override your TS variables to the new location. Do this by iterating through each _SMSTSblahblah variable in the TS Variables, then matching the package id to a cached subfolder in your cache location and finally overriding each variable.

I will try to get some sample code up if anyone is interested (drop me a comment). It's a very simple script - as mentioned above, just get your content to the computer, step through each _smsts variable, match it to existing content on the machine and override.
Hope this helps!
FYI - this was done on ConfigMgr 2007 , I havent tested to see if the same principles apply to ConfigMgr 2012.