Quantcast
Channel: Symantec Connect - Endpoint Management - Articles
Viewing all articles
Browse latest Browse all 861

Patch Management Automation 7.1: A Look at the Project and Code

$
0
0

Due to popular demand on the download tool [1] (okay, one person asked - but that's enough for me ;-) I am releasing and documenting the source code (Visual Studio 2005 solution and project) here.

We will review here the assembly references needed to build the project, the code itself and the SQL (as this could be changed to target only bulletins with vulnerable computers).

So, let's dive into the project and assembly references: first of all we are using the PatchManagement WorkFlow API to stage and create the bulletin policies. This API is implement in "<install_path>\Patch Management\Core\Web\bin\Altiris.PatchManagementCore.Web.dll".

Here is a screen shot of some of the classes and methods exposed by this DLL (with the one that interest us highlighted):

Then we need to bring in a few assemblies from the GAC (which can be tricky in itself, but that's another subject on its own), namely:

  • Altiris.NS.dll
  • Altiris.NS.Common.dll
  • Altiris.NS.Database.dll
  • Altiris.Resource

And here comes a review of the code itself (from program.cs, unabridged but broken down into sections of interest):

First we do the traditional declaration of types namspaces that we will use, so we don't have to provide full path to classes to use them.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;


using Altiris.NS;
using Altiris.Resource;
using Altiris.NS.ItemManagement;
using Altiris.NS.ContextManagement;
using Altiris.NS.Security;
using Altiris.Common;
using Altiris.PatchManagementCore.Web;

Then comes the name space declaration, class declaration and global variables:

namespace ZeroDayPatch
{
    class Program
    {
        static string targetGuid = "";
        static string severity = "critical";
        static bool dryrun = false;
        static bool test = false;

This tool is command line based, so the program starts in the function Main():

        static void Main(string[] args)
        {

Which starts processing by checking the command line argument and setting global variables accordingly:

            Console.Write("ZeroDayPatch starting");
            foreach (string arg in args)
            {
                if (arg.ToLower().StartsWith("/targetguid="))
                {
                    targetGuid = arg.Substring("/targetguid=".Length);
                    Console.Write(", Custom target guid = {0}", targetGuid);
                }
                if (arg == "/dryrun")
                {
                    dryrun = true;
                    Console.Write(", tryrun = true");
                }
                if (arg == "/test")
                {
                    test = true;
                    Console.Write(", test = true");
                }
                if (arg.ToLower().StartsWith("/severity="))
                {
                    severity = arg.Substring("/severity=".Length);
                    Console.Write(", severity = {0}", severity);
                }
            }

            Console.Write("\n\n");

Now we're all set, so we can start the real work: get a list of bulletins we want to check and process them:

            int i = 0;
            try
            {
                SecurityContextManager.SetContextData();
                GuidCollection bulletins = new GuidCollection();

                bulletins = GetSoftwareBulletins();

                PatchWorkflowSvc wfsvc = new PatchWorkflowSvc();

                string name = "";

                if (dryrun)
                    Console.WriteLine("\n######## THIS IS A DRY RUN ########");
                foreach (Guid bulletin in bulletins)
                {
                    name = Item.GetItem(bulletin).Name;
                    Console.WriteLine("");
                    Console.WriteLine("Processing bulletin {0} ({1}) now.", name, bulletin);
                    if (wfsvc.IsStaged(bulletin.ToString()))
                    {
                        Console.WriteLine("\tThis bulletin is already staged.");
                    }
                    else
                    {
                        Console.WriteLine("\t... bulletin will be stagged now.");
                        if (!dryrun)
                            wfsvc.EnsureStaged(bulletin.ToString(), true);
                        Console.WriteLine("\tBulletin is now stagged.");
                    }
                    Console.WriteLine("\tChecking if we need to create a new policy now.");

                    if (targetGuid == "" || targetGuid.Length == 0)
                        targetGuid = "f74f662b-f586-457a-9a2e-804cc8f347e5";

                    string policyGuid = "";
                    policyGuid = wfsvc.ResolveToPolicies(bulletin.ToString());

                    // Console.WriteLine("Existing policy guids: " + policyGuid);
                    if (policyGuid == "" || policyGuid.Length == 0)
                    {
                        Console.WriteLine("\t... create a policy for the bulletin now.");
                        if (!dryrun)
                        {
                            wfsvc.CreateUpdatePolicy(name, bulletin.ToString(), targetGuid, true);
                            i++;
                        }
                        Console.WriteLine("\tSoftware update policy created!");
                    }
                    else
                    {
                        Console.WriteLine("\tA policy already exists for this bulletin.");
                    }
                    if (i == 10  && test)
                        break; // Limit the staging to 10 bulletin whilst testing
               }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            Console.WriteLine("\n{0} software update policy creation tasks were started.", i.ToString());
            Console.WriteLine("ZeroDayPatch execution completed now. See you soon...");

/*          Console.Write("Press enter to terminate...");
            Console.ReadLine();
*/      }

Here is the method where we get the list of bulletins: you can use a procedure or SQL query of your own to get bulletins that are for example applicable to the environement:

        public static GuidCollection GetSoftwareBulletins()
        {
            GuidCollection gcResources = new GuidCollection();

            string strSelect = @"exec spPMCoreReport_AllSoftwareBulletins";


            using (DatabaseContext context = DatabaseContext.GetContext())
            {
                SqlCommand cmdAllResources = context.CreateCommand() as SqlCommand;
                cmdAllResources.CommandText = strSelect;

                using (SqlDataReader sqlRdr = cmdAllResources.ExecuteReader())
                {
                    while (sqlRdr.Read())
                    {
                        Guid bulletinGuid = sqlRdr.GetGuid(0); // Position 0 = _ResourceGuid
                        String sev = sqlRdr.GetString(2); //Position 2 = Severity

                        // if (sev.ToUpper() != "UNCLASSIFIED" && sev.ToUpper() != "LOW" && sev.ToUpper() != "MODERATE")
                        if (sev.ToUpper() == severity.ToUpper())
                        {
                            //Console.WriteLine("Acquired guid {0} with severity {1}...", bulletinGuid.ToString(), sev);
                            gcResources.Add(bulletinGuid);
                        }
                    }
                }
            }
            Console.WriteLine("{0} bulletins match the {1} severity and will be checked for policies.", gcResources.Count, severity);
            return gcResources;
        }

    }
}

This is it. Any comments and feedback is more than welcome as usual :D.

[1] https://www-secure.symantec.com/connect/downloads/patch-automation-tool-pms-71-sp2


Viewing all articles
Browse latest Browse all 861

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>