As a workaround, this will add users from multiple groups to a PTL group. Run nightly as a scheduled task.
import subprocess
import os, sys, string, calendar, datetime, traceback, smtplib
import csv
from os import listdir
from os.path import isfile, join
from arcgis.gis import GIS
import itertools
from collections import Counter
import arcpy
from arcpy import env
# Use this script when you need to add members of multiple AD groups to one or more PTL groups
# All scripts and files should read/write to the same directory
##########################
#Begin variables
ptl ="https://portal.com/portal"
#Coded to work with headless account
# Additional parameters will need to be defined to use enterprise account or token
user = "bigfoot"
passw = "sasquatch!"
workdir = 'C:\PRODUCTION\PTL_GROUPS\IANDM'
# List of PTL Groups that will include members of the multiple AD groups lists in adgroups.txt
ptllist = ['GRSM IandM Map Editors','GRSM IandM Workspace','GRSM Vital Signs Editors','GRSM Vital Signs Workspace','GRSM Wetlands Editors','GRSM Wetlands Workspace','GRSM Sochan Workspace']
# a text file titled "adgroups.txt" containing the name of multiple AD groups (one per line, no delimiters or
# seperators) is required to be in the workdir
# Output file containing UPN of AD members from the groups listed in adgroups.txt
admembers = 'GRSM_IANDM_USERS.csv'
# Define log setting
try:
d = datetime.datetime.now()
log = open("C:\PYTHON_LOGS\\iandmLOG."+admembers+".txt","a")
log.write("----------------------------" + "\n")
log.write("----------------------------" + "\n")
log.write("Log: " + str(d) + "\n")
log.write("\n")
# Start process...
starttime = datetime.datetime.now()
log.write("Begin process:\n")
log.write(" Process started at " + str(starttime) + "\n")
log.write("\n")
### Start setting variables
# Mail Server Settings
SERVER = "mail.server"
PORT = "25"
FROM = "me"
MAILDOMAIN = '@portal.com'
# Data Steward getting the email. Needs to be their email address...without @nps.gov at the end
userList=["the_man"]
# get a list of usernames from the list of named tuples returned from ListUsers
userNames = [u for u in userList]
# take the userNames list and make email addresses by appending the appropriate suffix.
emailList = [name + MAILDOMAIN for name in userNames]
TO = emailList
# Grab date for the email
DATE = d
#End variables
##########################
try:
os.remove(admembers)# Remove AD names list if it exists
except OSError:
pass
#PS command to get members of ad group(s)
command = '$groups = Get-Content '+workdir+'\\adgroups.txt ;foreach($Group in $Groups) {Get-ADGroupMember -Id $Group | \
Where { $_.objectClass -eq "user" }|%{Get-ADUser $_.SamAccountName | select UserPrincipalName} | Export-CSV '+workdir+'\\'+admembers+' \
-NoTypeInformation -append}'
process=subprocess.Popen(['powershell',command],stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE)
out, err = process.communicate()
print(process.returncode, out, err)
#Remove any special charactes, including quotes, from AD names list
input_file = workdir+'\\'+admembers
chars = '$%^*"_\n' # etc notice the \n (linefeed)
with open(input_file) as f:
lines = [x.strip(chars) for x in f]
with open(input_file,"w") as f:
f.writelines("{}\n".format(x) for x in lines)
#Initialize GIS connection to PTL
gis = GIS(ptl, user, passw)
#Loop through all PTL groups and do the following:
for item in ptllist:
#Get PTL group name
group = gis.groups.search('title: "'+item+'"', '')
print(group)
#Add AD users to PTL group
readCSV = list(csv.reader(open(workdir+'\\'+admembers)))
for row in readCSV:
group[0].add_users(row)
else:
print ('done')
#Get list of all members in PTL group
members = group[0].get_members()
members_list = members['users']
#Get list of authorized members in PTL group
allowed_list = list(itertools.chain(*readCSV))
#Figure out who doesn't belong
c1 = Counter(allowed_list)
c2 = Counter(members_list)
diff = list((c2 - c1).elements())
#Remove unauthorized group members
for j in diff:
group[0].remove_users([str(j)])
# Write nothing to log if success.
endtime = datetime.datetime.now()
log.write(" Completed successfully in "
+ str(endtime - starttime) + "\n")
log.write("\n")
log.close()
######################################################################
#Delete below if not want email on success
#Define email message if success
## SUBJECT = "Notification of Successful Update of "+str(ptllist)
## MSG = "Finished updating:"+str(ptllist)+" at "+ str(DATE)
## print (MSG)
## print (emailList)
##
## # Send an email notifying steward of successful archive
## #MESSAGE = "\ From: %s To: %s Subject: %s %s" % (FROM, ", ".join(TO), SUBJECT, MSG)
## MESSAGE = "Subject: %s\n\n%s" % (SUBJECT, MSG)
## try:
## try:
## print("Connecting to Server...")
## server = smtplib.SMTP(SERVER,PORT)
## try:
## print("Login...")
## try:
## print("Sending mail...")
## server.sendmail(FROM, TO, MESSAGE)
## except Exception as e:
## print("Send Error Mail\n" + e.message)
## except Exception as e:
## print("Error Authentication Server: check the credentials \n" + e.message)
## except Exception as e:
## print("Error Connecting to Server : check the URL of the server and communications port ( 25 and ' the default ) \n" + e.message)
##
## print("Quit.")
## server.quit()
##
## except Exception as e:
## print (e.message)
#Delete above if not want email on success
######################################################################
# Something with wrong
except:
# Get the traceback object
tb = sys.exc_info()[2]
tbinfo = traceback.format_tb(tb)[0]
# Concatenate information together concerning
# the error into a message string
pymsg = "PYTHON ERRORS:\nTraceback info:\n" + tbinfo + "\nError Info:\n" + str(sys.exc_info()[1])
msgs = "ArcPy ERRORS:\n" + arcpy.GetMessages(2) + "\n"
# Return python error messages for use in
# script tool or Python Window
arcpy.AddError(pymsg)
arcpy.AddError(msgs)
# Print Python error messages for use in
# Python / Python Window
log.write("" + pymsg + "\n")
log.write("" + msgs + "")
log.close()
# Define email message if something went wrong
SUBJECT = "Notification of Un-Successful Update of "+str(ptllist)
MSG = "This horrible thing happend:"+ str(DATE)+ "; " +pymsg + "; " + msgs
print (MSG)
print (emailList)
# Send an email notifying steward of successful archive
#MESSAGE = "\ From: %s To: %s Subject: %s %s" % (FROM, ", ".join(TO), SUBJECT, MSG)
MESSAGE = "Subject: %s\n\n%s" % (SUBJECT, MSG)
try:
try:
print("Connecting to Server...")
server = smtplib.SMTP(SERVER,PORT)
try:
print("Login...")
try:
print("Sending mail...")
server.sendmail(FROM, TO, MESSAGE)
except Exception as e:
print("Send Error Mail\n" + e.message)
except Exception as e:
print("Error Authentication Server: check the credentials \n" + e.message)
except Exception as e:
print("Error Connecting to Server : check the URL of the server and communications port ( 25 and ' the default ) \n" + e.message)
print("Quit.")
server.quit()
except Exception as e:
print (e.message)
This functionality is currently present in the software.
@jill_es thanks, what version was it added at?
@Anonymous User, there's been support for nested enterprise groups for many releases now. It's present in all supported versions of Enterprise (10.7+). Our product documentation goes into more detail regarding this: https://enterprise.arcgis.com/en/portal/10.7/administer/windows/create-groups.htm#ESRI_SECTION1_5E3FFFAA1B7E443FBB1E483E070B1979. Is this what you were referring to or were you wanting to use separate AD groups to create one group in your Enterprise organization?
No, this should allow multiple Non-Nested AD groups be added to portal groups
We have the same use case as @BillFox, it needs to allow for multiple non-nested AD groups.
We commonly have projects which span multiple parts of the business e.g. environment, engineering and property teams which all need access. They each have an AD group which we would like to be able to add to a Portal group, rather than having to add every user individually. If a user drops out of an AD group or a new user is added to an AD group the Portal group should reflect this and be updated.
There are similar ideas requesting the same functionality:
Groups from multipe active directory groups
Invite extra users to active directory group based groups
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.