Hello everyone,
Few days ago, I navigate through my CRM and I was like :
Why don't we have "standard" picture profile synchronisation ?!
It's indeed not available with the out of the box synchronisation between the Azure Active
If you manage to push your users to update their profile pictures in Office 365, you did a nice work. That would be too bad to not take advantage of this and push this picture directly to the user record inside the CRM.
The added value here is not that much, but let's say it's cool to find the same profile picture everywhere you go between your online Apps !
What do we want to achieve in this scenario? :
- Connect to CRM and AAD in powershell
- Retrieve my active CRM users to check the picture
- For each user, retrieve its profile picture from his Azure Active Directory profile
- Update the picture if necessary
- What can we do next ?
Here is a sum up of the actions done by the script :
Pre-requisites :
- Download the Microsoft.Xrm.Data.Powershell module to allow you doing actions in the CRM in powershell.
- Make sure you have the AzureAD powershell module installed
- Being on a CRM Online instance (whatever version)
Disclaimer : This is a sample/draft script.
Let's do it now !
1. Connect to AAD & CRM
#Add-Crm-Sdk;
Import-Module -Name ".\Microsoft.Xrm.Data.Powershell"
# Preparing the needed informations to connect to AAD & CRM
$aadUser = "yourname@domain.com"
$aadPassword = ConvertTo-SecureString -String "YourStrongestPassword" -AsPlainText -Force
$crmUser = "yourname@domain.com"
$crmPassword = ConvertTo-SecureString -String "YourStrongestPassword" -AsPlainText -Force
$crmUrl = "https://tenant.crm4.dynamics.com"
# creating a connection to your AAD
$CredentialAAD = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $aadUser, $aadPassword
try {
$connAAD = Connect-AzureAD -Credential $CredentialAAD
}
catch {
write-host "Caught an exception during connection to AAD:" -ForegroundColor Red
write-host "Exception Message: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
# creating a connection your your CRM instance
$CredentialCRM = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList crmUser, $crmPassword
$conn = Connect-CrmOnline -Credential $CredentialCRM -ServerUrl $crmUrl
# we make sure that the CRM connection was performed properly
if($conn.IsReady -ne $true){
write-host "Caught an issue during connection to CRM instnace:" -ForegroundColor Red
Write-Host $conn.LastCrmError -ForegroundColor Red
exit 1
}
A bit of explanations :
- We import the Microsoft.Xrm.Data.Powershell module as said in prerequisites, this will allow us to query and perform actions over the CRM.
- We define the user accounts which will be used to create a connection to AAD & CRM (it's the same account in my case for example, but based on the permissions control in your organization, it can be different)
2. Retrieve Active CRM Users
Now we want to get our users from the CRM, active ones, since we can't update disabled one.
So we will do that using our previous downloaded module "Microsoft.Xrm.Data.Powershell"
As said, we want to focus on the users who are currently Licensed (via the office365 portal) and are not disabled.
#Getting all users and who are not disabled
$CrmUsers = (Get-CrmRecords -conn $conn -EntityLogicalName systemuser -FilterAttribute isdisabled -FilterOperator eq -FieldValue false -Fields domainname,entityimage,islicensed).CrmRecords
# Now from the result, we keep only the licensed users (to avoid getting the crmoln@microsoft.com users for example)
$CrmUsers = $CrmUsers | ? { $_.islicensed -eq "Yes" }
Write-Host $CrmUsers.Count" users retrieved."
3. Retrieve Picture profile of each user
In order to get access to the profile picture, we need to perform 2 actions :
- Retrieve the user from the Azure AD
- If the user is found, then retrieve the picture
# retrieving the user from the AAD
$userAAD = Get-AzureADUser -ObjectId $CrmUser.domainname
Write-Host " -> AAD profile retrieved."
#Making sure the user was found
if($userAAD -ne $null)
{
#getting the picture and downloading it locally (by default it will be the GUID.jpg filename)
Get-AzureADUserThumbnailPhoto -ObjectId $userAAD.ObjectId -FilePath (Get-Location).Path
# we get the exact filename in case the file doesn't have a jpg extension
$picName = (Get-ChildItem -Path (Get-Location).Path | ? { $_.Name -like ''+$userAAD.ObjectId+'*' }).Name # to handle any kind of extension
# storing the full path to picture
$picPath = (Get-Location).Path+"\"+$picName
Write-Host " -> AAD picture profile retrieved. (path : " $picPath")"
# step 4 of the process will goes here
}
In this part of our script, as you can see in the comments, we perform :
- Retrieve the user from the Azure Active Directory using the DomainName
- If we have a result from that user, we try getting the picture
- and then keeping the picture path in a variable to use it later
4. Update the picture in CRM
if((Test-Path $picPath))
{
# getting the picture content in Bytes
$pictureInBytes = [System.IO.File]::ReadAllBytes($picPath)
# setting the image in bytes to systemuser record
Set-CrmRecord -conn $conn -EntityLogicalName "systemuser" -Id $CrmUser.systemuserid -Fields @{"entityimage"=$pictureInBytes}
Write-Host " -> profile picture updated."
# cleaning the user picture from your drive
Remove-Item -Path $picPath
}
Now that we have all necessary data to actually perform the picture update on the CRM side, we will do it !
The systemuser entity has a field entityimage (field name is similar to other entities which support picture too), this is a field which accept bytes data.
5. What can we do next ?
When you are done "configuring the accounts in the script, there are a lot of possibilities to use it, few quick ideas here :
- Set it up as a schedule task (every day for example) so you make sure that the user's picture are always up to date.
- Improve the way to retrieve the picture : using GraphApi and BearerToken as example
- Improve the error handling : in this version if a user is not found in the AAD, an exception is thrown which is not that "end user" friendly.
- Integrate it in some automation execution in TFS/VSTS
Bonus : démo !
On left side, this is the CRM
On right side, it's my office365 profile.
Limitations
The script works fine but as mentioned above, it needs an account which have enough permissions to connect to the AAD and retrieve profile pictures of other users as well as an account which need enough permissions (read/write all users on the CRM side) to perform the update action.
The error handling is not that perfect so far, as if you enter the wrong user/password for the connection to the AAD, it will throw an exception even if you encapsulate the connection in a try/catch.
Conclusion
As we've seen, this script is pretty simple in term of actions and added value to the CRM.
But i thought, it was really nice regarding the look and feel of the CRM instance having your picture in the top right corner.
Besides that, it reminds us that we can do a lot with Powershell and CRM to add some extra automation / stuff inside your instance.
Hope this can be useful to some of you !
Happy CRM'in !