Let's start with a scenario.

You have user workstations (Windows) that need to have licensed software deployed and you want to leverage Salt Open to manage who receives the software. The problem is that natively Salt doesn't talk to Active Directory and Salt is minion (machine) centric. If possible, I recommend targeting machine groups but this method will work for user groups too.

As often is the case in our field, there are a number of different ways you can go about to achieve this. This option will use a couple of lines of PowerShell (executed from a cmd.script run) to be stored a Jinja variable which will then be placed into a our Salt grain.


To begin, we will create a PowerShell script with the commands required to grab the Active Directory group information. Remember, this script is executed on the minion side, this means we are restricted from using any cmdlets that might exist on the DCs server side.

The following code example is fairly convoluted but in our environment, it made the most sense. You may subsitute this with any option that works for you to obtain the user and group information. For example, to get the username, something simple like: $(Get-WMIObject -class Win32ComputerSystem | select username).username may work for you.

$CurrentUser = (tasklist /v /FI "IMAGENAME eq explorer.exe" /FO list | find "User Name:").Substring(18) | Select-Object -First 1
([ADSISEARCHER]"samaccountname=$($CurrentUser)").Findone().Properties.memberof -replace '^CN=([^,]+).+$','$1' | Sort-Object | ConvertTo-Json

Next, create a state file in the Salt environment in which you want to have AD group information about the minions or the users of those minions. In this example, we will be putting in the default file roots base environment.

vim /srv/salt/ADGroups.sls

In this file, you'll insert something like the following.

{% set adgroups = salt['cmd.script']('salt://GetUserADGroups.ps1', shell='powershell') %}
ADGroups:
  grains.present:
    - name: adgroups
    - value: {{ adgroups.stdout | load_json }}
    - force: true

Let's walk through what we're doing here.

  1. We're telling Jinja to set a variable equal to the output of the following Salt command. The Salt command is running an execution module (cmd.script) for a PowerShell script sitting in the base Salt environment.
  2. We're using the grains.present state module to create a grain called adgroups with the value of the standard output of the earlier Jinja variable and format it as JSON.
  3. We're setting the force flag to true to ensure that the AD groups are overwritten each time it runs.

Now, you can place this into your top.sls file for the required environment to ensure it is executed on every highstate run.

When this has executed on your minion, you will now have your Active Directory groups for the user stored as a grain for each minion.

To confirm, you can test by running:

salt Insert-Minion-ID-Here grains.get adgroups

You can target based on this grain in your top.sls file now too. Here is a very simple example:

base:
  'adgroups:GroupName':
    - StateToApply

Alternatively, you could take a different approach for this information. You could create a custom Python module for Salt, try your hand at the external LDAP pillar or any number of other options.

If you have any questions, please feel free to comment or reach out to me and don't forget to share if you found this helpful!