Background
This is the second part on how to delete accounts. In this blog post we will explain why we also exposed CRUD request on our CrmData module.
We also moved the repetitive code (Client SDK and Proxy) to a Helper script file DG.Delegate.HowToDaxif.DataManagement.Helper.fsx
Delete all accounts
As mentioned above, we just moved a few function to another file and created a prime version of the script we used in the previous blog post DG.Delegate.HowToDaxif.DataManagement.Prime.fsx.
It’s only the second step that we changed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// 2) Delete all entities from query (with ExecuteMultiple and parallelism)
accounts ()
|> hlp.Seq.split (10*1000)
|> Seq.iter(fun xs ->
printfn "- Chunks of 10.000"
xs
|> Array.Parallel.map(fun e -> CRUD.deleteReq e.LogicalName e.Id)
|> Array.toSeq
// ExecuteMultiple - Run-time limitations:
// https://msdn.microsoft.com/en-us/library/jj863631.aspx#limitations
|> hlp.Seq.split 1000
|> Seq.toArray
|> Array.Parallel.map (fun dreqs ->
let orc = new OrganizationRequestCollection()
dreqs // OrganizationRequestCollection is not thread-safe
|> Array.iter (fun x -> orc.Add(x))
let emreqs = new ExecuteMultipleRequest()
emreqs.Settings <- new ExecuteMultipleSettings()
emreqs.Settings.ContinueOnError <- true
emreqs.Settings.ReturnResponses <- true
emreqs.Requests <- orc
emreqs, dreqs)
|> Array.Parallel.map (fun (emreqs, dreqs) ->
try
(hlp.proxy().Execute(emreqs) :?> ExecuteMultipleResponse, dreqs) |> Some
with ex ->
Console.Error.WriteLine(sprintf "* Proxy execute: %s" ex.Message); None)
|> Array.Parallel.choose (id)
|> Array.Parallel.iter (fun (emresps, _) ->
emresps.Responses
|> Seq.toArray
|> Array.Parallel.iter(fun kv ->
match kv.Fault with
| null -> ()
| fault ->
Console.Error.WriteLine(
sprintf " --Execute multiple: %s" fault.Message))))
If we now run the two deletion script for comparison, we can see that they have similar performance, due to the size of data:
Note: There is a limitations on MS CRM Online (only two ExecuteMultiple can be executed at the same time.
Output from evaluating script from part 1:
Output from evaluating script from part 2:
Bonus
While I was writing this blogpost, we got the following question: “We have a question about timezones. It seems like there is no way to set up a default timezone that will be used when new users are added to CRM. Do you know of a way that we can set up a timezone that gets used for each user without having to edit them individually?”
We provided the following answers:
-
Post plug-in added on the SystemUser Create event: You can hook up an event that sets the time zone when a new users is added (you will have to find the related UserSettings created by the kernel). Downside is that this approach only work with new created SystemUsers.
-
As Microsoft have bought AdxStudio, they are slowly moving all the fancy PowerShell scripts from their ALM Toolkit to Microsoft Xrm Data Powershell library (which is nice). Here is an example on how to update a System Users settings: UpdateCrmUsersSettings.ps1
-
Last but not least, you could use Daxif (now it’s open source) and run the following F# script when a user is created and also on some time frequency, to ensure that users are using the time zone that you specify:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
let timeZoneCode () =
CRUD.retrieve
(hlp.proxy())
target.Metadata.TimeZoneDefinition.``(LogicalName)``
target.Records.TimeZoneDefinition.``(GMT+01:00) Brussels, Copenhagen, Madrid, Paris``
|> fun e -> e.Attributes.[target.Metadata.TimeZoneDefinition.TimeZoneCode]
target.Records.SystemUser.``(All Records)``
|> Array.filter(fun guid -> guid <> target.Records.SystemUser.SYSTEM)
|> Array.filter(fun guid -> guid <> target.Records.SystemUser.INTEGRATION)
|> Array.Parallel.map(
fun guid ->
try
let e = new Entity(entityName = target.Metadata.UserSettings.``(LogicalName)``)
e.Id <- guid
e.Attributes.Add(target.Metadata.UserSettings.TimeZoneCode,timeZoneCode())
CRUD.update (hlp.proxy()) e |> Choice1Of2
with ex -> ex |> Choice2Of2)
(semi-type safe approach which is readable and generic for all MS CRM instances)
More info:
- NUGET package: https://www.nuget.org/packages/Delegate.Daxif/
- Github website with documentation and API Description: http://delegateas.github.io/Delegate.Daxif/
- Is constantly being developed: http://delegateas.github.io/Delegate.Daxif/RELEASE_NOTES.html
References:
- GitHub: Microsoft.Xrm.Data.PowerShell
- Dynamics CRM in the Field Blog: Great Power Tools for CRM Administrator: Microsoft.Xrm.Data.PowerShell module - Part II