There is no option in JIRA to do that, but there are plugins out there that can. User Deactivator for JIRA is one, or you could use the REST API and create your own plugin/script for it.
Hi Mikael
It would be great if you can provide the link for REST API.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You can find the documentation for all the REST APIs here, https://developer.atlassian.com/docs/?_ga=2.158361978.1985121612.1520266316-819614289.1519148677
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hello @nudo
JIRA does not provide any provision to delete or deactivate users in Bulk. However, you can use the miniOrange Bulk User management plugin for JIRA. Along with bulk delete & deactivate operations, It allows you to automatically deactivate never logged-in users or users without any activity for a certain amount of time. Apart from this, you can even import or export users.
Feel free to reach out at atlassiansupport@xecurify.com in case of any further queries.
PS: I work for miniOrange, one of the top Atlassian SSO Vendors!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
In case it helps other searchers, I wrote the following script (as an amalgamation of other people's scripts) to handle this very quickly in the Scriptrunner console.
The goal was for this to be very reproducible, so hopefully it helps out. The example below is used to delete all users of a certain domain, but you could tweak it to use other search parameters.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.user.ApplicationUser
def userSearchService = ComponentAccessor.getComponent(UserSearchService.class);
// The search will be case sensitive, so you may need to do multiple runs. (@abc.com, @ABC.com, etc)
def domainToDelete = "@spam.email"
// The deletion process does not scale well, so play with the number to delete and see what works best. 50-100 has worked well thus far.
// You can test more safely by trying out 1 or 2 users as you confirm your rules.
Integer deletionBatchSize = 50
UserSearchParams userSearchParams = (new UserSearchParams.Builder()).allowEmptyQuery(true).includeActive(true).includeInactive(true).maxResults(deletionBatchSize).build();
def userService = ComponentAccessor.getComponent(UserService)
def asUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
userSearchService.findUsers(domainToDelete, userSearchParams).each{
String jiraUserName = it.getName();
// Confirm 100% that the user we are deleting is actually in the domain to delete by confirming that their
// jira username ends with the domain
// The search params can sometimes find matches based on domainToDelete if portions of the string exist in the userName without this protection
if (jiraUserName.endsWith(domainToDelete)){
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(asUser, it)
log.error "REMOVAL TEST - $it matched domain"
if (result.isValid()) {
// If you would like to test the script without actually deleting the users found, comment the line below out when you run it.
userService.removeUser(asUser, result)
log.error "REMOVAL SUCCESSFUL - $it"
}
else {
log.error "REMOVAL FAILED - $it " + result.getErrorCollection().errorMessages
}
}
else {
log.error "REMOVAL SKIPPED - " + jiraUserName + " did not match domain: " + domainToDelete + " for removal";
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Patrick, do you think there would be any way to use this script to delete users based on a JQL statement? If so, can you please help! I getting very frustrated deleting/disabling users via the GUI. Thanks in advance!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Parker,
I never found a way to do it with JQL, just the Script Runner add-on.
After I posted the answer on this thread, I apparently wrote a Script Listener to block spam accounts (Service Desk portal sign-up) from getting created at all. Here you go in case it helps. Originally answered in this post.
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.crowd.model.user.User
import com.atlassian.crowd.event.user.UserCreatedEvent
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.UserService
// Catch the UserCreatedEvent and get the User
def newUserEvent = event as UserCreatedEvent;
User newUser = newUserEvent.getUser();
String email = newUser.getEmailAddress();
// Define the domain you want to block
String spamDomain = "@spam.xyz";
if (email.toUpperCase().endsWith(spamDomain.toUpperCase())){
log.error "SPAMBOT DETECTED! " + email;
def userService = ComponentAccessor.getComponent(UserService)
def userManager = ComponentAccessor.getUserManager();
// Set the user account we want to run delete permissions with
ApplicationUser runAsUser = userManager.getUserByKey("yourJiraAdminAccount")
// validate permissions
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(runAsUser, email)
if (result.isValid()) {
log.error "SPAMBOT REMOVAL VALID - $email"
userService.removeUser(runAsUser, result)
log.error "SPAMBOT REMOVAL SUCCESSFUL - $email"
}
else
{
log.error "REMOVAL INVALID - $email"
}
}
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.crowd.model.user.User
import com.atlassian.crowd.event.user.UserCreatedEvent
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.UserService
// Catch the UserCreatedEvent and get the User
def newUserEvent = event as UserCreatedEvent;
User newUser = newUserEvent.getUser();
String email = newUser.getEmailAddress();
// Define the domain you want to allow
String allowedDomain = "@safeDomain.com";
if (!email.toUpperCase().endsWith(allowedDomain.toUpperCase())) {
log.error "EXTERNAL ATTEMPT DETECTED! " + email;
def userService = ComponentAccessor.getComponent(UserService)
def userManager = ComponentAccessor.getUserManager();
// Set the user account we want to run delete permissions with
ApplicationUser runAsUser = userManager.getUserByKey("yourJiraAdminAccount")
// validate permissions
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(runAsUser, email)
if (result.isValid()) {
log.error "EXTERNAL ATTEMPT REMOVAL VALID - $email"
userService.removeUser(runAsUser, result)
log.error "EXTERNAL ATTEMPT REMOVAL SUCCESSFUL - $email"
}
else
{
log.error "EXTERNAL ATTEMPT REMOVAL INVALID - $email"
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Patrick, would there be a way to manually add users to delete?
Where you say
def domainToDelete = "@spam.email"
instead I want to delete the account parker@atlassian.xyz. How does the script change in order me to be able to put individuals that need to be deleted?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Are you thinking of doing something like pasting in a list of email addresses for the accounts you want to delete?
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Parker Van Dyk - If they are inactive users, you might be best served by this script, which you can set up to auto-delete users that are inactive for X days.
Otherwise, something like the following will do it. If you've found this helpful, feel free to thumb my original response up so that others are more likely to see it.
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.bc.user.UserService
import com.atlassian.jira.user.ApplicationUser
def userService = ComponentAccessor.getComponent(UserService)
def userSearchService = ComponentAccessor.getComponent(UserSearchService)
def asUser = ComponentAccessor.jiraAuthenticationContext.loggedInUser
def addressesToDelete = ["emailABC@faker.com","GetRidOfMe@email.com","etc@etc.com"]
for (def i = 0; i < addressesToDelete.size(); i++) {
def user = userSearchService.findUsersByEmail(addressesToDelete[i])
if (user){
ApplicationUser thisUser = user[0]
log.error "The username is: " + thisUser.getName()
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(asUser, thisUser)
if (result.isValid()) {
// Uncomment the line ncommentbelow to actually delete the account. It is commented for testing.
//userService.removeUser(asUser, result)
log.error "REMOVAL SUCCESSFUL - $thisUser"
}
else {
log.error "REMOVAL FAILED - $thisUser " + result.getErrorCollection().errorMessages
}
}
else
{
log.error "No user account found for: "+ addressesToDelete[i]
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Patrick SI am actually wanting to paste a list of email addresses of users that I want to strip out of all groups/licensing and deactivate. Since we are using cloud, deleting the users would have hurt is more than help. Any suggestions?
Thanks in advance!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Parker Van Dyk - Gotcha. That starts to get too far outside the original scope of this question. The logic of utilizing the list, looping, logging, etc in the last comment would all still be valid, but instead of doing a delete trial and the .removeUser you would want some logic that deactivated the user. I haven't done that myself before, but I'm sure there's a function to do it that you could substitute into the script.
If you don't see an existing forum post or document that has a code snip of disabling a user account, pop it in as a new question on the community.
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(asUser, thisUser)
if (result.isValid()) {
// Uncomment the line ncommentbelow to actually delete the account. It is commented for testing.
//userService.removeUser(asUser, result)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
No problem @Parker Van Dyk.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
@Manikanta Maram - Sorry for the slow reply! This was written for JIRA Server.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
This came up for me again when we decided we no longer wanted to manually maintain our list of blocked domains. The updated Script Listener below reaches out to several github repositories of blacklisted domains and free email services. These are all pretty well maintained already, so this pulls their contents in for the script when validating accounts.
If anyone finds this useful, be sure to look at the email lists its pulling from to make sure they don't contain domains you actually want to allow. For example the free email provider URL includes things like gmail.com, which some organizations may want to allow. If you hit a situation like that, you might want to have your own whitelist as well and check for when looping through domains.
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.crowd.model.user.User
import com.atlassian.crowd.event.user.UserCreatedEvent
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.UserService
// Catch the UserCreatedEvent and get the User
def newUserEvent = event as UserCreatedEvent;
User newUser = newUserEvent.getUser();
String email = newUser.getEmailAddress();
String fullName = newUser.getDisplayName()
// Initialize the spam domain list with some manual entries that may not be in the git repositories.
def spamDomains = [".ru", ".whateverElseYouWantToManuallyBlock"]
def urlToSearchForDomains // This will be the URL for each repository we search for domains to block.
def domainSearchResults // the resulting list of domains found at the URL.
// I know, this should be a function where we pass the URL instead of repeating the same try / catch multiple times. I don't have time to sort all that syntax out after testing it and getting it working, but feel free to tweak.
// Try / catch the domain lookup in case we hit a temporary DNS / connection issue.
try {
// We're repeating this logic for each github repository of free email domains and blacklisted domains.
urlToSearchForDomains = "https://gist.githubusercontent.com/ammarshah/f5c2624d767f91a7cbdc4e54db8dd0bf/raw/660fd949eba09c0b86574d9d3aa0f2137161fc7c/all_email_provider_domains.txt"
domainSearchResults = new URL(urlToSearchForDomains).getText()
// If the lookup worked, the domains on that page will be added to our spamDomains string array.
spamDomains.addAll(domainSearchResults)
} catch(exception) {
log.error "SPAM Account Prevention: Error retreiving domain " + urlToSearchForDomains
}
try {
urlToSearchForDomains = "https://gist.githubusercontent.com/tbrianjones/5992856/raw/93213efb652749e226e69884d6c048e595c1280a/free_email_provider_domains.txt"
domainSearchResults = new URL(urlToSearchForDomains).getText()
spamDomains.addAll(domainSearchResults)
} catch(exception) {
log.error "SPAM Account Prevention: Error retreiving domain " + urlToSearchForDomains
}
try {
urlToSearchForDomains = "https://gist.githubusercontent.com/michenriksen/8710649/raw/e09ee253960ec1ff0add4f92b62616ebbe24ab87/disposable-email-provider-domains"
domainSearchResults = new URL(urlToSearchForDomains).getText()
spamDomains.addAll(domainSearchResults)
} catch(exception) {
log.error "SPAM Account Prevention: Error retreiving domain " + urlToSearchForDomains
}
// Other spammers have usernames with URLs in them
String spamAccountURLContent = "//"
// spamDomains will have the results from all sites above, plus any that we manually put into the list at the beginning.
// Down the road we may want to remove duplicates either while searching, or above when we add them. Not sure if it will save any processing time though, because either way we'll be doing the same number of comparisons.
for (String spamDomain : spamDomains) {
if (email.toUpperCase().endsWith(spamDomain.toUpperCase()) || fullName.contains(spamAccountURLContent)){
log.error "SPAMBOT DETECTED! Display Name: " + fullName + " Email: " + email;
def userService = ComponentAccessor.getComponent(UserService)
def userManager = ComponentAccessor.getUserManager();
// Set the user account we want to run delete permissions with
ApplicationUser runAsUser = userManager.getUserByKey("yourJiraAdminAccount")
// validate permissions
final UserService.DeleteUserValidationResult result = userService.validateDeleteUser(runAsUser, email)
if (result.isValid()) {
log.error "SPAMBOT REMOVAL VALID - $email"
userService.removeUser(runAsUser, result)
log.error "SPAMBOT REMOVAL SUCCESSFUL - $email"
}
else
{
log.error "REMOVAL INVALID - $email"
}
break;
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hey @Patrick S 👋
by any chance, is there a script for Jira scriptrunner cloud, that you could provide for deleting in bulk?
Cheers, Alex
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hey @Alex Ziegltrum
I am not aware of whether the script above would work with Script Runner cloud. Best bet would be to give it a try, and if it fails see which of the libraries the original script is referencing is the point of failure and use the newer library from there.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
It is surprising that the Administration page does not provide a datatable like interface to select multiple users/records and perform actions. Such basic feature is lacking!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
I wrote a blog post on how to bulk edit Jira user e-mail accounts, it can be easily changed to perform other operations like deactivation.
It's based on ScriptRunner and Groovy.
Cheers!
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
removeUser and updateUser with the deactivate parameter can be used. They are part of the JIRA Command Line Interface (CLI).
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.