10.3 Power Automate Expression Language (WDL / Functions)

Key Takeaways

  • Power Automate expressions use the Workflow Definition Language (WDL), evaluating functions, dynamic tokens, and literal values within action parameters.
  • The safe navigation operator '?' (e.g., body('Get_row')?['cr123_revenue']) prevents flow-crashing null reference exceptions when accessing optional or empty properties.
  • String functions (concat, substring, toLower, toUpper, trim, split, replace, guid) and Collection functions (first, last, length, empty, contains, union, intersection) provide robust manipulation without custom code.
  • Logical and comparison functions (if, equals, greater, less, and, or, not, coalesce) allow inline conditional evaluations and fallback value assignment.
  • Date/Time functions (utcNow, addDays, addHours, formatDateTime, convertTimeZone) handle timezone adjustments and ISO 8601 formatting critical for scheduled and enterprise workflows.
Last updated: August 2026

Power Automate Expression Language (WDL / Functions)

While Microsoft Power Automate provides an extensive visual designer with prebuilt dynamic content tokens, enterprise scenarios frequently require operations beyond basic token mapping: calculating future business dates, parsing complex text formats, evaluating inline ternary logic, coercing data types, and preventing null reference crashes. The underlying engine executes these calculations using the Workflow Definition Language (WDL).

For the PL-200: Microsoft Power Platform Functional Consultant certification exam, you must master the syntax, function taxonomy, safe navigation operators, and execution rules of the Power Automate expression engine.


1. Workflow Definition Language (WDL) Architecture

WDL is the declarative expression language powering Azure Logic Apps and Power Automate cloud flows. Expressions are entered via the Expression Builder tab in the dynamic content pop-up or written directly into flow definitions.

+-----------------------------------------------------------------------------+
|                        WDL EXPRESSION SYNTAX ANATOMY                        |
|                                                                             |
|   @concat('Account: ', toUpper(triggerOutputs()?['body/name']), ' (', guid(), ')')
|    |---|   |----------| |------| |----------------------------|       |----|
|    Prefix  Outer Func   Inner    Safe Navigation Token               Scalar|
|    (JSON)               Func     to Trigger Body Column              Func  |
+-----------------------------------------------------------------------------+

Core Syntax Principles

  1. Prefix Notation: Inside raw JSON definitions, expressions are prefixed with @ (e.g., @equals(...)). When using the visual Expression Builder GUI, the leading @ is omitted.
  2. Function Nesting: Functions can be nested infinitely (e.g., toUpper(trim(first(split(variables('FullName'), ' '))))).
  3. Case Sensitivity: Function names are case-insensitive in WDL (e.g., utcNow() and utcnow() are identical), but property schema names and dictionary keys are strictly case-sensitive.
  4. Action Name Formatting: When referencing action names containing spaces, replace the spaces with underscores (e.g., action Get customer record becomes outputs('Get_customer_record') or body('Get_customer_record')).

The Safe Navigation Operator: ?

In enterprise flows, data payloads often contain optional columns or null values. If an expression attempts to traverse a missing property using standard bracket syntax (e.g., body('Get_row')['address1_city']), and body('Get_row') is null or missing the property, the flow runtime crashes with an unhandled NullReferenceException.

The safe navigation operator (?) instructs the engine to return null rather than throwing an exception if the preceding object or property is undefined:

// Unsafe (Crashes if contact is null or missing telephone1):
outputs('Get_contact')['body']['telephone1']

// Safe Navigation (Evaluates cleanly to null if property is missing):
outputs('Get_contact')?['body']?['telephone1']
triggerOutputs()?['body/telephone1']

2. Referencing Trigger & Action Outputs

Function / SyntaxPurposeExample Syntax
triggerOutputs()Returns complete trigger output headers and bodytriggerOutputs()?['body/accountnumber']
triggerBody()Returns the trigger payload body directlytriggerBody()?['emailaddress1']
outputs('Action_Name')Returns headers and body of a completed actionoutputs('HTTP_Call')?['statusCode']
body('Action_Name')Returns the parsed body payload of an actionbody('Get_Account_Row')?['revenue']
item()References the current element in an Apply to each loopitem()?['primarycontactid']
items('Loop_Name')References current item of a specifically named loopitems('Apply_to_each_Order')?['total']
variables('VarName')Retrieves current value of an initialized variablevariables('varCounter')

