D365 Scheduling : msdyn_SearchResourceAvailability – C# Working Code

Currently, we use Schedule Board/Assistant to find the availability of resources based on the requirement.

msdyn_SearchResourceAvailability SDK message has been recently released to build custom functionality around the resource availability finding.

Here’s the C# Working Code snippet:

Entity settings = new Entity(“organization”);
settings[“UseRealTimeResourceLocation”] = false;
settings[“ConsiderTravelTime”] = true;
settings[“ConsiderSlotsWithOverlappingBooking”] = false;
settings[“ConsiderSlotsWithLessThanRequiredDuration”] = false;
settings[“ConsiderSlotsWithProposedBookings”] = false;

var entityCollectionResourceType = new EntityCollection();
entityCollectionResourceType.Entities.Add(new Entity
{
Id = new Guid(),
LogicalName = “ResourceTypes”,
Attributes =
new AttributeCollection
{
new KeyValuePair(“value”, 8)
}
});

var entityCollectionTerritories = new EntityCollection();
entityCollectionTerritories.Entities.Add(new Entity
{
Id = new Guid(),
LogicalName = “territory”,
Attributes =
new AttributeCollection
{
new KeyValuePair(“territoryid”, workOrderDetails.TerritotyId)
}
});
var constraints = new Entity() { LogicalName = “organization”, Id = new Guid(),
Attributes = new AttributeCollection
{
new KeyValuePair(“Territories”, entityCollectionTerritories)
}
}; //Territories

Entity resourceSpecification = new Entity(“organization”);
resourceSpecification[“ResourceTypes”] = entityCollectionResourceType;
resourceSpecification[“RetrieveResourcesQueryId”] = new Guid(fpsActionRetrieveResourcesQueryId);// “e014219f-65c7-476c-88e0-da0e21d4048a”);
resourceSpecification[“Constraints”] = constraints;

var response = service.Execute(
new OrganizationRequest(“msdyn_SearchResourceAvailability”)//””msdyn_getresourceavailability”)
{
Parameters = {
{ “Version”, “1.0” },
{ “Requirement”, requirement},
{ “Settings”, settings},
{“ResourceSpecification”, resourceSpecification}
}
});
var timeSlots = (EntityCollection)response.Results[“TimeSlots”];

Dynamics 365 CI/CD : Turn ON Power Automate (MS Flow) using PowerShell after Solution Import

Often, Power Automate (MS Flow) components goes into OFF mode, post solution import. Had to manually turn it on in this case, as post deployment step.

Especially, if you automated solution deployment setup (CD) in Azure DevOps using Pipelines, this PowerShell script would save your time.

Just a create a Powershell task and put it after solution import step.

$Username=’$(Username)’
$Passwrod=’$(Passwrod)’
$EnvironmentName=’$(EnvironmentName)’

try
{
$modulePowerAppAdministrator=’Microsoft.PowerApps.Administration.PowerShell’
$modulePowerAppAdministrator=’Microsoft.PowerApps.PowerShell’

if(!(Get-Module -ListAvailable -Name $modulePowerAppAdministrator))
{
Write-Host “Installing PowerAppsModule.”
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -Force -Verbose -Scope CurrentUser
Install-Module -Name Microsoft.PowerApps.PowerShell -AllowClobber -Force -Verbose -Scope CurrentUser
Write-Host “Installed Successfully PowerAppsModule.”
}
else
{
Write-Host “Module already installed”
}

}
catch
{

Write-host $_.Exception.Message
}

try{
Write-Host “Connecting Target Instance of PowerApps.”
$pass = ConvertTo-SecureString $Passwrod -AsPlainText -Force
Add-PowerAppsAccount -Username $Username -Password $pass
Write-Host “Successfully Target Instance connected.”
}
catch
{
Write-host $_.Exception.Message
}

try{
Write-Host “Connecting Environment.”

$en=”*$EnvironmentName*”
$environmentName=Get-PowerAppEnvironment $en | Select -ExpandProperty EnvironmentName
Write-Host “Connected Environment.” $environmentName

Get-FlowEnvironment $environmentName
}
catch
{
Write-host $_.Exception.Message
}

