Automating Audit Collection Services in Workgroups with PowerShell

The Case

We all have the same experience with ACS Forwarders, known also as ACS Agents. While enabling ACS on the agent isn’t that hard to master, as you just have to run task inside OpsMgr console on the Health Service object, the pain starts when you need to start working with non-domain or non-trusted domain environments.

Whole point is that nearly all tasks have to be done manually (well, that’s what official documentation says). What we will try to achieve is to automate whole process which was never possible.

The Process

The process is very clearly documented in blog article by Udish. There are several steps which I won’t be covering at all as the process is often different in each company like certificate creation or agent installation process. I would like to explicitly cover three steps which are often done manually and this makes it very boring and overwhelming, especially when a company has a relatively short certificate lifetime.

Process 1 – Computer Account Creation

When you gather security logs from a non-domain or cross-untrusted domain server, your first point is creating a dummy computer account inside domain, where ACS Collector resides. As this is very straightforward. Your friend is New-ADComputer.

New-ADComputer -Name "USER02-SRV2" -SamAccountName "USER02-SRV2" -Path "OU=ApplicationServers,OU=ComputerAccounts,OU=Managed,DC=USER02,DC=COM"

Process 2 – Importing your computer certificate to computer object

The second part of this process is something, which manually is done by selecting Name Mappings on computer account and from there you are choosing a certificate to be imported. Now what does this exactly do? It just creates a special entry in altsecurityidentities property of computer object. And it in reality doesn’t do anything with this certificate except retrieving its Common Name and Issuer. That’s relatively easy to achieve. You can put your certificate in a specific location and take its properties, modify their format to be able to import it into AD property field and we’re done. Because the field takes a bit strange format (X509:<I>DC=com,DC=contoso,OU= IssuingCAs,CN=IssuingCA123<S>DC=com,DC=contoso,CN=USER02-SRV2) we need to somehow parse the fields to reverse order of path values.

$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate "$file" #Just before declare $file as a path to your CER file
$comp = Get-ADComputer -Filter {Name -Like $server} -Server $Domain #Also declare $server and $domain to query for computer object
$paths = [Regex]::Replace($cert.Issuer, ',\s*(CN=|OU=|O=|DC=|C=)', '!$1') -split "!"
$issuer = ""
# Reverse the path and save as $issuer
for ($i = $paths.count -1; $i -ge 0; $i--) {
$issuer += $paths[$i]
if ($i -ne 0) {
$issuer += ","

# Do the same things for $cert.subject
$paths = [Regex]::Replace($cert.subject, ',\s*(CN=|OU=|O=|DC=|C=)', '!$1') -split "!"
$subject = ""
# Reverse the path and save as $subject
for ($i = $paths.count -1; $i -ge 0; $i--) {
$subject += $paths[$i]
if ($i -ne 0) {
$subject += ","

 # Format as needed for altSecurityIdentities
$newcert = "X509:<I>$issuer<S>$subject"

# Insert data
try {
$comp | Set-ADComputer -Add @{'altsecurityidentities'=$newcert}
Write-Output "Cannot write value to altsecurityidentities. Check permissions on domain level for your user. Failed server = $server"

Now having it done we can go to the most tricky part which is…

Process 3 – Importing certificate to ACS Forwarder

We all know that the one and only way is to fire adtagent -c, choose one and only certificate and then launch task from OpsMgr Console. Well… up to now 😉

I assumed in my process that OpsMgr Agent (MMA Agent) is already up and running also with addition of certificate, so MomCertImport has already been run and agent is green in console. That gives us a big step forward as we have data already. Let’s start our work.

Firstly we need to retrieve the certificate we have to use:

$cert = (Get-ChildItem Cert:\LocalMachine\My | where { $_.Thumbprint -eq (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Microsoft Operations Manager\3.0\Machine Settings' -Name ChannelCertificateHash).ChannelCertificateHsdash })

From now on we have our $cert object filled with certificate, which has the same Thumbprint as the one imported into OpsMgr Agent configuration in registry. From this certificate we have to retrieve the thumbprint as this value is later stored in AdtAgent service registry

$certdata = $($cert.Thumbprint)

The certificate’s thumbprint as a string is now stored in $certdata variable… but the value inside registry key is stored in… Binary value. So again, converting is our goal.

$newdata = for ($i = 0; $i -lt $certdata.Length; $i += 2) { [convert]::ToByte($certdata.Substring($i,2), 16) }
# Setting the value inside ADTAGENT service registry
Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Services\AdtAgent\Parameters' -Name CertHash -Value $newdata -Type Binary

Now that step would be enough if the certificate would be imported into AdtAgent for the second or latter time. If it is for the first time, the account on which AdtAgent runs (normally Network Service) has to have access to decrypt data with this certificate and this is done by access to RSA files hidden inside ProgramData folder.

Firstly we will create proper ACL

# Static path for RSA Keys in Windows
$fileRSAlocation = 'C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\'
# Getting Network Service SID Object
$principal = New-Object System.Security.Principal.SecurityIdentifier([System.Security.Principal.WellKnownSidType]::NetworkServiceSid, $null)
# Rule for ACL to be added to key file
$right = 'Read'
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($principal, $right, 'Allow')

Now we need to find the proper file for this certificate

$certRSAStore = $($cert.PrivateKey.CspKeyContainerInfo.UniqueKeyContainerName)

And finally apply ACS and restart agent (if already configured) or you can skip restart and launch Enable Audit Collection Services task in OpsMgr Console.

$path = $fileRSAlocation + $certRSAStore
$acl = Get-Acl -Path $path
Set-Acl -Path $path -AclObject $acl

#Restarting ACS Agent (adtagent) [Optional]

Restart-Service adtagent


Hope this guide will help you somehow automating your ACS deployments 🙂

You can find full scripts here:



Posted on October 18, 2018, in Uncategorized. Bookmark the permalink. Leave a comment.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: