ScriptRunner - script to remove inactive users from all groups

Chris Shepherd August 30, 2017

I'm looking for a script that removes all inactive users from any groups they are in.  Does anyone have such a thing?

 

thanks in advance

Chris

4 answers

2 accepted

1 vote
Answer accepted
Chris Shepherd August 30, 2017

For anyone who searches this,  this is what I did in the end - including some logging and the ability to exclude groups that are controlled via ldap:

 

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.groups.GroupManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.user.util.UserUtil
import org.apache.log4j.Logger
import org.apache.log4j.Level
def log = Logger.getLogger("com.jira.DelActiveScript")
log.setLevel(Level.DEBUG)

def userManager = ComponentAccessor.getUserManager()
def userUtil = ComponentAccessor.userUtil
def users = userManager.getAllApplicationUsers()
def array = users.toArray()
def groupManager = ComponentAccessor.getGroupManager()

for (int i =0; i < array.size(); i ++){
def user = array[i].getName().toString()

if(!userManager.getUserByName(user).isActive()){
def groups = groupManager.getGroupsForUser(user)

for (int j =0; j < groups.size(); j ++){
if(groups[j].getName().toString() != "jira-users"){
def groupName = groups[j].getName().toString()
log.debug(user + " - " + groupName)

def group = groupManager.getGroup(groupName)
userUtil.removeUserFromGroup(group, userManager.getUserByName(user))
}
}
}
}
Mauri Suomivuori January 27, 2021

Thanks for this. Still works well!

kdickason April 26, 2022

@Chris Shepherd I am looking to remove Inactive users from all my groups, including jira-users.  I think this is what you were trying to achieve.  Can you help me understand what is happening in this portion of your script above?  