3. Core WDL Function Taxonomy

+-----------------------------------------------------------------------------+
|                         WDL FUNCTION TAXONOMY                               |
|                                                                             |
|   +-----------------------+    +-----------------------+    +-----------+   |
|   |   STRING FUNCTIONS    |    | COLLECTION FUNCTIONS  |    |  LOGICAL  |   |
|   | - concat, substring   |    | - first, last, length |    | - if      |   |
|   | - toLower, toUpper    |    | - empty, contains     |    | - equals  |   |
|   | - trim, split, replace|    | - union, intersection |    | - greater |   |
|   | - guid, indexOf       |    | - take, skip          |    | - coalesce|   |
|   +-----------------------+    +-----------------------+    +-----------+   |
|               |                            |                            |   |
|               v                            v                            v   |
|   +-----------------------+    +----------------------------------------+   |
|   |  DATE & TIME FUNCS    |    |          CONVERSION FUNCTIONS          |   |
|   | - utcNow, addDays     |    | - string, int, float, bool             |   |
|   | - addHours, addMinutes|    | - json, xml, base64, base64ToString    |   |
|   | - formatDateTime      |    | - uriComponent, uriComponentToString   |   |
|   | - convertTimeZone     |    +----------------------------------------+   |
|   +-----------------------+                                                 |
+-----------------------------------------------------------------------------+

1. String Functions

FunctionSignature & BehaviorExample
concatCombines two or more strings into oneconcat('EMP-', string(101)) --> 'EMP-101'
substringExtracts characters: substring(text, startIndex, length)substring('PL-200 Exam', 0, 6) --> 'PL-200'
toLower / toUpperConverts text casingtoUpper('contoso') --> 'CONTOSO'
trimStrips leading and trailing whitespacetrim(' hello world ') --> 'hello world'
splitSplits string by delimiter into an arraysplit('red;green;blue', ';') --> ['red','green','blue']
replaceReplaces all occurrences of substringreplace('2026/08/17', '/', '-') --> '2026-08-17'
guidGenerates a new unique GUID stringguid() --> 'c7a8b3e1-9d24-4e89-b12a-8f9210a5b4c3'
indexOfReturns 0-based index of substring (-1 if not found)indexOf('admin@contoso.com', '@') --> 5

2. Collection & Array Functions

FunctionSignature & BehaviorExample
firstReturns the first element of an array or stringfirst(body('List_rows')?['value'])
lastReturns the last element of an array or stringlast(split('doc_v2_final.pdf', '.')) --> 'pdf'
lengthReturns item count in array or character count in stringlength(body('List_rows')?['value']) --> 45
emptyReturns true if array, string, or object is empty/nullempty(triggerOutputs()?['body/websiteurl'])
containsChecks if collection contains item or string contains substringcontains(variables('AdminList'), 'jsmith')
unionCombines two arrays/objects removing duplicate entriesunion(variables('TeamA'), variables('TeamB'))
intersectionReturns common elements present in both collectionsintersection(varRolesA, varRolesB)
takeReturns first N elements: take(collection, count)take(body('List_rows')?['value'], 10)
skipSkips first N elements and returns remainderskip(body('List_rows')?['value'], 10)

3. Logical & Comparison Functions

FunctionSignature & BehaviorExample
ifInline ternary conditional: if(expression, valueIfTrue, valueIfFalse)if(greater(variables('Score'), 700), 'Pass', 'Fail')
equalsStrict equality comparison returning booleanequals(triggerOutputs()?['body/statecode'], 0)
greater / lessRelational numerical/chronological comparisongreater(item()?['revenue'], 500000)
and / or / notCompound boolean logic evaluationand(equals(varTier, 'Gold'), not(empty(varEmail)))
coalesceEvaluates arguments left-to-right; returns first non-null/non-empty valuecoalesce(triggerOutputs()?['body/telephone1'], triggerOutputs()?['body/mobilephone'], 'No Phone')

[!IMPORTANT] The Power of coalesce on PL-200: coalesce is the definitive WDL function for establishing fallback values when querying Dataverse lookups or optional fields. If a contact record has mobilephone populated but telephone1 is null, coalesce(body('Get_contact')?['telephone1'], body('Get_contact')?['mobilephone'], 'N/A') immediately evaluates to the mobile number without requiring multiple nested Condition or if() actions.

