Administrate Windows local user groups in Puppet
Windows local user groups in Puppet
I recently had a challenge where I needed to add an item to an existing array in Puppet, after some searching on internet I didn’t find a proper native solution to add it. On some Stackoverflow post I saw a mention to join/split the array and create it this way. The example wasn’t that clear so I try to make it a bit more readable.
In the end a very simple solution but it took me a few tries to get it right.
Use case:
I want to manage the Windows local user groups with Puppet, currently for example the “administrators” group has a few local user accounts (LocUserX) and a few domain group accounts (DomGroupX). This is a specific set of users that doesn’t change and is our base.
For each server we want to add a specific variable domain user group (DomGroupServer1).
Plan:
To manage groups in Puppet we can use the Group resource type. Let’s have a look how the group resource is handled now.
Let’s start on a Windows server where Puppet is installed, open a command prompt and use “puppet resource group” to list all current groups and settings.
PS C:\WINDOWS\system32> puppet resource group group { 'Administrators': ensure => 'present', gid => 'S2342315-1235', members => ['administrator', 'Domain Admins', 'LocUser1', 'DomGroup1', 'DomGroup2', 'DomGroup3'], }
That’s the information we need.
Now we now how the information is interpreted and displayed. Use the Group to see if anything extra is needed for your environment
Building:
Setting the backend
In our environment we use Hiera as backend, so this is where we store the ‘static’ data. So first I create some entries in the yaml file to use in the new Puppet profile.
local_groups: - administrators: name: 'Administrators' ensure: 'present' members: ['administrator', 'Domain Admins', 'LocUser1', 'DomGroup1', 'DomGroup2', 'DomGroup3'] auth_membership: true
As you may notice I also added the last line “auth_membership” this option will enforce the group settings as described. So accounts not mentioned to be in the group will be removed. If you leave it off only users are added, but nothing is done with any existing users in the group.
Create the profile
Because Puppet runs on Linux and Windows I started with a case to simply only apply this to windows machines, else give a warning message.
I added some comments to make it clearer what happens where. By using a for each loop, we can simply add more groups in our Hiera backend and the profile will loop through it.
class profile::windows::local_groups{ case $::operatingsystem { #Case switch to only apply on Windows 'windows': { $local_groups = hiera('local_groups',undef) #Get local groups from Hiera $local_groups.each|$local_group|{ #For each group in local_groups do apply group group { $local_group['name']: #make use of the group resource type ensure => $local_group['ensure'], #use the proper value from Hiera members => $local_group['members'], #use the proper value from Hiera auth_membership => $local_group['auth_membership'], #use the proper value from Hiera } } } default: { #If operatingsystem is not windows give an error and do nothing warning("This operating system is NOT supported by ${module_name}") } }
So this this is the basic start, now I want to add an item to the $local_group[‘name’].
As mentioned before this can be done by a join/split construction. First I start to put all the members in a seperate variable:
$members = $local_group['members'] #now contains : ['administrator', 'Domain Admins', 'LocUser1', 'DomGroup1', 'DomGroup2', 'DomGroup3'] #So let's create a string from this array, in a new variable $local_admin_group = join($members,',') #this will create a string from $members with a comma as separator. I used space at the start, but this will cut domain admins also in half. So I switched to comma. # Now let's add the new variable to the string $new_local_admin_group = "${local_admin_group},DomGroupServer1" #This will create a string containing: administrator,Domain Admins,LocUser1, DomGroup1, DomGroup2,DomGroup3,DomGroupServer1 #Now we need to rebuild the array for further processing $final_local_admin_group = split($new_local_admin_group,',') #This will create the new array ['administrator', 'Domain Admins', 'LocUser1', 'DomGroup1', 'DomGroup2', 'DomGroup3','DomGroupServer1<strong>'</strong>] #Now apply this to our group reference group { $local_group['name']: ensure => $local_group['ensure'], members => $final_local_admin_group, auth_membership => $local_group['auth_membership'], }
Now we put all things together:
### Class: profile::windows::local_groups # # == Description : # This profile manages the local groups of a Windows system # # === Supported Operating Systems # * Windows 2012 R2 class profile::windows::local_groups{ case $::operatingsystem { 'windows': { #Get local group from Hiera $local_groups = hiera('local_groups',undef) #Loop trough all groups and if the group is administrators, and additional #adminstator group for environments is added $local_groups.each|$local_group|{ if $local_group['name'] == 'administrators'{ $members = $local_group['members'] #Create a new string splitted by comma(beacuse domain admins has a # space in the name) $local_admin_group = join($members,',') #Add the environment group to the string $new_local_admin_group = "${local_admin_group},DomGroupServer1" #Recreate an array from the new_local_admin_group string $final_local_admin_group = split($new_local_admin_group,',') group { $local_group['name']: ensure => $local_group['ensure'], members => $final_local_admin_group, auth_membership => $local_group['auth_membership'], } } else { #If the group doesn't match the administrators group the standard #groups are applied. group { $local_group['name']: ensure => $local_group['ensure'], members => $local_group['members'], auth_membership => $local_group['auth_membership'], } } } } default: { warning("This operating system is NOT supported by ${module_name}") } } }
Summary for adding item to array
$members = ['administrator', 'Domain Admins', 'LocUser1', 'DomGroup1'] $local_admin_group = join($members,',') $new_local_admin_group = "${local_admin_group},DomGroupServer1" $final_local_admin_group = split($new_local_admin_group,',')
Hope this can help with someones issue, took me a few hits before I got it working properly. Could be my experience at the moment, but hey you gotta learn sometime 🙂 Probably other people are learning too..