ArcGIS Portal Active Directory Groups Questions

4596
7
Jump to solution
02-01-2018 11:53 AM
BillHarvey1
New Contributor III

I have ArcGIS Portal setup to use Active Directory for authentication. I can add remove users fine and everything is working great.

1) I added users to an AD group. I can add the group to the Portal and ALL the users show up. E.g. Add one group with 5 users and every individual user in the group shows up. I want to remove all of the people in the group but cannot figure out how to do it. I want to remove the group and have all corresponding users go away as well, or change the permissions on the AD group I have added.

2) I have added the AD group to Portal. I would like it so when a user is added to the AD group they have access without having to do anything in Portal. This seems like it should be default behavior, but based on the previous question adding a user to the AD group does not seem to automatically grant them access to the Portal. How would this work.

Thank you.

0 Kudos
1 Solution

Accepted Solutions
ThomasColson
MVP Frequent Contributor

A bit over complicated...requires Pro Py (3.5.3)

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"
#Coded to work with headless account
# Additional parameters will need to be defined to use enterprise account or token
user = "user"
passw = "pw"
workdir = 'C:\PRODUCTION\PTL_GROUPS\FIRE'
# List of PTL Groups that will include members of the multiple AD groups lists in adgroups.txt
ptllist = ['Fire Editors']
# 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 = 'FIRE_USERS.csv'
# Define log setting
try:
 d = datetime.datetime.now()
 log = open("C:\PYTHON_LOGS\hotLOG."+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 = "server"
 PORT = "25"
 FROM = "from"
 MAILDOMAIN = '@domain'
 # Data Steward getting the email. Needs to be their email address...without @nps.gov at the end
 userList=["sasquatch"]
 # 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)



View solution in original post

7 Replies
RandallWilliams
Esri Regular Contributor

Removing users in bulk can be achieved with the DeleteUsers tool.

Manage members—Portal for ArcGIS (10.6) | ArcGIS Enterprise 

If you'd like, you can enable the AutoAccountCreation option via the admin API.

Automatic registration of enterprise accounts—Portal for ArcGIS (10.5.x) | ArcGIS Enterprise 

Please note the risks of doing so - you may end up with your named user licenses being inadvertently consumed by members that you didn't intend to have licensed with your ArcGIS Enterprise instance.

BillHarvey1
New Contributor III

Hi Randall.  Thank you for your response.  That is good stuff and gets me part of the way there.   I don't think the automatic registration will work for us.   If for nothing else we have a mobile product pulling named licenses and we also don't want to have users access the Portal without some control.   The listing of users and deletion is good stuff, though.

Is there no way to have a user show up, or deleted, in Portal after the AD group has been modified?

1)  Active Directory group is created.  All those users show up in Portal.

2)  User is added to the Active Directory group.   Can we have that user then show up in Portal automatically?   Same thing with a delete.  If a user is deleted from the AD group can it be setup to automatically remove their access without having to do anything on the Portal side?

Would it be a matter of removing all of the users in that AD group within Portal, with the command line tool, and then re-adding the group?

Thank you.

Bill

0 Kudos
ThomasColson
MVP Frequent Contributor

I've had the same problem....and solve it with a python scheduled tasks that compares membership in AD to group membership and does the appropriate add/delete. 

0 Kudos
BillHarvey1
New Contributor III

Ugh.   I was just looking at something similar and doing it in C#.   Was hoping that wasn't the case, but looks like I will be heading that way.  Thank you Thomas, I will mark this as correct after I get some more feedback.   I am not seeing any other way around it either.

0 Kudos
ThomasColson
MVP Frequent Contributor

A bit over complicated...requires Pro Py (3.5.3)

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"
#Coded to work with headless account
# Additional parameters will need to be defined to use enterprise account or token
user = "user"
passw = "pw"
workdir = 'C:\PRODUCTION\PTL_GROUPS\FIRE'
# List of PTL Groups that will include members of the multiple AD groups lists in adgroups.txt
ptllist = ['Fire Editors']
# 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 = 'FIRE_USERS.csv'
# Define log setting
try:
 d = datetime.datetime.now()
 log = open("C:\PYTHON_LOGS\hotLOG."+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 = "server"
 PORT = "25"
 FROM = "from"
 MAILDOMAIN = '@domain'
 # Data Steward getting the email. Needs to be their email address...without @nps.gov at the end
 userList=["sasquatch"]
 # 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)



BillHarvey1
New Contributor III

Thank you!    That is great.  Very much appreciated.

0 Kudos
WillemJenniskens1
New Contributor II

Thanks! A non-oneliner would have been appreciated even more ;)

0 Kudos