7

I'm fully aware that deleting users (SystemUser Entity) in CRM Dynamics 2011 is not supported by Microsoft.

However, we're currently developing a tool to support our User Provisioning needs. In order to be able to write integration tests for this tool, it seems necessary to be able to remove users afterwards, so that we can rollback our test environment to the original state.
Currently, we're doing this by restoring organizations from SQL backups, but this is too time consuming to do for each test run.

Update

So far, the best solution we have is to create a user in the integration test, assert everything we need to assert, and afterwards "clean it up" by disabling the user and removing its AD credentials, so that we can re-use those credentials for the next run of the test.

However, as we're only looking for a solution for a test environment, I would really like to have a solution that cleans everything up properly: deleting the records in SQL seems like the way to go. Due to the complex DB structure, however, I was hoping that someone could provide scripts for this.

Update2

We've created the script to manually delete the user from SQL (see accepted answer). This is not supported, so only use it in test environments, if you know what you're doing.

Joris Van Regemortel
  • 935
  • 1
  • 10
  • 34

6 Answers6

10

The following script is not supported by Microsoft. Using it might harm, brick, blow up or molest your CRM organization, deployment, server and career.
Never use this.
Ever.

That being said, we used this, and it worked fine for our purpose: cleaning up our test environment after running AddSystemUser tests.

Some other things to keep in mind :

  • We are using CRM Dynamics 2011 UR10 On-Premises
  • Our test user doesn't have any related records, it's just an isolated user
  • We're using AD authentication
USE OrganizationName_MSCRM
BEGIN TRANSACTION
DECLARE @username AS VARCHAR(50)

-- CHANGE THIS -- 
SET @username = 'domain\username'
-- DONT CHANGE ANYTHING AFTER THIS --

DECLARE @userId AS UNIQUEIDENTIFIER
SET @userId = (SELECT SystemUserId  FROM dbo.SystemUserBase WHERE DomainName = @username)

DECLARE @orgid AS UNIQUEIDENTIFIER
SET @orgid = (SELECT OrganizationId FROM dbo.SystemUserBase WHERE systemuserid = @userid)

DECLARE @userEmail AS VARCHAR(MAX)
SET @useremail = (SELECT InternalEMailAddress FROM dbo.SystemUserBase WHERE SystemUserId = @userid)

DECLARE @userfullname AS VARCHAR(max)
SET @userfullname = (SELECT fullname FROM dbo.systemuserbase WHERE systemuserid = @userid)

DECLARE @queueid AS UNIQUEIDENTIFIER
SET @queueid = (SELECT queueid FROM dbo.SystemUserBase WHERE SystemUserId = @userid)

DECLARE @ownerid AS UNIQUEIDENTIFIER
SET @ownerid = (SELECT ownerid FROM dbo.OwnerBase WHERE name = @userfullname)

DELETE FROM dbo.SystemUserExtensionBase WHERE SystemUserId = @userId
DELETE FROM dbo.UserSettingsBase WHERE SystemUserId = @userId
DELETE FROM dbo.TeamMembership WHERE SystemUserId = @userId
DELETE FROM dbo.SystemUserPrincipals WHERE systemuserid = @userId
DELETE FROM dbo.SystemUserRoles WHERE systemuserid = @userId
DELETE FROM dbo.SystemUserBusinessUnitEntityMap WHERE systemuserid = @userid
DELETE FROM dbo.UserQueryBase WHERE OwnerId = @userid
DELETE FROM dbo.SystemUserProfiles WHERE SystemUserId = @userId
DELETE FROM dbo.SystemUserBase WHERE SystemUserId = @userid
DELETE FROM dbo.QueueBase WHERE QueueId = @queueid
DELETE FROM dbo.PrincipalEntityMap WHERE PrincipalId = @ownerid
DELETE FROM dbo.PrincipalObjectAccess WHERE principalid = @ownerid
DELETE FROM dbo.OwnerBase WHERE ownerid = @ownerid
DELETE FROM dbo.EmailSearchBase WHERE EmailAddress = @userEmail
DELETE FROM dbo.ResourceBase WHERE name = @userfullname
DELETE FROM dbo.CalendarRuleBase WHERE CalendarId IN (SELECT CalendarId FROM dbo.CalendarBase WHERE PrimaryUserId = @userid)
DELETE FROM dbo.CalendarBase WHERE primaryuserid = @userId
DELETE FROM dbo.InternalAddressBase WHERE parentid = @userId

DELETE FROM mscrm_config..SystemUserOrganizations WHERE CrmUserId = @userid AND OrganizationId = @orgid

COMMIT
hydr
  • 408
  • 3
  • 10
Joris Van Regemortel
  • 935
  • 1
  • 10
  • 34
  • 2
    I had to add two lines to your script. Thanks a lot BTW! DELETE FROM dbo.UserQueryBase WHERE OwnerId = \@userid DELETE FROM dbo.SystemUserProfiles WHERE SystemUserId = \@userId – hydr Feb 26 '16 at 17:17
2

Maybe you can try this work around. Rather than just disabling them, change the active directory name to something else, then disable the records.

For example, your script could look as follows (assuming AD authentication):

Create AD users msmith, bmiller, and jdoe.

Perform tests and validation.

Update msmith to testuser1
Update bmiller to testuser2
Update jdoe to testuser3

Deactivate testuser1, testuser2, testuser3

Next test will need to use testuser4, testuser5, testuser6, which means you'll need to create quite a few dummy accounts, but it may be easier to do that, than mess with the CRM SQL database.

For my unit tests where I need a User, I actually mock out the IOrganizationService call for just SystemUser requests, and return a mocked SystemUser entity without it actually hitting CRM. I would suggest that as well, but it sounds like you're attempting to actually test System User creation, so probably isn't an option in this case.

Joris Van Regemortel
  • 935
  • 1
  • 10
  • 34
Daryl
  • 18,592
  • 9
  • 78
  • 145
  • Thanks a lot for your reply. Your work around indeed sounds feasible. However, it will require us to keep a counter of how many users we've already created, and it will leave our CRM Integration Test environment really cluttered with old test users. So definitely an option, but not ideal, I'd think. – Joris Van Regemortel Jun 17 '13 at 12:48
  • On mocking out the User : that approach is indeed not an option for this specific request, as we would like to test creation of a SystemUser. – Joris Van Regemortel Jun 17 '13 at 12:53
  • 1
    @JorisVanRegemortel - You wouldn't need to keep a count of how many users you've already created, you could just do a query, and search for the greatest testuser (Might want to name them testuser00001 for sorting purposes). But again, this might be a case of the cure being worse than the disease (ie, it'd be easier to figure out the SQL required to cleanup the user accounts, than create all these user accounts) – Daryl Jun 17 '13 at 13:10
  • agreed on the query for max user count, that'll be the easiest way. However, that still leaves the cluttered integration test environment. A SQL delete still sounds like a better option - although it's unsupported. Thanks a lot for your replies so far, though! – Joris Van Regemortel Jun 17 '13 at 13:13
2

Here is what I have done in CRM 2015 based on Joris code

USED ORGANIZATIONNAME_MSCRM

BEGIN TRANSACTION

DECLARE @username AS VARCHAR(50)



-- CHANGE THIS --

SET @username = 'AD\USERNAME'

-- DONT CHANGE ANYTHING AFTER THIS --



DECLARE @userId AS UNIQUEIDENTIFIER

SET @userId = (SELECT SystemUserId  FROM dbo.SystemUserBase WHERE DomainName = @username)



DECLARE @orgid AS UNIQUEIDENTIFIER

SET @orgid = (SELECT OrganizationId FROM dbo.SystemUserBase WHERE systemuserid = @userid)



DECLARE @userEmail AS VARCHAR(MAX)

SET @useremail = (SELECT InternalEMailAddress FROM dbo.SystemUserBase WHERE SystemUserId = @userid)



DECLARE @userfullname AS VARCHAR(max)

SET @userfullname = (SELECT fullname FROM dbo.systemuserbase WHERE systemuserid = @userid)



DECLARE @queueid AS UNIQUEIDENTIFIER

SET @queueid = (SELECT queueid FROM dbo.SystemUserBase WHERE SystemUserId = @userid)



DECLARE @ownerid AS UNIQUEIDENTIFIER

SET @ownerid = (SELECT ownerid FROM dbo.OwnerBase WHERE name = @userfullname)



DECLARE @MSCRMUserID as UNIQUEIDENTIFIER

SET @MSCRMUserID = (SELECT Userid FROM mscrm_config..SystemUserOrganizations WHERE CrmUserId = @userid AND OrganizationId = @orgid)

DECLARE @authinfo as NVARCHAR(255)

SET @authinfo = (SELECT Authinfo FROM mscrm_config..SystemUserAuthentication WHERE Userid = @MSCRMUserID)

DECLARE @SUid as UNIQUEIDENTIFIER

SET @Suid = (SELECT id FROM mscrm_config..SystemUserAuthentication WHERE Userid = @MSCRMUserID)



DELETE FROM dbo.UserSettingsBase WHERE SystemUserId = @userId

DELETE FROM dbo.TeamMembership WHERE SystemUserId = @userId

DELETE FROM dbo.SystemUserPrincipals WHERE SystemUserId = @userId

DELETE FROM dbo.SystemUserRoles WHERE SystemUserId = @userId

DELETE FROM dbo.SystemUserBusinessUnitEntityMap WHERE systemuserid = @userid

DELETE FROM dbo.UserQueryBase WHERE OwnerId = @userid

DELETE FROM dbo.SystemUserProfiles WHERE SystemUserId = @userId

DELETE FROM dbo.TeamMembership WHERE SystemUserId = @userId



DELETE FROM dbo.QueueMembership  WHERE SystemUserId = @userId

DELETE FROM dbo.SystemUserBase WHERE SystemUserId = @userid

DELETE FROM dbo.QueueBase WHERE QueueId = @queueid



DELETE FROM dbo.PrincipalEntityMap WHERE PrincipalId = @ownerid

DELETE FROM dbo.PrincipalObjectAccess WHERE PrincipalId = @ownerid

DELETE FROM dbo.MailboxBase WHERE OwnerId = @ownerid

DELETE FROM dbo.OwnerBase WHERE OwnerId = @ownerid

DELETE FROM dbo.EmailSearchBase WHERE EmailAddress = @userEmail

DELETE FROM dbo.ResourceBase WHERE name = @userfullname

DELETE FROM dbo.CalendarRuleBase WHERE CalendarId IN (SELECT CalendarId FROM dbo.CalendarBase WHERE PrimaryUserId = @userid)

DELETE FROM dbo.InternalAddressBase WHERE parentid = @userId

DELETE FROM dbo.CalendarBase WHERE primaryuserid = @userId



DELETE FROM mscrm_config..SystemUserOrganizations WHERE CrmUserId = @userid AND OrganizationId = @orgid

DELETE FROM mscrm_config..SystemUserAuthentication WHERE authinfo = @authinfo

DELETE FROM mscrm_config..SystemUser WHERE id = @MSCRMUserID



rollback

--COMMIT

Once you have run the query and made sure it is deleting the right data, you can un-comment the COMMIT statement and comment the Rollback statement

Hope it helps.

Pang
  • 9,564
  • 146
  • 81
  • 122
2

Just some slight modifications for Dynamics CRM 2016 (On Premise) to allow for some common constraint errors that I came across. Again, this is completely non-supported and proceed at your own risk. (I will update when I find other constraint errors.)

BEGIN TRANSACTION
DECLARE @username AS VARCHAR(50)
/* CHANGE THIS LINE ONLY */
SET @username = 'DOMAIN\USERNAME'
/* END CHANGES */
DECLARE @userId AS UNIQUEIDENTIFIER
SET @userId = (SELECT SystemUserId  FROM dbo.SystemUserBase WHERE DomainName = @username)
DECLARE @orgid AS UNIQUEIDENTIFIER
SET @orgid = (SELECT OrganizationId FROM dbo.SystemUserBase WHERE systemuserid = @userid)
DECLARE @userEmail AS VARCHAR(MAX)
SET @useremail = (SELECT InternalEMailAddress FROM dbo.SystemUserBase WHERE SystemUserId = @userid)
DECLARE @userfullname AS VARCHAR(max)
SET @userfullname = (SELECT fullname FROM dbo.systemuserbase WHERE systemuserid = @userid)
DECLARE @queueid AS UNIQUEIDENTIFIER
SET @queueid = (SELECT queueid FROM dbo.SystemUserBase WHERE SystemUserId = @userid)
DECLARE @ownerid AS UNIQUEIDENTIFIER
SET @ownerid = (SELECT ownerid FROM dbo.OwnerBase WHERE name = @userfullname)
DECLARE @MSCRMUserID as UNIQUEIDENTIFIER
SET @MSCRMUserID = (SELECT Userid FROM mscrm_config..SystemUserOrganizations WHERE CrmUserId = @userid AND OrganizationId = @orgid)
DECLARE @authinfo as NVARCHAR(255)
SET @authinfo = (SELECT Authinfo FROM mscrm_config..SystemUserAuthentication WHERE Userid = @MSCRMUserID)
DECLARE @SUid as UNIQUEIDENTIFIER
SET @Suid = (SELECT id FROM mscrm_config..SystemUserAuthentication WHERE Userid = @MSCRMUserID)
DELETE FROM dbo.UserSettingsBase WHERE SystemUserId = @userId
DELETE FROM dbo.TeamMembership WHERE SystemUserId = @userId
DELETE FROM dbo.SystemUserPrincipals WHERE SystemUserId = @userId
DELETE FROM dbo.SystemUserRoles WHERE SystemUserId = @userId
DELETE FROM dbo.SystemUserBusinessUnitEntityMap WHERE systemuserid = @userid
DELETE FROM dbo.UserQueryBase WHERE OwnerId = @userid
DELETE FROM dbo.SystemUserProfiles WHERE SystemUserId = @userId
DELETE FROM dbo.TeamMembership WHERE SystemUserId = @userId
DELETE FROM dbo.QueueMembership  WHERE SystemUserId = @userId
update dbo.SdkMessageFilterBase set ModifiedOnBehalfBy = NULL where ModifiedOnBehalfBy = @userid
update dbo.SdkMessageFilterBase set CreatedOnBehalfBy = NULL where CreatedOnBehalfBy = @userid
DELETE FROM dbo.SystemUserBase WHERE SystemUserId = @userid
DELETE FROM dbo.CalendarRuleBase WHERE CalendarId IN (SELECT CalendarId FROM dbo.CalendarBase WHERE PrimaryUserId = @userid)
DELETE FROM dbo.CalendarBase WHERE primaryuserid = @userId
DELETE FROM dbo.QueueBase WHERE QueueId = @queueid
DELETE FROM dbo.PrincipalEntityMap WHERE PrincipalId = @ownerid
DELETE FROM dbo.PrincipalObjectAccess WHERE PrincipalId = @ownerid
DELETE FROM dbo.UserEntityUISettingsBase WHERE OwnerID = @userid
DELETE FROM dbo.UserApplicationMetadataBase WHERE OwnerID = @userid
DELETE FROM dbo.PostFollowBase WHERE OwnerID = @userid
DELETE FROM dbo.MailboxBase WHERE OwnerId = @ownerid
DELETE FROM dbo.OwnerBase WHERE OwnerId = @ownerid
DELETE FROM dbo.EmailSearchBase WHERE EmailAddress = @userEmail
DELETE FROM dbo.ResourceBase WHERE name = @userfullname
DELETE FROM dbo.InternalAddressBase WHERE parentid = @userId
DELETE FROM mscrm_config..SystemUserOrganizations WHERE CrmUserId = @userid AND OrganizationId = @orgid
DELETE FROM mscrm_config..SystemUserAuthentication WHERE authinfo = @authinfo
DELETE FROM mscrm_config..SystemUser WHERE id = @MSCRMUserID
/* rollback */
COMMIT
Red Knight 11
  • 127
  • 1
  • 10
1

You could use the totally unsupported way of deleting them by SQL.
As long as you're doing this in an integration test environment I think the harm would be relatively low.

To find what changes are made in the database when adding a user you could

  • copy your current database
  • add a user
  • compare new database state with the previous one (e.g: redgate's SQL compare)

It could be this changes with each rollup so be sure to not rely on this for anything critical or production code.

Boris Callens
  • 90,659
  • 85
  • 207
  • 305
  • I had come to the same conclusion. However, I can't believe that nobody has done this before. I'll give it a little bit more time before I'll be creating the SQL myself :) – Joris Van Regemortel Jun 19 '13 at 07:28
0

This isn't supported, but how about deleting the records directly from SQL?

Never tried it myself and I wouldn't want to do it on a production environment, but if its just for testing/development the worst that happens is you trash a development environment.

James Wood
  • 17,286
  • 4
  • 46
  • 89
  • Indeed, I already figured that this might be the easiest way to do it. However : I'm hoping that someone has done this before, and can provide the SQL script to do this, as it will be a complex one. – Joris Van Regemortel Jun 17 '13 at 09:39