The need to manage dormant users becomes increasingly important with the recent introduction of enforcement for named-user license entitlement. Over-provisioning of named-user licenses is problematic and discussed extensively in my blog.
Dormant users should no longer consume a license. Such users must be deleted or deactivated to free up limited licenses for others and ensure continued service.
However, there are issues facing any administrator:
There is no API or programmatical means to activate or deactivate users. There is no option to use the SCIM API to change the users’ status. The isActive user property is now read-only, which means manual intervention is the only option. Go to the Menu-Security-Users screen, select one or multiple users, and press the ‘activate’ or ‘deactivate’ button.
Whilst the activation and deactivation of users require the use of the user interface, this doesn’t prevent:
I have updated my SAP Analytics Cloud SCIM API Sample Scripts to do precisely this. In particular, my sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’ has been updated to do all the hard work for you! The remainder of this post provides the details of how this works.
It’s not as easy as you first think, as there are many complications and use cases to support. For example, a dormant user would not be:
But it gets more complicated than that. For example:
They may have private content. When the user is deleted via the API, any content in their private folder is moved to the System Owner’s private folder. Even though it isn’t best practice to share private content directly with others, if this has been done, the system owner could start to own a lot of private content unexpectedly when the user is deleted.
A deactivated user doesn’t lose their content; it stays where it is, but any schedules they set up will be paused.
They may have created content now stored in public folders. By default, such content grants special access rights to the creator, known as owner rights. Whilst ownership can be transferred to others, this is only possible via the user interface and not via any API. It means when the user is deleted, the ownership is lost. Content without an owner isn’t necessarily a problem if others have been given rights; however, some artefacts, like models, require an owner to perform specific tasks on them. Overall, it could present unexpected and unnecessary surprises for others later. Ownership can be restored by recreating the user with the same user ID as the previously deleted user.
A deactivated user doesn’t lose their ownership, but there can be implications, especially for models, which could prevent import jobs from running.
The user could be a manager. Users who are managers can’t be deleted, and you may not wish to delete them anyway!
A deactivated manager means they can no longer grant request roles to others.
The user could be consuming a Business Intelligence concurrent session license. These users only consume a license at the time of login; they don’t consume a license when they have no active session. This means deleting a concurrent session-based user for license compliance may be unnecessary.
Equally, there’s no need to deactivate a concurrent-session-based user from a license perspective. (for more details about concurrent sessions, please visit my blog).
The user could already be deactivated, which means they don’t consume a license, and in turn, this means the need to delete a user for license compliance may be unnecessary. Unnecessarily deleting users could cause surprises later, and this can be avoided simply by not deleting them in the first place.
Some users just should never be either deactivated or deleted, and these might include:
Thankfully, all the hard work is done for you, and the above issues are either fully addressed or mitigated.
The solution is primarily captured in the sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’, which does nothing more than identify dormant users and adds them to a team. The team can then be further processed:
Depending upon your use-case other sample scripts may need to be run, for example, to remove certain users because they are ‘special’ users (and members of specific teams), or you’d like to delete the users outright in an automated means.
The sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’ reads a data file to determine what a dormant user is. This data file is easily editable and enables you to customise to your needs. Once the dormant users are identified, they are added to a team, and any previously identified users who are no longer dormant are removed.
The data file can become quite complex, but do not fear! I’ve provided many samples for you to re-use; you only need to pick the most suitable example and make minor edits to things like the ‘number of days since last logon’.
Example data file | Description/use-case |
Dormant users A | Deletes users that were created over 3 months ago, have not logged in within the last 30 days, and have 2 or fewer logins within the last 90 days |
Dormant users B | Same as A, but users have no private folder content. |
Dormant users C | Same as B, but users did not create public folder content. |
Dormant users D | Same as C, but users are not managers. |
Dormant users E | Same as D, but users are activated. |
Dormant users F | Same as E, but users are with a BI named license |
As an example, here is ‘Dormant users A’ data file, and you can see the data file, which is easily editable to change the values to your needs:
[{ "file_team": "AdminToolKit_Users_Dormant_A__Created_3_Months_No_Recent_Login_Fewer_Than_3_Logins_Last_3_Months", "file_team_displayname": "Users that were created over 3 months ago, have not logged in within the last 30 days, and have 2 or fewer logins within the last 90 days. Updated TIMESTAMP", "file_users_action": "replace", "file_multiple_action_users_operator_is_AND": true, "file_action_users_created_more_than_days_ago": true, "file_users_created_more_than_days": 90, "file_action_users_with_most_recent_login_at_least_days_ago": true, "file_users_with_with_most_recent_login_at_least_days": 30, "file_action_users_with_fewer_logins_than": true, "file_users_with_fewer_logins_than": 3, "file_action_users_with_fewer_logins_within_last_days": true, "file_users_with_logins_within_last_days": 90 }]
My user guide provides the entire specification, but to understand what’s possible, let’s look at the most complex sample, ‘Dormant users F’ and what it means.
These are those users:
The image above shows when users were created and their historic login activity. This table explains the logic determining if the user is dormant or not:
User 1 | User-created over 3 months ago, without any logins since creation. |
The user is dormant. |
User 2 | User-created under 3 months, without any logins since creation. |
The user is not dormant. |
User 3 | User-created over 3 months ago and has 2 or fewer logins within the last 90 days. The user has no login within the last 30 days. |
The user is dormant. |
User 4 | User-created over 3 months ago, but has 3 logins within the last 90 days and a login within the last 30 days. |
The user is not dormant. |
User 5 | User-created over 3 months ago and has 2 or fewer logins within the last 90 days, but there was a login within the last 30 days. |
The user is not dormant. |
User 6 | User-created over 3 months ago, but has 4 logins within the last 90 days, although no login within the last 30 days. |
The user is not dormant. |
This scenario partly resolves a problem when users have private content:
When the user is deleted via the API, any content in their private folder is moved to the System Owner’s private folder. Even though it isn’t best practice to share private content directly with others, if this has been done, the system owner could start to own a lot of private content unexpectedly when the user is deleted.
Users that have the following content types in their private folder are excluded:
This issue is only partly resolved because of many other types of content that aren’t identified. However, it’s likely that given these types of content are the most popular, it’s unlikely that a user with different content types would not have one of these identifiable types.
This scenario partly resolves a problem when users create content stored in public folders:
By default, any content created is granted special access rights to the creator, known as owner rights. Whilst ownership can be transferred to others, this is only possible via the user interface and not via any API. It means when the user is deleted, the ownership is lost. Content without an owner isn’t necessarily a problem if others have been given rights; however, some artefacts, like models, require an owner to perform specific tasks on them. Overall, it could present unexpected and unnecessary surprises for others later. Ownership can be restored by recreating the user with the same user ID as the previously deleted user.
This issue is only partly resolved because there is no check to see if the user owns the content. Ownership rights may have changed since creation. The check is if the user created the content, not if they are still the owner or have any particular rights to the content. However, any users that created public folder content will be excluded and thus help reduce future surprises with a lack of access to any content. It is more unlikely that such users would be owners of other content, which could be problematic if deleted.
Users who are managers can’t be deleted. Any attempts to delete the manager will fail, which could be unexpected or require some exception to manage. Excluding managers resolves this problem and would mean that the sample script that deletes users should not fail for this reason. Managers are thus excluded from being identified as dormant.
Deactivated users don’t consume a license and are excluded from being identified as dormant. There’s no need to delete users unnecessarily.
Users with a Business Intelligence concurrent-session-based license only consume a licence while having an active session in SAP Analytics Cloud. It means you can have as many registered users as you please that are configured this way and remain compliant; there is no limit to the number of Business Intelligence concurrent-session-based users in SAP Analytics Cloud. For more details about managing licenses, please visit my blog.
In this scenario, users with the ‘concurrent-session’ setting are excluded from being identified as dormant; however, there is a limitation. The ‘concurrent-session’ setting is only a ‘request’ for a concurrent-session license, and it does not mean the user will consume a concurrent-session license. The user could consume a named-user license because they were assigned a Planning Role (or an Analytics Hub Role). For more details on this, please visit the blog just mentioned. It means users could incorrectly be removed from the ‘dormant list’ of users because their setting is ‘requesting’ a concurrent-session license when they are consuming a named-user license. In turn, this means these users may not get deleted when you might want them to.
You can exclude individually named users using the settings ‘file_JSON_users_to_exclude’ even if they are dormant; they will not be added to the team. Such users could be SAP Support users or System Owner. Add multiple by separating them with a comma (,), for example
[{"value":"SAP_SUPPORT12345"},{"value":"MATTHEW"}]
Once you have run the sample script (Postman Collection) ‘1665-All_U-Uc-Uu-Oarrieei-Fj-Es-AdminToolKit’, you may need to remove some users from being considered dormant because they are particular users of a given team.
You’ll need to run another sample script, ‘1653-T-Uc-Utr-Oarrkie-Fcj-Es-Teams on Teams’ with another data file. It could be a more favourable option to exclude users from being deleted than listing individual users earlier by file_JSON_users_to_exclude. It will remove users in teams called ‘TeamA’ and ‘TeamB’ from your team of so far identified dormant users.
The data file will need to contain something like:
[{ "file_source_team": "TeamA", "file_target_team": "AdminToolKit_D07_Dormant_Users_F", "file_users_action": "remove", "file_roles_action": "keep" }, { "file_source_team": "TeamB", "file_target_team": "AdminToolKit_D07_Dormant_Users_F", "file_users_action": "remove", "file_roles_action": "keep" }]
Adjust the team names accordingly and add or remove other teams for your needs. (Sorry for any confusion, but there are 2 example data files for each example, A to F. The duplicate is because I copied them into a ‘scenario’, and this uses a different team name. So, the target_team might need a name change compared to the one shown here. The scenario has all the data files preconfigured to delete the users and the team, saving you some work – see the user guide for more. The scenarios also include the setting file_JSON_users_to_exclude)
The teams TeamA and TeamB are not updated; they are read-only.
The data files needed for deleting the users and the team are preconfigured for you. Even if you don’t intend to delete the users, you can still use these preconfigured sets of data files to identify the users for manual deactivation or potentially re-activation. These preconfigured data files form a ‘scenario’. Just ignore the last step in the scenario that deletes users. The benefit of the scenario is that the preceding action to ‘preserve special users’ is preconfigured. (see below about scenarios)
Deactivate/activate
Dormant users need not be deleted for license compliance since a deactivated user does not consume any license. There is no API or automated means to set users as deactivated programmatically, which means the user interface is the only means to achieve this. Currently, it is not possible to de-activate a whole team of users or easily select users of a given team for deactivation, though this may change in the future.
With the dormant users now identified and members of a team, it makes it just a little easier to see which users need to be deactivated manually.
A scenario is a straightforward concept comprising sets of preconfigured sample data files. Each scenario addresses a single use-case by combining different sample scripts (Postman collections) in a particular order.
It means most of the thinking has been done for you. All you need to do is tweak the data files for your needs, such as the team names, roles names, manager ids, etc.
The summary of the scenarios for managing dormant users:
Scenario | Description / use-case |
D02 – Delete dormant users A | Deletes users that were created over 3 months ago, have not logged in within the last 30 days, and have 2 or fewer logins within the last 90 days |
D03 – Delete dormant users B | Same as D02, but users have no private folder content. |
D04 – Delete dormant users C | Same as D03, but users did not create public folder content. |
D05 – Delete dormant users D | Same as D04, but users are not managers. |
D06 – Delete dormant users E | Same as D05, but users are activated. |
D07 – Delete dormant users F | Same as D06, but users are with a BI named license |
Pick the best scenario that suits your needs, and follow the user guide for that scenario to make any necessary changes.
Download the user guide found in my blog post and follow the step-by-step instructions.
Suppose you’ve already made use of my SCIM API samples. In that case, you will probably need to create a new OAuth client, as this updated 1665-AdminToolKit uses the ‘Activities’ access to obtain login activity. Without access, it can’t identify dormant users based on in-activity.
Comment here if you found this blog and sample helpful, especially if it saved you time and effort.
The updated 1665-AdminToolKit, which inspects login events in the activities log, enables other use cases beyond dormant users. For example, the preconfigured data file provided describes their use case:
x665 sample - 20 - AdminToolKit_Users_Created_Over_A_Year_Ago.json x665 sample - 21 - AdminToolKit_Users_Created_Recently.json x665 sample - 22 - AdminToolKit_Users_With_A_Recent_Login.json x665 sample - 23 - AdminToolKit_Users_Without_A_Recent_Login.json x665 sample - 24 - AdminToolKit_Users_With_Few_Logins_Since_Oldest_Log_Entry.json x665 sample - 25 - AdminToolKit_Users_With_Few_Logins_This_Last_Month.json x665 sample - 26 - AdminToolKit_Users_Without_A_Recent_Login_And_Fewer_Than_3_Logins_Last_3_Months.json x665 sample - 27 - AdminToolKit_Users_With_100_Or_More_Logins_Since_Oldest_Log_Entry.json x665 sample - 28 - AdminToolKit_Users_With_100_Or_More_Logins_Within_Last_3_Months.json x665 sample - 29 - AdminToolKit_Users_With_Private_Folder_Content.json x665 sample - 30 - AdminToolKit_Users_Without_Private_Folder_Content.json x665 sample - 31 - AdminToolKit_Users_That_Created_Public_Folder_Content.json x665 sample - 32 - AdminToolKit_Users_That_Did_Not_Create_Public_Folder_Content.json
It means you can identify very productive users quickly and may go some way to help manage your user base more efficiently.
There is no need to download the Postman app, connect to any Postman website or web service or register with Postman. The open-source option doesn’t require any internet connectivity to operate.