Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in
Celebration

Earn badges and make progress

You're on your way to the next level! Join the Kudos program to earn points and save your progress.

Deleted user Avatar
Deleted user

Level 1: Seed

25 / 150 points

Next: Root

Avatar

1 badge earned

Collect

Participate in fun challenges

Challenges come and go, but your rewards stay with you. Do more to earn more!

Challenges
Coins

Gift kudos to your peers

What goes around comes around! Share the love by gifting kudos to your peers.

Recognition
Ribbon

Rise up in the ranks

Keep earning points to reach the top of the leaderboard. It resets every quarter so you always have a chance!

Leaderboard

Come for the products,
stay for the community

The Atlassian Community can help you and your team get more value out of Atlassian products and practices.

Atlassian Community about banner
4,457,020
Community Members
 
Community Events
176
Community Groups

ScriptRunner - script to remove inactive users from all groups

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

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))
}
}
}
}

Thanks for this. Still works well!

@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. 

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

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

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.

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. 

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

1 vote
Answer accepted

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}

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

Thanks Loads

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

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

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

Super! Thanks a lot for that.

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

Suggest an answer

Log in or Sign up to answer