An issue with Google Apps Directory Sync and how to fix it

An issue with Google Apps Directory Sync and how to fix it


As you know, Google Apps Directory Sync is a great tool to synchronize your MS Active Directory accounts with your Google Apps (for Business or Education). It can help you map your user account structure into Google including the users, groups, OUs... You simply set up the proper search rules for users and groups of your AD architecture. The tool works great except for one thing:

When you add a new user into a group in AD, it will add that user into the counter part of that group in Google. But, when you move that user out of the group in AD, the google account will not be removed from the google groups. What google only does is stop allowing the user to post to that group.

After looking for the solution for a while, I came up with one hack that works:

1. Search for all users in AD groups which you want to sync to Google:

http://www.dangtrinh.com/2016/07/get-all-ms-active-directory-group.html

2. Search for all users in Google groups:

http://www.dangtrinh.com/2016/07/get-google-group-members-using-gam-and.html

3. Compare two lists and delete Google Group members that does not appears in ADs counter part.

Here is a working script:

#! /usr/bin/env python
import shlex, subprocess
import sys
# ad_utils.py: http://www.dangtrinh.com/2016/07/get-all-ms-active-directory-group.html
import ad_utils
GADMIN_ACCOUNT = '<your google apps administrator email>'
GAM_PATH = '/path/to/your/gam.py'
GOOGLE_GROUPS = {
'<group name>': 'group email',
...
}
def get_group_members(group_email, gam_path=GAM_PATH):
cmd = 'python %s print group-members group %s' % (gam_path, group_email)
if sys.platform == 'win32':
cmd = 'gam print group-members group %s' % (group_email)
args = shlex.split(cmd)
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
members = []
if proc.returncode == 0:
if out:
out = out.split('\n')
for i in range(1, len(out)):
row = out[i].split(',')
if len(row) >= 3:
if row[2].lower() != GADMIN_ACCOUNT: # exclude gadmin account
members.append(row[2].lower())
return members
def del_group_member(group_email, member_email, gam_path=GAM_PATH):
cmd = 'python %s update group %s remove user %s' % (gam_path, group_email, member_email)
if sys.platform == 'win32':
cmd = 'gam update group %s remove user %s' % (group_email, member_email)
args = shlex.split(cmd)
proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
return proc.returncode, out, err
def sync_ad_gapps_group_members(group_name, group_email, ad_conn, dry_run=False):
ad_members = ad_utils.get_group_members(group_name, ad_conn)
if ad_members:
googlegroup_members = get_group_members(group_email)
for guser in googlegroup_members:
if guser not in ad_members:
print "=== %s not active in AD" % guser
if dry_run:
pass
else:
del_group_member(group_email, guser)
def sync_ad_gapps_groups(dry_run=False):
ad_conn, ad_result = ad_utils.ad_auth()
if ad_result:
for gname, gemail in GOOGLE_GROUPS.iteritems():
print "\n+++ Syncing group %s" % gname
sync_ad_gapps_group_members(gname, gemail, ad_conn, dry_run)
else:
print "Fail!"
if __name__ == "__main__":
dry_run = False
if len(sys.argv) > 1:
dry_run = bool(sys.argv[1])
if dry_run:
print "=== Running Google Apps Groups sync in dry-run mode"
print "==== Dry running: %s" % dry_run
sync_ad_gapps_groups(dry_run)


Usage:

$ python google_groups_ad_sync.py [dry_run]

You can set up a scheduled task that runs this script after GADS.
download
alternative link download