Clear System Center End Point Protection Exclusions without SCCM
Defining the problem
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.
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
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
Copy the program to the $admin\temp path on remote computers, and run it from a central console. 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: