Hi,
I'm trying to convert an old portalpy/excalibur script that 'wipes' an ArcGIS Online organisation based on a role, but I'm struggling to recreate it in Python API. Every week or so my current script seems to fail or present a new error, so I figure now is the time to update it.
The steps the script takes are as follows:
I've been using notebooks so far as it fits my limited knowledge of code and allows me to see where things are going wrong. Trouble is, it's going wrong everywhere!
I can get a list of users, and then find and delete their content, but I can't seem to work out how to delete their folders and any groups that they're a member of. It's possibly a very simple answer, but I figure I may as well ask in case it's also useful for anyone else.
Does anyone have an example script (using the Python API) or any tips to fully deleting users?
Thanks,
Rich
On the off chance that anyone does have need of anything like this, I'm half way there. Tips on making it look pretty rather than my fudged together code below are appreciated.
Edit: Finished the script as much as my patience allows for, I've copied it below (and attached the Python notebook) in case anyone finds it useful.
For further context I work as a trainer for a distributor, and we need to empty our ArcGIS Online training account once a week, so it can be used as fresh the next. This is possibly very niche code...
Connect to Org
# import gis and connect to orgfrom arcgis.gis import GISgis = GIS("https://www.arcgis.com", "<admin_username", "admin_password")Some examples of searching for users:
studentlist = gis.users.search('username:Student_001') # select individualstudentlist = gis.users.search('username:{Student_001 TO Student_020') # select range of studentsstudentlist = gis.users.search('role:0JEz0BZ5jCrbjbwu') # select all students# get accounts# clean up anyone who was invited/set to user, making them a student role againstudentlistreset = gis.users.search('role:org_user')for user in studentlistreset: user.update_role(role = '0JEz0BZ5jCrbjbwu')if len(studentlistreset) > 0: print(str(len(studentlistreset))+" users converted") studentlist = gis.users.search('role:0JEz0BZ5jCrbjbwu') # select all studentstrainerlist = gis.users.search('role:VMWmtlUSUiDq6xQv') # select all trainers print("trainers: "+str(len(trainerlist))+" - students: "+str(len(studentlist)))Process trainers
Caution: please move any demos or content over to the organisation admin user before running the next step - if you wish to keep them!
# delete trainer itemsprint("deleting trainer items...")for user in trainerlist: traineritems = user.items() try: for item in traineritems: print(str(item['owner'])+" - "+str(item['title'])+" - "+str(item['type'])) item.protect(enable = False) item.delete() except: passprint("finished")# delete trainer foldersprint("deleting trainer folders...")for user in trainerlist: trainerfolders = user.folders try: for folder in trainerfolders: print(str(item['owner'])+" - "+str(item['title'])) gis.content.delete_folder(folder['title'],owner=user) except: passprint("finished")# delete trainer groupstrainergroups = gis.groups.search('owner:ea_trainer*')print("deleting trainer groups...")for group in trainergroups: try: print(str(group['owner'])+"\t"+str(group['title'])) group.delete() except: passprint("finished")Process students
# delete student itemsprint("Deleting student items...")for user in studentlist: useritems = user.items() if len(useritems) > 0: try: for item in useritems: print("Deleted "+str(item['owner'])+"\t"+str(item['title'])+" - "+str(item['type'])) item.protect(enable = False) item.delete() except: passprint("finished")# delete student foldersprint("Deleting student folders...")for user in studentlist: userfolders = user.folders for folder in userfolders: print(""+str(folder['title'])) gis.content.delete_folder(folder['title'],owner=user)print("finished")# delete student groupsprint("Deleting student groups...")usergroups = gis.groups.search(query='owner:{Student_000 TO Student_081}')for group in usergroups: print(""+str(group['title'])) group.delete()print("finished")# Return licenses to pool# note that future apps will need to be added to this listtrainerlic = [trainer.get('username') for trainer in gis.users.search('role:VMWmtlUSUiDq6xQv')] # create list of trainers# find users who have pro licensesprint("Finding ArcGIS Pro licenses...")pro_lic = gis.admin.license.get('ArcGIS Pro')pro_users = pro_lic.all()# if the Pro user isn't a trainer, revoke the licenseprint("Returning ArcGIS Pro licenses...")for user in pro_users: user_name = user['username'] if user_name not in trainerlic: try: pro_lic.revoke(username=user_name,entitlements='*') print("removing Pro license: "+user_name) except: pass# Drone2Map print("Finding Drone2Map licenses...")d2m_lic = gis.admin.license.get('Drone2Map for ArcGIS')d2m_users = d2m_lic.all()print("Returning Drone2Map licenses...")for user in d2m_users: user_name = user['username'] if user_name not in trainerlic: try: d2m_lic.revoke(username=user_name,entitlements='*') print("removing Drone2Map license: "+user_name) except: pass# GeoPlannerprint("Finding GeoPlanner licenses...")geo_lic = gis.admin.license.get('GeoPlanner for ArcGIS')geo_users = geo_lic.all()print("Returning GeoPlanner licenses...")for user in geo_users: user_name = user['username'] if user_name not in trainerlic: try: geo_lic.revoke(username=user_name,entitlements='*') print("removing GeoPlanner license: "+user_name) except: pass# AppStudio Standard print("Finding AppStudio licenses...")app_lic = gis.admin.license.get('AppStudio for ArcGIS Standard')app_users = app_lic.all()print("Returning AppStudio licenses...")for user in app_users: user_name = user['username'] if user_name not in trainerlic: try: app_lic.revoke(username=user_name,entitlements='*') print("removing GeoPlanner license: "+user_name) except: pass# Community Analystprint("Finding Community Analyst licenses...")com_lic = gis.admin.license.get('ArcGIS Community Analyst')com_users = com_lic.all()print("Returning Community Analyst licenses...")for user in com_users: user_name = user['username'] if user_name not in trainerlic: try: com_lic.revoke(username=user_name,entitlements='*') print("removing GeoPlanner license: "+user_name) except: pass# Navigatorprint("Finding Navigator licenses...")nav_lic = gis.admin.license.get('Navigator for ArcGIS')nav_users = nav_lic.all()print("Returning Navigator licenses...")for user in nav_users: user_name = user['username'] if user_name not in trainerlic: try: nav_lic.revoke(username=user_name,entitlements='*') print("removing GeoPlanner license: "+user_name) except: pass# Business Analystprint("Finding Business Analyst licenses...")bus_lic = gis.admin.license.get('ArcGIS Business Analyst')bus_users = bus_lic.all()print("Returning Business Analyst licenses...")for user in bus_users: user_name = user['username'] if user_name not in trainerlic: try: bus_lic.revoke(username=user_name,entitlements='*') print("removing GeoPlanner license: "+user_name) except: pass print("finished")# delete students, or disable them otherwisefor user in studentlist: try: # can't delete them if they have a license taken out user.delete() print(str(user['username'])+" deleted") except: user.disable() # if the user can't be deleted, try disabling it. print(str(user['username'])+" disabled")print("finished")Recreate Users
for user in studentlist: try: user_name = user.username print("adding "+str(user['username'])) gis.users.create(username = user_name, password = '<password>', firstname = '<firstname>', lastname = '<lastname>', email = '<email>', description = 'Student account', role = 'org_user', provider = 'arcgis' ) user.update_role(role = '0JEz0BZ5jCrbjbwu') user.update(thumbnail=r'http://www.arcgis.com/sharing/rest//community/users/Esri_Curator_Historical/info/esri_150.jpg') except: passprint("finished")Add users to groups
# Groupsea_groups = gis.groups.search('tags:ea_org') # You can add a tag to any mandatory or desired groupsprint("Target groups:")for group in ea_groups: print(str(group['title']))print("Adding users to groups...")for user in studentlist: user_name = user.username for group in ea_groups: group.add_users([user_name])print("finished")Hopefully, by this stage, nothing has crashed or set on fire, and your organisation is scrubbed and ready!
As an addendum, if anyone fancies adding to this or improving it any way, I'm quite happy to throw the code on Github to make it easier.
Nice job Rich - really handy. I've made a slight variation (mainly simplified) to cater for what we want. Instead of deleting the user, we just change the password. And we disable the user when the course is finished. We also have a role which means students can't create groups so deleting these is not necessary.
DeleteUserContent = True
DeleteUserFolders = True
DisableAccount = True
VerifyRole = True
RoleId = 'WlnpXFdbXk9EktYp'
ChangeUserPassword = True
OldPassword = 'MyOldPassword'
NewPassword = 'MyNewPassword'
PortalUsername = 'MyUsername'
PortalPassword = 'MyPassword'
Users = ['StudentUsernameOne', 'StudentUsernameTwo']
from arcgis.gis import GIS
from IPython.display import display, HTML
gis = GIS('https://www.arcgis.com', PortalUsername, PortalPassword)
for User in Users:
display(HTML('<h1>User: {}</h1>'.format(User)))
UserObject = gis.users.get('{}'.format(User))
#DELETE USER CONTENT ITEMS
if DeleteUserContent == True:
display(HTML('<h3>Deleting User Content Items...</h3>'))
Items = gis.content.search(query='owner:{}'.format(User), max_items=99999)
print('{} Item(s) Returned'.format(len(Items)))
try:
for Item in Items:
print('Deleting Item: {} - {} - {}'.format(str(Item['owner']), str(Item['title']), str(Item['type'])))
display(Item)
Item.protect(enable = False)
Item.delete()
except:
pass
else:
display(HTML('<h3>DeleteUserContent not set to True</h3>'))
#DELETE USER FOLDERS
if DeleteUserFolders == True:
display(HTML('<h3>Deleting User Folders...</h3>'))
Folders = UserObject.folders
print('{} Folder(s) Returned'.format(len(Folders)))
try:
for Folder in Folders:
FolderDeletedResult = gis.content.delete_folder(Folder['title'], owner=User)
print('Folder "{}" Deleted: {}'.format(Folder['title'], FolderDeletedResult))
except:
pass
else:
display(HTML('<h3>DeleteUserFolders not set to True</h3>'))
#DISABLE ACCOUNT
if DisableAccount == True:
display(HTML('<h3>Account being disabled</h3>'))
DisableAccountResult = UserObject.disable()
print('Account Disabled: {}'.format(DisableAccountResult))
else:
display(HTML('<h3>DisableAccount not set to True - Ensuring account is not disabled</h3>'))
DisableAccountResult = UserObject.enable()
print('Account Enabled: {}'.format(DisableAccountResult))
#VERIFY ROLE
if VerifyRole == True:
display(HTML('<h3>Role being Verified</h3>'))
UpdateRoleResult = UserObject.update_role(role = RoleId)
print('Specified Role Applied: {}'.format(UpdateRoleResult))
else:
display(HTML('<h3>VerifyRole not set to True</h3>'))
#CHANGE PASSWORD
if ChangeUserPassword == True:
display(HTML('<h3>Password being changed</h3>'))
ChangeUserPasswordResult = UserObject.reset(OldPassword, new_password = NewPassword)
print('Password Changed: {}'.format(ChangeUserPasswordResult))
else:
display(HTML('<h3>ChangeUserPassword not set to True</h3>'))