for (int j =0; j < groups.size(); j ++){
if(groups[j].getName().toString() != "jira-users"){
def groupName = groups[j].getName().toString()
log.debug(user + " - " + groupName)

I am not strong with scripting (obviously). Thank you. 

Chris Shepherd April 26, 2022

Well, it's 5 years since I wrote it but:


for (int j =0; j < groups.size(); j ++){

is creating a counter (j) to loop through all the groups

if(groups[j].getName().toString() != "jira-users"){

Get the group name for the counter.
If the group name is not equal (!=)  to jira-users  then do the next bit

def groupName = groups[j].getName().toString()

get the group name (again!  who wrote this rubbish  :) )

log.debug(user + " - " + groupName)

write it to the log file to show whats going on 

def group = groupManager.getGroup(groupName)
userUtil.removeUserFromGroup(group, userManager.getUserByName(user))

Then take them out the group.


I ignore the jira-users group as that is controlled by ldap in our instance.  but if you don't want to do that remove the 

if(groups[j].getName().toString() != "jira-users"){

 

 

HTH
Chris

kdickason April 26, 2022

Thank you so, so much.  And I love your rubbish comment. Made me laugh--thanks.

kdickason April 26, 2022

Tried running this and removed 

if(groups[j].getName().toString() != "jira-users"

Result shows "null"

The Log is packed full of entries identifying the Inactive User and group assignment, then the INFO message"[IssueSecurityLevelManagerImpl.projectAndUserToSecurityLevelCache]: Cache com.atlassian.jira.issue.security.IssueSecurityLevel managerImpl.projectAndUserToSecurityLevelCache was flushed

When I go back to the User Management area though, all the Inactive users are still assigned to all their groups, though.  Any guidance if appreciated.

Chris Shepherd April 26, 2022

Sorry don't really know why that wouldn't work.  you could try adding some more logging:

change

   def group = groupManager.getGroup(groupName)
userUtil.removeUserFromGroup(group, userManager.getUserByName(user))

to

def group = groupManager.getGroup(groupName)
def userObj = userManager.getUserByName(user)
log.debug(group)
log.debug(userObj)
userUtil.removeUserFromGroup(group, userObj)


If either group or userobj display as null then that might be the problem. 

kdickason April 26, 2022

Yeah, now I'm seeing info about Crowd and immutable groups. I'll have to dive into this. Thank you!!

1 vote
Answer accepted
Tayyab Bashir
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
August 30, 2017

Hi, 

Ive used deprecated method in it, but it should work i think. 

{code}

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.groups.GroupManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserManager
import com.atlassian.jira.user.util.UserUtil

def userManager = ComponentAccessor.getUserManager()
def userUtil = ComponentAccessor.userUtil

def users = userManager.getAllApplicationUsers()
def array = users.toArray()

def groupManager = ComponentAccessor.getGroupManager()


for (int i =0; i < array.size(); i ++){
def iter = array[i].getName().toString()
print iter
def groups = groupManager.getGroupsForUser(iter)
def currentApplicationUser = userManager.getUserByName(iter)
print currentApplicationUser
if(!userManager.getUserByName(iter).isActive()){
userUtil.removeUserFromGroups(groups, currentApplicationUser)
}
}

{code}

Chris Shepherd August 30, 2017

Thanks so much,  it wasn't exactly what I needed but got me right to the edge of what was required.

Thanks Loads

1 vote
Efren Miguel August 1, 2022

Thanks for this, I faced a similar req, but removing just from a specific group since we synch groups from LDAP, here's my modified version, saved it in ScriptEditor, and used it with different group names as separate ScriptRunner Jobs:

 

/**
 * Script scans for inactive users and removes it from group specified as parameter.
 *
 * @author  xxx
 * @version 1.0
 * @since   2022-08-01
 */

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.security.groups.GroupManager
import com.atlassian.jira.user.ApplicationUser
import com.atlassian.jira.user.util.UserUtil
import com.onresolve.scriptrunner.parameters.annotation.*
import org.apache.log4j.Logger
import org.apache.log4j.Level

def log = Logger.getLogger(getClass())
log.setLevel(Level.DEBUG)

def userManager = ComponentAccessor.getUserManager()
def userUtil = ComponentAccessor.userUtil
def groupManager = ComponentAccessor.getGroupManager()

@ShortTextInput(label = "Group To Remove From", description = "Enter a group to remove inactive users from.")
String groupToRemoveFrom

def users = userManager.getAllApplicationUsers()
users.each {user ->

    def userName = user.getName()

    // process only Inactive users
    if ( !user.isActive() ) {

        def userDisplayName = user.getDisplayName()

        def groups = groupManager.getGroupsForUser(userName)
        groups.each {group ->

            def groupName = group.getName().toString()

            if ( groupToRemoveFrom == null || groupName.equals(groupToRemoveFrom) ) {
                userUtil.removeUserFromGroup(group, user)
                log.debug("User [${userName}] ${userDisplayName} removed from group ${groupName}")
            }

        }

    }
}

return null
Michiel Schuijer September 29, 2022

Thanks for that @efrel !

I have tried using this and see some warnings appear in ScriptEditor.

The first is concerning line 17 and the variable "log":

Screen Shot 2022-09-29 at 09.51.20.png

If I change that to "logs" another warning appears, this time on line 27, concerning an improved search method:

Screen Shot 2022-09-29 at 09.51.44.png

Do you have any tips on how to deal with this?

Can it safely be ignored, or could you improve it, maybe?

Many thanks and kind regards.

Michiel

Efren Miguel October 5, 2022

Hi Michiel, apparently there are newer more efficient ways to accomplish this now, I upgraded my code as well and tested successfully on 8.22.6, here it is:

 

/**
 * Script scans for inactive users and removes it from group specified as parameter.
 *
 * @author  Efren Miguel
 * @version 2.0
 * @since   2022-10-05
 */

import com.atlassian.jira.bc.user.search.UserSearchParams
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.user.UserFilter
import com.atlassian.crowd.embedded.api.Group
import com.onresolve.scriptrunner.parameters.annotation.GroupPicker

@GroupPicker(label = 'Group to Remove From', description = 'Pick a group to remove Inactive users from.', placeholder = 'Pick a group')
Group theUsersGroup

def userSearchService = ComponentAccessor.getComponent(UserSearchService)
def userUtil = ComponentAccessor.userUtil

// user search parameters
def allowEmptyQuery = true
def includeActive = false  // IMPORTANT: MUST BE true
def includeInactive = true
def canMatchEmail = false
Set<Long> projectIds = null
int limit = 100  // this is the max value
def sorted = false
def ignorePermissionCheck = true
UserFilter groupUserFilter = new UserFilter(true, null as Collection<Long>, [theUsersGroup.getName()] as Collection<String>)
def searchParams = new UserSearchParams(allowEmptyQuery, includeActive, includeInactive, canMatchEmail, groupUserFilter, projectIds, limit, sorted, ignorePermissionCheck)

def outputLines = ["REPORT:" as String]
def totalUsers = 0
// execute 5 times to process a maximum of (5 x limit) inactive users
for (int i=0; i<5; i++) {
    // get users (inactive and in specified group), then remove from group
    def inactiveUsersInGroup = userSearchService.findUsers('', searchParams)
    outputLines.add("${inactiveUsersInGroup?.size()} inactive users found in group ${theUsersGroup.getName()}." as String)
    inactiveUsersInGroup.each {user ->
        // double check to make sure user is inactive, before removing from group
        if (user.isActive()==false) {
            userUtil.removeUserFromGroup(theUsersGroup, user)
            outputLines.add("User [${user.getName()}] ${user.getDisplayName()} removed from group ${theUsersGroup.getName()}." as String)
            totalUsers++
        }
    }
    if (inactiveUsersInGroup.size()==0) {
        break
    }
}
outputLines.add("Total of ${totalUsers} inactive users deleted from group ${theUsersGroup.getName()}." as String)

// return outputLines as HTML string
return "<p>"+outputLines.join("<br/>")+"</p>"
Like Michiel Schuijer likes this
Michiel Schuijer October 6, 2022

Super! Thanks a lot for that.

0 votes
Olivia Case December 29, 2022

Does anyone know how to do this for Jira Cloud using ScriptRunner?

Suggest an answer

Log in or Sign up to answer