Defining the problem

I recently had a requirement to install / configure / modify Microsoft's System Center End Point Protection software on around 1000 servers without using System Center Configuration Manager.

Installing, performing scans, changing the policy, and gathering data on the system health are trivial.

However, when changing the policy via ConfigSecurityPolicy.exe, it was noticed that the old exclusions were not removed from the registry.

I figured we must be building our policy xml files incorrectly, and started a Bing search, which led to a similar question in the Forefront forums: FEP Policy not applying completely.

Registry Keys of interest

So, I created the following program, which when run from the target server, clears out the following registry keys:
SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\Extensions
SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\Paths
SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\Processes
SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions\TemporaryPaths

The program first grants Ownership of the key SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions to the local Administrators group, then takes ownership of the subkeys, before clearing out the values.

We run the program remotely just before changing policies.

Code

using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Security.AccessControl;
 
namespace modifyRegistry
{
    class Program
    {
        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
            ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);
        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);
        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);
        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct TokPriv1Luid
        {
            public int Count;
            public long Luid;
            public int Attr;
        }
        internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
        internal const int TOKEN_QUERY = 0x00000008;
        internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
        static System.Security.Principal.NTAccount adminAccount = new System.Security.Principal.NTAccount("Administrators");
        static RegistryAccessRule rule = new RegistryAccessRule(adminAccount, RegistryRights.FullControl, AccessControlType.Allow);
        static string exclusionKey = @"SOFTWARE\Microsoft\Microsoft Antimalware\Exclusions";
        static RegistryKeyPermissionCheck permissionCheck = RegistryKeyPermissionCheck.ReadWriteSubTree;
        static RegistryRights rights = RegistryRights.TakeOwnership;
        static void Main(string[] args)
        {
            EnablePrivilege();
            using (RegistryKey rk = Registry.LocalMachine.OpenSubKey(exclusionKey, permissionCheck, rights))
            {
                if (rk != null)
                {
                    TakeOwnershipOfKey(rk, "Extensions");
                    ClearKey(rk, "Extensions");
                    TakeOwnershipOfKey(rk, "Paths");
                    ClearKey(rk, "Paths");
                    TakeOwnershipOfKey(rk, "Processes");
                    ClearKey(rk, "Processes");
                    TakeOwnershipOfKey(rk, "TemporaryPaths");
                    ClearKey(rk, "TemporaryPaths");
                }
            }
        }
        public static void TakeOwnershipOfKey(RegistryKey rootKey,string subKey)
        {
            using (RegistryKey myKey = rootKey.OpenSubKey(subKey, permissionCheck, rights))
            {
                RegistrySecurity acl = myKey.GetAccessControl(AccessControlSections.None);
                acl.SetOwner(adminAccount);
                myKey.SetAccessControl(acl);
                acl = myKey.GetAccessControl(AccessControlSections.Access);
                acl.SetAccessRule(rule);
                acl.SetAccessRuleProtection(true, true);
                myKey.SetAccessControl(acl);
                myKey.Close();
          }
        }
        public static void ClearKey(RegistryKey rootKey, string subKey)
        {
            foreach (string registryValue in rootKey.OpenSubKey(subKey).GetValueNames())
            {
                Console.WriteLine("deleting the value " + registryValue);
                rootKey.CreateSubKey(subKey).DeleteValue(registryValue);
            }
        }
        public static void EnablePrivilege()
        {
            Process currentProcess = Process.GetCurrentProcess();
            IntPtr hproc = currentProcess.Handle;
            TokPriv1Luid tp;
            IntPtr htok = IntPtr.Zero;
            OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
            tp.Count = 1;
            tp.Luid = 0;
            tp.Attr = SE_PRIVILEGE_ENABLED;
            LookupPrivilegeValue(null, "SeTakeOwnershipPrivilege", ref tp.Luid);
            AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
        }
    }
}

Running the program

I copy the program to the $admin\temp path on remote computers, and run it from a central console. I use the Create method of the Win32_Process class.


Output

Before running the program

The image below is representative of the Paths key before running the program:



During program execution


As the program is running, it displays the values that are removed:
deleting the value C:\Windows\Security\Database\*.jrs
deleting the value C:\Windows\Security\Database\*.log
deleting the value C:\Windows\Security\Database\*.sdb
deleting the value C:\Windows\SoftwareDistribution\Datastore\Datastore.edb
deleting the value C:\Windows\SoftwareDistribution\Datastore\Logs\Edb.chk
deleting the value C:\Windows\SoftwareDistribution\Datastore\Logs\Res*.jrs
deleting the value C:\Windows\SoftwareDistribution\Datastore\Logs\Res*.log
deleting the value C:\Windows\SoftwareDistribution\Datastore\Logs\Tmp.edb
deleting the value C:\Windows\system32\spool\PRINTERS\*.shd
deleting the value C:\Windows\system32\spool\PRINTERS\*.spl
deleting the value C:\pagefile.sys

After running the program


Once the program is finished, the keys are empty:



See Also