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:

image image

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:"http://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 “http://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

Program Manager

Microsoft Dynamics Marketing

Follow My Curah!s on Microsoft Dynamics Marketing


Skip to main content