Showing posts with label Configuration Manager 2012. Show all posts
Showing posts with label Configuration Manager 2012. 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 :)

Monday, 4 March 2013

Configuration Manager 2012 SP1 SDK - Error trying to update boot image

Hi,
Long time, no post.

Expect a bunch more action on this blog, I'm working on a project that is based on System Center Orchestrator and ConfigMgr 2012 SP1 - as such, I'm writing a custom Orchestrator Integration Pack to contain a bunch of (what I think) are useful actions. Anyway, onto the post...

I have been trying to write an Orchestrator action to inject Drivers into a specified boot image. But hey, that's all detailed in the ConfigMgr SDK right? Well... kind of!

The SDK shows you how to import the driver to the package - However when you run the RefreshPkgSource method of the SMS_BootImagePackage class with the following:
bootImagePackage.ExecuteMethod("RefreshPkgSource",null);
An SMSException is raised, and in the SMS Provider logs you will notice an eror along the lines of: *~*~Null parameter object! ~*~*

Annoying!

So I checked the paramters of the RefreshPkgSource method here - It has a ContextID parameter defined as optional. I then checked the ContextID property of an instance of the SMS_BootImagePackage class, and saw a blank entry. Putting two and two together, it seems it is expecting something other than null to actually run the method.

So I created a Dictionary object to hold the blank parameter instead of specifying a null parameter and YOWZA - success!
Full code is as follows:

Configurations.WQLConnect wql = new Configurations.WQLConnect();
WqlConnectionManager connection = wql.Connect(Credentials.siteServer, Credentials.User, Credentials.Password);
            try
            {
                // Get the boot image package.
                IResultObject bootImagePackage = connection.GetInstance(@"SMS_BootImagePackage.packageId='" + request.Inputs["Boot Image Package ID"].AsString() + "'");

                // Get the driver.
                IResultObject driver = connection.GetInstance("SMS_Driver.CI_ID=" + request.Inputs["Driver CI"].AsString());

                // Get the drivers that are referenced by the package.
                List referencedDrivers = bootImagePackage.GetArrayItems("ReferencedDrivers");

                // Create and populate an embedded SMS_Driver_Details. This is added to the ReferencedDrivers array.
                IResultObject driverDetails = connection.CreateEmbeddedObjectInstance("SMS_Driver_Details");

                driverDetails["ID"].IntegerValue = request.Inputs["Driver CI"].AsInt32();
                driverDetails["SourcePath"].StringValue = driver["ContentSourcePath"].StringValue;

                // Add the driver details to the array.
                referencedDrivers.Add(driverDetails);

                // Add the array to the boot image package.
                bootImagePackage.SetArrayItems("ReferencedDrivers", referencedDrivers);
               
                // Commit the changes.
                
                bootImagePackage.Put();
                Dictionary inParams = new Dictionary();
                inParams.Add("ContextID", "");

                IResultObject result = bootImagePackage.ExecuteMethod("RefreshPkgSource", inParams);




Hope that helps someone, and saves you a little bit of time!