$listOfMsFlow=”;
$listOfMsFlow=Get-AdminFlow -EnvironmentName $environmentName |where-object {!($_.Enabled -eq “True”) } | Select FlowName
$count=1;
foreach ($flow in $listOfMsFlow)
{

try{

Write-Host “Flow Name : ” $flow.FlowName $count

Enable-AdminFlow -EnvironmentName $environmentName -FlowName $flow.FlowName
#Disable-AdminFlow -EnvironmentName $environmentName -FlowName $flow.FlowName
# Write-Host “Turn Off.” $flow
$count=$count+1;
}
catch
{
Write-Host “Failed to Turn On.” $flow.FlowName
Write-host $_.Exception.Message
}

}

PS : On very first deployment of flows into new instance, you probably have to set up the connections.

 

Cheers

Dynamics 365 Field Service Geo-fencing Asset

Apart from the below MS Doc steps, some additional things to do to implement geo-fencing for Asset entity.

https://docs.microsoft.com/en-us/dynamics365/field-service/geofencing

1. Geo-code Asset entity:

Before we start following the doc, geo-code the asset – update the assets with geo-coordinates (latitude/longitude) and then write a workflow to copy the asset’s geo-coordinates to Work Order on Work Order Creation.

This is because system copies the service account geo-coordinates to work order on its creation.

2. Create Entity Configuration for Asset:

Lets follow the steps in the doc.

When I reached step #7, i deleted the Entity Configuration for Account and create new one for Asset. Under the hood, it creates a lookup to Asset in Geofence entity.

3. Update the step ‘Create a geofence’ in OOB workflow GenerateGeofenceWhenBookingIsCreated 

Geofencing Logical Entity Name = msdyn_customerasset

Geofencing entity ID = GUID of the asset record.

First, create a new lookup field to asset in booking entity and set its value on booking creation from the Work Order’s primary customer asset field.

Secondly, i used Dynamics 365 custom workflow tools, to get asset guid from record.

generategeofencewhenbookingiscreated

4. Geotracked Record Status is empty

Once its all done and i created a booking, a geofence record got created by the system – all good, but Geotracked Record Status is empty. Final Hurdle.

If you too face this issue, read below:

Reason : As per the documentation, Latitude / Longitude in Bookable Resource should have set based on the mobile audit values. In my case, it’s not.

Fix : I built a Power Automate (MS Flow) that fetches the latitude/longitude values from Mobile Audit on its record creation and update the bookable resource latitude/longitude values.

Now, i can see geofence events getting created:-)

One last thing – i noticed Geofence Alerts solution was not installed, due to which the workflows are not available to send mobile push notifications.

Not a problem, you can implement it by your own by following below:

https://docs.microsoft.com/en-us/dynamics365/field-service/mobile-push-notifications

 

Hope this helps someone

Cheers

 

 

Dynamics 365 CE S2S : Automate App Registration in Azure AD using PowerShell

Application user creation in Dynamics 365 CE requires an app registration in Azure AD, which is a lengthy process. You can automate it using PowerShell.

Launch PowerShell as Administrator in your local machine and run this script.

# Install AzureAD PS module in local m/c
Install-Module AzureAD

#Connect to Azure AD – Launches popup to enter username/password
Connect-AzureAD

#Get CDS object (shown as Dynamics CRM in Azure Portal)
$AzureMgmtPrincipal = Get-AzureADServicePrincipal -All $true | Where-Object {$_.DisplayName -eq "Common Data Service"}

#Create API permission to CDS
$AzureMgmtAccess = New-Object -TypeName "Microsoft.Open.AzureAD.Model.RequiredResourceAccess"
$AzureMgmtAccess.ResourceAppId = $AzureMgmtPrincipal.AppId
$AzureSvcMgmt = New-Object -TypeName "microsoft.open.azuread.model.resourceAccess" -ArgumentList $AzureMgmtPrincipal.Oauth2Permissions.Id, "Scope"
$AzureMgmtAccess.ResourceAccess = $AzureSvcMgmt

#Create App Registration – Update DisplayName value as needed
$App = New-AzureADApplication -DisplayName "Integration App2" -RequiredResourceAccess @($AzureMgmtAccess)

#Create App Secret
$AppSecret = New-AzureADApplicationPasswordCredential -ObjectId $App.ObjectId -CustomKeyIdentifier "Access Key" -EndDate (get-date).AddYears(1)

#Create managed application in local directory
$AppSPN = New-AzureADServicePrincipal -AppId $App.AppId -Tags @("WindowsAzureActiveDirectoryIntegratedApp")

Once the script runs successfully, you can fetch the Client ID and Secret from the script variables $App.AppId and $AppSecret respectively.

 

 

Hope this saves your time!!

Cheers