4. Date and Time Functions

FunctionSignature & BehaviorExample Output
utcNow()Current timestamp in UTC ISO 8601'2026-08-17T13:30:00.0000000Z'
addDaysAdds/subtracts days: addDays(timestamp, days, format?)addDays(utcNow(), 30, 'yyyy-MM-dd')
addHours / addMinutesAdds/subtracts hours or minutes from timestampaddHours(utcNow(), -8)
formatDateTimeFormats ISO timestamp using standard .NET specifiersformatDateTime(utcNow(), 'MMMM dd, yyyy')
convertTimeZoneConverts timestamp between standard IANA/Windows time zonesconvertTimeZone(utcNow(), 'UTC', 'Eastern Standard Time', 'yyyy-MM-dd HH:mm')
ticksReturns 100-nanosecond tick count since 0001-01-01 (for date math)ticks('2026-08-17T00:00:00Z')

5. Type Conversion Functions

FunctionPurpose & Input TypeExample Conversion
stringConverts any scalar/object into string representationstring(1050.50) --> '1050.5'
intConverts string representation of number to 64-bit integerint('450') --> 450
floatConverts numeric string to floating-point numberfloat('19.99') --> 19.99
boolConverts string 'true' or 'false' to booleanbool('true') --> true
jsonParses raw JSON string into JSON object/arrayjson('{"id": 1}') --> {"id": 1}
base64Encodes string/binary into Base64 format (for email attachments)base64('Sample Text') --> 'U2FtcGxlIFRleHQ='
base64ToStringDecodes Base64 string back to plaintextbase64ToString('U2FtcGxl...') --> 'Sample Text'

4. Complex Nested Expression Patterns for PL-200

Pattern A: Extracting Email Domain for Dynamic Routing

// Input: 'sarah.connor@cyberdyne-systems.com'
// Expression: Extract substring after '@' and convert to lowercase
toLower(last(split(triggerOutputs()?['body/emailaddress1'], '@')))
// Evaluates to: 'cyberdyne-systems.com'

Pattern B: Calculating Dynamic Expiration Date in Local Time

// Calculate due date 14 days from now formatted for US Central Standard Time
formatDateTime(convertTimeZone(addDays(utcNow(), 14), 'UTC', 'Central Standard Time'), 'yyyy-MM-dd')

Pattern C: Safe Conditional Full Name Construction

// Build 'LastName, FirstName' if both exist, otherwise use whichever is populated
if(
  and(not(empty(triggerOutputs()?['body/lastname'])), not(empty(triggerOutputs()?['body/firstname']))),
  concat(triggerOutputs()?['body/lastname'], ', ', triggerOutputs()?['body/firstname']),
  coalesce(triggerOutputs()?['body/lastname'], triggerOutputs()?['body/firstname'], 'Valued Customer')
)
Test Your Knowledge

A cloud flow receives an incoming webhook containing an optional customer shipping address payload. The consultant writes the expression 'body('Parse_Webhook')['shippingAddress']['postalCode']' inside a Compose action. When an order arrives without a shipping address object, the flow execution fails with an 'ActionFailed - Cannot evaluate property on null object' error. How should the consultant update the expression to prevent this failure and return null safely?

A
B
C
D
Test Your Knowledge

An automated cloud flow must generate a dynamic reminder notification for invoices created in Dataverse. The flow must calculate a due date exactly 45 days after the current UTC execution time, convert the resulting timestamp to 'Pacific Standard Time', and format the output as 'yyyy-MM-dd'. Which WDL expression correctly achieves this?

A
B
C
D
Test Your Knowledge

A functional consultant needs to extract the top-level domain extension from an email address stored in the variable 'varEmail' (e.g., extracting 'org' from 'contact@charity.org' or 'com' from 'user@contoso.com'). Which expression returns the file extension or domain extension following the final period in the string?

A
B
C
D
Test Your Knowledge

A flow reads an employee record where the consultant needs to populate a greeting string. The flow must check 'preferredName'; if 'preferredName' is null or empty, it must fall back to 'firstName'; if 'firstName' is also null or empty, it must default to 'Colleague'. Which WDL function is the most concise and efficient way to implement this fallback logic?

A
B
C
D