Using PowerShell to script Dynamics Marketing
Dynamics Marketing is a great tool to capture, score and nurture leads in automated campaigns. You can build your campaigns and lead management processes which automatically invite your audience, capture registrations, send welcome emails register for your marketing events and trigger post event communication e.g. based on specific record of attendance.
While most of marketing processes are automated in Dynamics Marketing, often a lot of what is going on at an event is also in different systems or in real world – like the system that records attendees at an in person event when they enter the session room.
In such situations you have a simple goal: Log a record of attendance in Dynamics Marketing such that lead scoring and nurturing processes can pick up this information for example through Lead Interactions and leads that get created automatically. And because Dynamics Marketing offers API and OData endpoints, this sounds to be very feasible – doesn’t it?
Some background
With the SDK for Dynamics Marketing sample code ships that shows how to write an application that communicated through a Windows Azure Service Bus queues with the API endpoint of an Dynamics Marketing instance. The methods available on this endpoint focus creation and update of Contacts, Companies and Leads; also managing lists, sending transactional email marketing messages creation of event registrations and records of attendance and more.
A good way to learn about the capabilities of the API Endpoints is simply looking into the assembly from the SDK directly and exploring the available methods and messages:
If you are looking for a simple step by step guide on building an SDK client with Visual Studio you can download this document. It explains step by step how to build a simple application that communicates through the Service Bus queues.
The OData endpoint has a rich documentation of all tables and fields here. And if you want to see how you can write an application that makes use of the OData endpoint as coded client application you can review one of my past blog posts here.
But for various smaller operations and feasibility prototypes or if you want to design a business flow then instead of developing an application a scripting approach might simply be easier for you. And if you are not a developer who likes to mangle with authentication code or data querying and parsing in code, then this is another reason to look into scripting options.
First Step: Install the PowerShell cmdlets from here. There are version available for both 32- and 64-bit PowerShell.
Scripting the SDK endpoint
After you have installed the power shell cmdlets on your machine you can connect with PowerShell to the SDK endpoint with this:
Add-PSSnapIn Microsoft.Dynamics.Marketing.API
$SecureString=ConvertTo-SecureString "QUEUE ACCESS KEY GOES HERE =" -asplaintext -force
Connect-MDMApi MyServiceBus101 owner $securestring sdkRequest sdkResponse -verbose
You need to configure the SDK endpoint before: Configure Dynamics Marketing to communicate through queues. This involves creating an ACS enabled Azure ServiceBus namespace also using PowerShell commands. You only need to create the service bus and then leave it to the SDK configuration in the integration settings page to configure the service bus and ACS. After that only one little piece is missing: In the ACS portal we need to add a credential of type symmetric key for the service identity that has been created for us. The key we define here is the secret that will allow your PowerShell command let to authorize sending commands to the service bus and receive responses. The key if referred below as the IssuerKey.
With that in place you are ready to use one of the commands from the cmdlet. Type Get-Command -Module:Microsoft.Dynamics.Marketing.API to get a list of all commands contained. Use the command Get-Help to learn about the command parameters.. For example Get-Help -Name:Get-MDMLeads
Connect-MDMApi Disconnect-MDMApi | Send-MDMApiRequest Get-MDMApiResponse |
Add-MDMCompany Add-MDMContact Add-MDMContacts Add-MDMContactToList Add-MDMCustomFieldCategories Add-MDMEventAttendance Add-MDMEventRegistration Add-MDMExternalEntity Add-MDMLead Add-MDMList Add-MDMMarketingResult Copy-MDMListContacts | Get-MDMAllLists Get-MDMCompanies Get-MDMCompany Get-MDMContact Get-MDMContactPermissions Get-MDMContacts Get-MDMCurrencies Get-MDMCustomFields Get-MDMEmailMessages Get-MDMEmailMessageSentStatus Get-MDMEventAttendance Get-MDMEventAttendanceStatuses Get-MDMEventRegistration Get-MDMExternalEntiity Get-MDMExternalEntity Get-MDMExternalIds Get-MDMHardbounces Get-MDMLanguages Get-MDMLead Get-MDMLeadPriorities Get-MDMLeads Get-MDMLeadStatuses Get-MDMList Get-MDMMarketingResult Get-MDMMarketingResults Get-MDMMarketingResultTypes Get-MDMMissingContactPermissions Get-MDMSalesRatings Get-MDMSalutations Get-MDMSchemaForEmailMessage Get-MDMTerritories |
Send-MDMEmailMessages Set-MDMContactPermissions Set-MDMContactsPermissions Set-MDMHardbouncesProcessed | Remove-MDMAllContactsFromList Remove-MDMCompany Remove-MDMContact Remove-MDMContactFromList Remove-MDMEventAttendance Remove-MDMEventRegistration Remove-MDMExternalEntity Remove-MDMExternalEntityType Remove-MDMLead Remove-MDMList Remove-MDMMarketingResult |
The first command we use is to connect to the API endpoint:
Connect-MDMApi [[-Namespace] <string>] [[-IssuerName] <string>] [[-IssuerKey] <securestring>]
[[-RequestQueueName] <string>] [[-ResponseQueueName] <string>] [[-SessionId] <string>] [<CommonParameters>]
A fully qualified connection command has the syntax like:
Connect-MDMApi -Namespace:"MyMDMserviceBus" -IssuerName:"MDMServiceIdentity" -IssuerKey:$SecureString
-RequestQueueName:"sdkRequest" -ResponseQueueName:"sdkResponse" -VERBOSE
Please note that the -IssuerKey (the 256bit symmetric key) must be maintained in a secure string object of PowerShell scripting – meaning it will be encrypted and cannot be used & decrypted by anything than the user who has created the secure string – you.
Lets try few Hello World type of samples
1. Reading all Leads that have been updated in the last days and simply out put the leads.
Get-MDMLeads [-BelongsToCompanyId <guid>] [-FromUpdateDate <datetime>] [-MaxNumberOfRecordsToGet <int>]
[-OriginOfChange <string>] [-MaxResponseWaitTime <int>] [<CommonParameters>]
$date = [System.DateTime]::Now.AddDays(-4).ToUniversalTime()
$leads = Get-MDMLeads -FromUpdateDate:$date
$leads
2. Adding a new marketing contact with parent marketing company under the assumption that we know the Id of the site company
(We assume knowledge of the External Id of the Site company. We will see later how to find the site company.)
Get-MDMCompany [[-CompanyId] <guid>] [-MaxResponseWaitTime <int>]
Add-MDMContact [[-Contact] <Contact>] [-DisableConcurrentRequestValidation <bool>] [-MaxResponseWaitTime <int>]
$SiteCompanyID="eddfce37-e3d9-4910-b0c4-f6979777dd07"
$belongsto = get-MDMCompany $SiteCompanyID -verbose
$error.Clear()
$contact = new-object Microsoft.Dynamics.Marketing.SDK.Model.Contact
$company = new-object Microsoft.Dynamics.Marketing.SDK.Model.Company
$company.Name = "Coolest Company On Planet Earth"
$company.IsMarketing = $true
$contact.BelongsToCompany = $belongsto
$contact.FirstName = "A First Name1"
$contact.LastName = "A Last Name1"
$contact.Company = $company
$contact.IsMarketing = $true
$newcontact = Add-MDMContact $contact -verbose
if($error.Count > 0)
{
$error
}
3. Let’s add a new lead to a know contact (like created above) and under a campaign and program. This sample shows also how to set fields like priority, status, sales rating, a custom origin of change, dates and even defines an initial score. The latter sill be overwritten as soon as lead get scored – if then a scoring model has been defined in the marketing context where the lead lands.
(We assume knowledge of Campaign Id and Program Id. These are the External Id)
$sitecompany="eddfce37-e3d9-4910-b0c4-f6979777dd07"
$programid="fba68e22-e822-4097-a40f-f244bb401736"
$campaignid="fcac690f-af01-43c0-9c9b-fda3b5ca8a9c"
$contactid = "6346d0e5-ec1c-4931-b63b-2f24b8666c23"
$program = new-object Microsoft.Dynamics.Marketing.SDK.Model.Program
$program.id = new-object Guid($programid)
$campaign = new-object Microsoft.Dynamics.Marketing.SDK.Model.Campaign
$campaign.id = new-object Guid($campaignid)
$lead = new-object Microsoft.Dynamics.Marketing.SDK.Model.Lead
$lead.Name="SDK test Lead 123"
$belongsto = Get-MDMCompany $sitecompany
$lead.BelongsToCompany = $belongsto
$contact = Get-MDMContact $contactid
$lead.Contact = $contact
$lead.Date=[System.DateTime]::Now.ToUniversalTime()
$lead.DueDate=$lead.Date.AddMonths(1)
$type = ("System.Collections.Generic.List"+'`'+"1") -as "Type"
$type = $type.MakeGenericType("system.string" -as "Type")
$origins = [Activator]::CreateInstance($type)
$origins.Add("Cool SDK")
$lead.OriginOfChanges=$origins
$lead.Score=999
$priorities = Get-MDMLeadPriorities
If ((-not ($priorities -eq $null)) , ($priorities.Count > 0))
{
$lead.Priority=$priorities[0]
}
$statuses = Get-MDMLeadStatuses
If ((-not ($statuses -eq $null)) , ($statuses.Count > 0))
{
$lead.Status=$statuses[0]
}
$salesRatings=Get-MDMSalesRatings
If ((-not ($salesRatings -eq $null)) , ($salesRatings.Count > 0))
{
$lead.SalesRating=$salesRatings[0]
}
$lead.Program = $program;
$lead.Campaign = $campaign;
$newLead = Add-MDMLead $lead
$newLead.Id
Scripting the OData endpoint
In order to connect with PowerShell to the OData endpoint you can use this command:
Add-PSSnapIn Microsoft.Dynamics.Marketing.OData
Connect-MDMOData`
-SeviceUrl:"https://YOURINSTANCE.marketing.dynamics.com"`
-RedirectUrl:"https://localhost"`
-OAuthTokenResourceName:"YOUR__REGISTERED_APPID" -verbose
Connect-MDMOData [[-SeviceUrl] <string>] [[-RedirectUrl] <string>] [[-AzureClientAppId] <string>] [-UserId <string>]
[-OAuthUrl <string>] [-OAuthTokenResourceName <string>] [<CommonParameters>]
The Service URL represents the root Url of your Dynamics Marketing instance, not the OData endpoint - so don’t bother adding the “/analytics”.
The RedirectUrl should typically be the “https://localhost”, which you have used when defining the app in Azure Active Directory (see here). And the AzureClientAppId is the Id of the app that you have created in Azure Active Directory.
Optionally you may pass the Sign-in User Id, if you want to default it for the login. The user still he must sign with his password.
The cmdlets for the OData endpoint provide Find functions in different flavors.
Find-MDMContacts [-BelongsToCompanyId <string>] [-Id <string>] [-IsActive <bool>] [-Email <string>]
[-FirstName <string>] [-LastName <string>] [-ChangedSince <datetime>] [-IsMarketing <bool>] [-IsClient <bool>]
[-IsVendor <bool>] [-IsStaff <bool>] [-Fields <string>] [-Filter <string>] [-OrderBy <string>] [-Expand
<string>] [-Top <int>] [-Skip <int>] [<CommonParameters>]
Find-MDMCompanies [-BelongsToCompanyId <string>] [-Id <string>] [-Name <string>] [-IsMarketing <bool>]
[-IsClient <bool>] [-IsVendor <bool>] [-IsSiteCompany <bool>] [-Fields <string>] [-Filter <string>] [-OrderBy
<string>] [-Expand <string>] [-Top <int>] [-Skip <int>] [<CommonParameters>]
Find-MDMLeads [-BelongsToCompanyId <string>] [-Id <string>] [-Name <string>] [-Status <string>] [-SalesReady
<bool>] [-MinScore <double>] [-Fields <string>] [-Filter <string>] [-OrderBy <string>] [-Expand <string>]
[-Top <int>] [-Skip <int>] [<CommonParameters>]
Find-MDMAnyData [[-TableName] <string>]
[-Fields <string>] [-Filter <string>] [-OrderBy <string>] [-Expand <string>] [-Top <int>] [-Skip <int>]
[<CommonParameters>]
The Find-MDMAnyData is the core cmd lets for finding records from any OData table which Dynamics Marketing exposes. You specify the table name, Fields to retrieve values for, an OData Filter string and sort fields to OrderBy. If you omit specifying the fields you are interested in, the call will load all columns.
The parameter “Top” allows to specify how many rows you want to retrieve from the top. Please note, if you do not specify a value by default in the comlet will try to load 10 rows. With the parameter “Skip” you can specify from where from top to start reading records. Parameters Top and Skip two together allow paging through your data, and you often will combine this with sorting and filtering.
This for example command will collect the last 100 Visits recorded:
$visits = Find-MDMAnyData -TableName:Visits -top:100 -OrderBy:"StartTime desc" –verbose
$visits
Expand is a more advanced option to include values from related objects into your result object. In the following sample we load programs and include the Program KPIs which deliver aggregated numbers for Expenses, Purchase Orders, Estimates, Invoices and more for different currencies.
$programs = Find-MDMAnyData -TableName:Programs -Expand:ProgramKPIs -verbose
$programs
Here is a simple way to find your Site company:
$comps = Find-MDMCompanies -Filter:"substringof('Site', Type) eq true" -verbose
$site = $comps[0]
$siteId = $site.Id
An example that used both OData and the SDK endpoint to create Leads
With the site company id at hand we for example can start browsing our marketing contact and run operations:
$pagesize = 100
$skip = 0
do
{
$contacts = Find-MDMContacts -BelongsToId:$siteId -Top:$pagesize -Skip:$skip
$skip += $contacts.Count
"Debug: Skip:" + $skip
#ProcessContacts($contacts)
}
while ($contacts.Count -ge 0)
In the sample below we start our journey with knowledge of the site company, a program and a campaign and then page through all contacts ad create leads for all contacts in a certain query.
$siteId = '[Assign Company.ExternalId]'
$programId = '[Assign Program.ExternalId here]'
$campaignId = '[Assign Campaign.ExternalId here]'
$belongsTo = Get-MDMCompany $siteId -verbose
$program = New-Object Microsoft.Dynamics.Marketing.SDK.Model.Program
$program.Id = $programId
$campaign = New-Object Microsoft.Dynamics.Marketing.SDK.Model.Campaign
$campaign.Id = $campaignId
$pagesize = 5
$skip = 30
$max = 5
$index = 0
do
{
$contacts = Find-MDMContacts -BelongsToId:$siteId -Top:$pagesize -Skip:$skip
foreach ($contact in $contacts)
{
$lead = new-object Microsoft.Dynamics.Marketing.SDK.Model.Lead
$lead.BelongsToCompany = $belongsTo
$lead.Name = "Initiative Lead N0." + $index
$ExId = $contact.Id
$sdkContact = Get-MDMContact -ContactId:$ExId
$lead.Contact = $sdkContact
$lead.Program = $program
$lead.Campaign = $campaign
$lead.Date=[System.DateTime]::Now.ToUniversalTime()
Add-MDMLead $lead
$index++
}
$skip += $contacts.Count
"Debug: Skip:" + $skip
#ProcessContacts($contacts)
}
while ($contacts.Count -ge 0)
With this blog post I wanted to give a quick glimpse into what is possible with the cmdlets for Dynamics Marketing OData endpoint and SDK. This topic certainly calls for more blog posts with practical sample applications. Stay tuned.
Enjoy!
Christian Abeln
Senior
Technorati Tags: Dynamics Marketing,SDK,OData,PowerShell
Program Manager
Microsoft Dynamics Marketing