Export/Import Local Group Membership

Synchronize Groups

At my job, we use local groups extensively for permissions to databases and websites. We have a script that sync's the groups with a master server and when we need to add someone, we just add them in one place.

Below is syncgroups.pl which we run on a windows 2003 server:

use strict;

use Win32::NetAdmin;

my @servers = ('server1','server2','server3');

my @groups = ('group1','group2','group3');

for (my $i=0; $i<scalar(@servers); $i++) {
	my $server = @servers[$i];
	print "SERVER = $server\n";
	for (my $j=0; $j<scalar(@groups); $j++) {
		my $group = $groups[$j];
		print "GROUP = $groups[$j]\n";
		my @localusers = ();
		my @remoteusers = ();
		Win32::NetAdmin::LocalGroupGetMembers("localhost","$group",\@localusers) or die ("GroupGetMembers failed for localhost: $^E");
		Win32::NetAdmin::LocalGroupGetMembers("$server.ringofsaturn.com","$group",\@remoteusers) or
			Win32::NetAdmin::LocalGroupCreate("$server.ringofsaturn.com","$group","");
 
		sort(@localusers);
		sort(@remoteusers);

		@localusers = map { uc($_) } @localusers;
		@remoteusers = map { uc($_) } @remoteusers;
		print "Adding users to $group on $server if needed.\n";
		for my $user (@localusers) {
			if (! grep {$user eq $_} @remoteusers) {

				Win32::NetAdmin::LocalGroupAddUsers("$server.ringofsaturn.com","$group","$user");

				print "\tAdding $user\n";
			}
		}

		print "Deleting users in $group on $server if needed.\n";

		for my $user (@remoteusers) {
			if (! grep {$user eq $_} @localusers) {
				Win32::NetAdmin::LocalGroupDeleteUsers("$server.ringofsaturn.com","$group","$user");
				print "\tDeleting $user\n";
			}
		}
	}
}

Backup and Restore Groups

We also do backups of our groups in case we have to restore them for any reason. For example, many of our groups are updated dynamically based on HR data. If we get bad HR data, then the groups could get truncated, and we can simply restore the groups from a backup.

Below is a script to backup your groups:

@echo off
if {%1}=={} @echo Syntax XLCLGRP FileName
setlocal ENABLEDELAYEDEXPANSION
set file=%1
if exist %file% del /q %file%
set wrk1="%TEMP%\XLCLGRP_%RANDOM%.TMP%"
set wrk2="%TEMP%\XLCLGRP_%RANDOM%.TMP%"
if exist %wrk1% del /q %wrk1%
if exist %wrk2% del /q %wrk2%
set fnd0=FIND "*"
set fnd1=FIND /V "The command completed successfully."
set fnd2=FIND "\"
set fnd3=FIND /V "NT AUTHORITY\"
for /f "Tokens=*" %%g in ('net localgroup^|%fnd0%^|%fnd1%') do
(
	set work=%%g
	set group=!work:~1!
	@echo 1 "!group!">>%wrk1%
	for /f "Tokens=*" %%m in ('net localgroup "!group!"^|%fnd1%^|%fnd2%^|%fnd3%') do
	(
		@echo 2 "!group!" "%%m">>%wrk1%
	)
)
sort %wrk1% /O %wrk2%
del /q %wrk1%
for /f "Tokens=1*" %%a in ('type %wrk2%') do
(
	@echo NET LOCALGROUP %%b /ADD>>%file%
)
del /q %wrk2%
endlocal 

And below is a batch script which can be used to restore the groups:

@echo off
if {%1}{} @echo Syntax ILCLGRP FileName&goto :EOF
if not exist %1 @echo ILCLGRP %1 - NOT found.&goto :EOF
setlocal
set file=%1
set wrk="%TEMP%\ILCLGRP_%RANDOM%.TMP%"
set fnd=FINDSTR /I /V /L /G:%wrk%
call XLCLGRP %wrk%
for /f "Tokens=*" %%a in ('type %file%^|%fnd%') do
(
	%%a
)
del /q %wrk%
endlocal