<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>LinkeD365 Blog</title><link>https://linked365.blog/</link><description>Recent content on LinkeD365 Blog</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Fri, 13 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://linked365.blog/index.xml" rel="self" type="application/rss+xml"/><item><title>PPTB - Metadata Browser</title><link>https://linked365.blog/metadatabrowser/</link><pubDate>Fri, 13 Feb 2026 00:00:00 +0000</pubDate><guid>https://linked365.blog/metadatabrowser/</guid><description>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-main.png" alt="Featured image of post PPTB - Metadata Browser" />&lt;p>Being involved from the outset of the &lt;a class="link" href="https://PowerPlatformToolBox.com" target="_blank" rel="noopener"
>https://PowerPlatformToolBox.com&lt;/a> has been hard work, tiring and worth every hour.&lt;/p>
&lt;p>To ensure the PPTB gets as much impetus as possible, providing equivalent tools as what is in the XrmToolBox was part of our goals. It is all very well to have a sexy looking multi-os framework, but without the core tools it would never take off.&lt;/p>
&lt;p>This is why the talented &lt;a class="link" href="https://www.linkedin.com/in/mohsin-mirza-94210615/" target="_blank" rel="noopener"
>Mohsin Mirza (MohsinoXrm)&lt;/a> has created the &lt;a class="link" href="https://www.powerplatformtoolbox.com/tools/e64db554-5dc9-4cc5-a712-832307d00777" target="_blank" rel="noopener"
>FetchXML Studio&lt;/a> and our glorious leader &lt;a class="link" href="https://www.linkedin.com/in/danishnaglekar/" target="_blank" rel="noopener"
>Danish Naglekar&lt;/a> has made the [PCF Builder](&lt;a class="link" href="https://www.powerplatformtoolbox.com/tools/" target="_blank" rel="noopener"
>https://www.powerplatformtoolbox.com/tools/&lt;/a>
fca7fd3c-54e1-4d2f-877c-ca29d1f4cd47)&lt;/p>
&lt;p>To that end, I have created &lt;a class="link" href="https://www.powerplatformtoolbox.com/tools/cbbb1649-3cc8-4c0f-9795-1ef64a1ab96d" target="_blank" rel="noopener"
>Metadata Browser&lt;/a>. Still going strong on the &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/MsCrmTools.MetadataBrowser/" target="_blank" rel="noopener"
>XrmToolBox&lt;/a> the legend that is &lt;a class="link" href="https://www.linkedin.com/in/tanguytouzard/" target="_blank" rel="noopener"
>Tanguy Touzard&lt;/a> created the original, and my version respectfully (with his permission) copies that with a reimagined interface to take advantage of the capabilities of the Electron PPTB, with a REact, Fluent based app with an &lt;a class="link" href="https://www.ag-grid.com/" target="_blank" rel="noopener"
>AG-Grid&lt;/a> grid to provide a performant interface.&lt;/p>
&lt;h2 id="using-the-tool">Using the tool&lt;/h2>
&lt;p>The tool is pretty (hopefully) self explanatory. Select a solution, or all tables and select a table for start looking at the various parts of the table as defined, whether it be fields, relationships, keys or everything else that is connected to a table.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-start.png"
loading="lazy"
alt="Image of the Metadata Browser top area"
>&lt;/p>
&lt;p>If you choose a solution, a drawer will appear allowing you select Managed or Unmanaged solutions in your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-solutionselector.png"
loading="lazy"
alt="Image of the Metadata Browser Solution Selector"
>&lt;/p>
&lt;p>The list of tables will then display all the tables associated with that solution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-tablelist.png"
loading="lazy"
alt="Image of the Metadata Browser Table screen"
>&lt;/p>
&lt;ol>
&lt;li>This icon opens the table as a new tab&lt;/li>
&lt;li>The grid is sortable and searchable&lt;/li>
&lt;li>You can add or remove columns to display in the list, displaying a popout like below&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-columnselection.png"
loading="lazy"
alt="Image of the Metadata Browser Column selection"
>&lt;/p>
&lt;ol>
&lt;li>Here you can add one more columns against the table. This applies to each subsequent tab, you can add columns to display further details on column attributes, relationships etc.&lt;/li>
&lt;li>Save updates the current list&lt;/li>
&lt;li>Set Default saves the configuration as your default next time you open the tool.&lt;/li>
&lt;/ol>
&lt;style type="text/css">.notice{--root-color:#444;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#c33;--warning-content:#fee;--info-title:#fb7;--info-content:#fec;--note-title:#6be;--note-content:#e7f2fa;--tip-title:#5a5;--tip-content:#efe}@media (prefers-color-scheme:dark){.notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}}body.dark .notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}.notice{padding:18px;line-height:24px;margin-bottom:24px;border-radius:4px;color:var(--root-color);background:var(--root-background)}.notice p:last-child{margin-bottom:0}.notice-title{margin:-18px -18px 12px;padding:4px 18px;border-radius:4px 4px 0 0;font-weight:700;color:var(--title-color);background:var(--title-background)}.notice.warning .notice-title{background:var(--warning-title)}.notice.warning{background:var(--warning-content)}.notice.info .notice-title{background:var(--info-title)}.notice.info{background:var(--info-content)}.notice.note .notice-title{background:var(--note-title)}.notice.note{background:var(--note-content)}.notice.tip .notice-title{background:var(--tip-title)}.notice.tip{background:var(--tip-content)}.icon-notice{display:inline-flex;align-self:center;margin-right:8px}.icon-notice img,.icon-notice svg{height:1em;width:1em;fill:currentColor}.icon-notice img,.icon-notice.baseline svg{top:.125em;position:relative}&lt;/style>
&lt;div>&lt;svg width="0" height="0" display="none" xmlns="http://www.w3.org/2000/svg">&lt;symbol id="tip-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"/>&lt;/symbol>&lt;symbol id="note-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="warning-notice" viewBox="0 0 576 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="info-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/>&lt;/symbol>&lt;/svg>&lt;/div>&lt;div class="notice note" >
&lt;p class="first notice-title">&lt;span class="icon-notice baseline">&lt;svg>&lt;use href="#note-notice">&lt;/use>&lt;/svg>&lt;/span>Note&lt;/p>&lt;p>The columns you select here also affect the columns exported for each tab. It does not impact the Excel export.&lt;/p>&lt;/div>
&lt;p>Selecting one of the tables opens that table as a new tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-tabledetails.png"
loading="lazy"
alt="Image of the Metadata Browser - Table details"
>&lt;/p>
&lt;ol>
&lt;li>Each table is added as another tab&lt;/li>
&lt;li>More tabs below give you further details for that table&lt;/li>
&lt;li>You can search to find an attribute.&lt;/li>
&lt;li>This button exports the details of the table, each tab has similar for the data shown.&lt;/li>
&lt;/ol>
&lt;p>Each sub tab (Columns, Keys, Relationships, Privileges and Solutions) will retrieve the relevant data from your environment, to quickly see the information that is stored in your system and export it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-exportallbutton.png"
loading="lazy"
alt="Image of the Metadata Browser = Excel export button"
>&lt;/p>
&lt;p>Selecting this option allows you to define which tabs will be created in an Excel report, with seperate sheets per option.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/metadatabrowser-exporttoexceldrawer.png"
loading="lazy"
alt="Image of the Metadata Browser - Excel export drawer"
>&lt;/p>
&lt;p>This will prompt you to save 1 Excel workbook per table.&lt;/p>
&lt;p>Please let me know if you have any issues or requests for improvements &lt;a class="link" href="https://github.com/LinkeD365/Metadata-Browser/issues" target="_blank" rel="noopener"
>Metadata Browser&lt;/a>&lt;/p></description></item><item><title>PPTB - Environment Manager</title><link>https://linked365.blog/EnvManager/</link><pubDate>Fri, 23 Jan 2026 00:00:00 +0000</pubDate><guid>https://linked365.blog/EnvManager/</guid><description>&lt;img src="https://linked365.blog/images/2026/envmanager-header.png" alt="Featured image of post PPTB - Environment Manager" />&lt;p>Much as I love XrmToolBox, and loved making tools for the toolbox, I have always thought that the visual aspect of the tools left some thing to be desired.
As it is based on WinForms technology, over 20 years old, it is from an era before my kids were born, suitable for us back then, with our long hair, leather jackets and mobile phones that didnt work and were the size of a brick.&lt;/p>
&lt;p>So, when &lt;a class="link" href="https://powermaverick.dev/" target="_blank" rel="noopener"
>Danish Naglekar&lt;/a> proposed late last year that we re-imagine the XTB, I jumped at the chance! If you haven&amp;rsquo;t seen the &lt;a class="link" href="https://www.powerplatformtoolbox.com/" target="_blank" rel="noopener"
>Power Platform ToolBox&lt;/a>, go download it, check it out and give us feedback!&lt;/p>
&lt;p>(Mostly I am excited by Dark Mode, but creating apps that use React/Fluent for wider use is exciting, and look great!)&lt;/p>
&lt;p>My first tool on the XTB was the &lt;a class="link" href="https://linked365.blog/OrgSettingsTool" target="_blank" rel="noopener"
>OrgSettings Tool&lt;/a>, a take on the solution that &lt;a class="link" href="https://github.com/seanmcne/OrgDbOrgSettings" target="_blank" rel="noopener"
>Sean McNellis&lt;/a> has made.&lt;/p>
&lt;p>If you are un-aware, there are several under the cover settings in your Power Platform environment that can alter the way some of the parts work, such as Server Side Sync, Security and other parts of a standard CRM environment. And, updating these settings is not a click in the admin centre.&lt;/p>
&lt;p>Whilst it is true to say, the product team are moving towards more clickable, or at least via the PAC CLI update of settings, these settings still keep getting added to and updated.&lt;/p>
&lt;p>With that said, I thought why not re-imagine the interface for it in the PPTB, hence I am proud to announce the Environment Manager in PPTB!&lt;/p>
&lt;h2 id="connecting-and-reviewing-your-settings">Connecting and Reviewing your settings&lt;/h2>
&lt;p>Environment Manager supports 2 connections, to compare environments. It will also work if you chose just one.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/EnVManager-Connection.png"
loading="lazy"
alt="Image of the connection tab for Environment Manager"
>&lt;/p>
&lt;p>For a single connection, you are presented with one column of values.
&lt;img src="https://linked365.blog/images/2026/envmanager-singledisplay.png"
loading="lazy"
alt="Image of Environment Manager with single connection"
>&lt;/p>
&lt;p>For multi connection, you are presented with 2 columns of values.
&lt;img src="https://linked365.blog/images/2026/envmanager-multidisplay.png"
loading="lazy"
alt="Image of the Environment Manager with multi connections"
>&lt;/p>
&lt;p>Here, you can sort, search and compare configuration settings across your environment(s).&lt;/p>
&lt;p>If you want to find out a little more information on the setting, there is a little i icon which will firstly show you information dragged from the Github repository, maintained by Sean.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/envmanager-addinfo.png"
loading="lazy"
alt="Image of the additional info popup"
>&lt;/p>
&lt;p>If I have added more info on my blog &lt;a class="link" href="https://linked365.blog/2019/10/01/d365-org-db-settings-email/" target="_blank" rel="noopener"
>here&lt;/a> this will be available in the LinkeD365 Info button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/envmanager-linked365info.png"
loading="lazy"
alt="Image of the LinkeD365 Info"
>&lt;/p>
&lt;h2 id="editing-a-variable">Editing a variable&lt;/h2>
&lt;p>On the left of the grid is a little pencil. Clicking on it enables the values to be changed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/envmanager-edit.png"
loading="lazy"
alt="Image of the edit pencil and save buttons"
>&lt;/p>
&lt;p>Once happy to update that value, hit the save button on top of the grid, which will give you a progress check and save back the configuration&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2026/envmanager-saving.png"
loading="lazy"
alt="Image of the edit pencil and save buttons"
>&lt;/p>
&lt;p>If you want to revert to the original value, hit the revert button.&lt;/p>
&lt;p>Thats it! Hope it helps someone.&lt;/p>
&lt;p>Please provide feedback and bugs on the GitHub repository &lt;a class="link" href="https://github.com/LinkeD365/PPTB-EnvManager/issues" target="_blank" rel="noopener"
>Env Manager&lt;/a>&lt;/p></description></item><item><title>6 Stages of Solution Deployment</title><link>https://linked365.blog/posts/EntDev/6StagesOfSolDev/</link><pubDate>Mon, 05 Feb 2024 00:00:00 +0000</pubDate><guid>https://linked365.blog/posts/EntDev/6StagesOfSolDev/</guid><description>&lt;img src="https://linked365.blog/images/2024/solution-deployment.png" alt="Featured image of post 6 Stages of Solution Deployment" />&lt;p>In my role, the ability to curate and control source code is essential. In the Enterprise Development space, the desire to put complicated, costly solutions in place to monitor the application and ensure that only quality, bug-free solutions are deployed is high. But, there is more than one way to ensure quality, there is more than one standard for quality, impacted by the requirement for each solution and your organisation’s approach to data and risk.&lt;/p>
&lt;p>In this post, I wanted to highlight what I see as the 6 (+ none) variations of code deployment, focus on how they apply to the Power Platform, and provide an insight into why your organisation should choose this way.&lt;/p>
&lt;p>Bear in mind, as has been said, the choice you make depends on your organisation, your maturity, your desire to control the amount of testing required, and your partner&amp;rsquo;s tools and abilities. What this does is give you much choice and a lot to consider.&lt;/p>
&lt;p>This is also solution-dependent. Do you want a full-blown, fully automated test coverage for a SharePoint app that your account administrator (👋 to Linda) made to simplify the invoice management process? Do you want no testing for your mission-critical, complicated solution across multiple domains or deep integrations between &lt;a class="link" href="posts/EntDev/composablearch" >composable applications&lt;/a>?&lt;/p>
&lt;h2 id="things-to-consider">Things to Consider&lt;/h2>
&lt;p>When you are deciding on what method works for your app, there are 4 options to consider. With any application, the levels of each can shift as the application matures. For example, a feature is added that effectively moves the needle on criticality to high, as it now is part of the core function; the complexity reduces as you have managed to bring the legacy application that needed APIs and service bus to integrate with into the main app.&lt;/p>
&lt;h3 id="criticality">Criticality&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/criticality-banner.png"
loading="lazy"
alt="Header image of Criticality highlight it is about your data or if your business would stop without the app"
>&lt;/p>
&lt;p>Define what the impact on your business would be if the application didn’t work. What is the data in the system worth to you if it is deleted or is shared? Less critical apps (for most businesses), such as Desk booking, recognition apps and simple improvements to email automation, do not have the same impact on your business on failure. Yes, it may be painful for a few, and harder work for a while, but your business will still operate.&lt;/p>
&lt;p>Consider your ERP system or your ability to stream video (for the Netflix/Amazon Prime’s of this world), if these go down, so does your business, making a financial loss for each minute that it is not available.&lt;/p>
&lt;p>What about your CRM or HR system? Probably not critical to run your business (you can still discuss opportunities, create service tickets, sell coffee or whatever you do, but the data it holds is very sensitive. Any data breach because of an app update could be business breaking, from a reputation point of view or a legal one, with GPDR and other considerations meaning your obligations to ensure the security of this data is critical to your organisation.&lt;/p>
&lt;h3 id="complexity">Complexity&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/complexity-banner.png"
loading="lazy"
alt="Header image of Complexity with image of juggler denoting you need to think about how many plates you are spinning"
>&lt;/p>
&lt;p>Define how complex your solution is. If there are a lot of moving parts that have to be aligned to ensure the application performs in the appropriate way, then it is essential to ensure your testing regime for all the constituent components is adequate enough to prevent data and functional issues.&lt;/p>
&lt;p>If you have a front-end portal, service broker and back-end database, aligning the functionality, data map and requirements for each is essential. Ensuring each knows about the additional field, what data type and how to use it when you deploy one of the parts will be necessary.&lt;/p>
&lt;p>These complex solutions tend to require full integration testing and full regression testing to ensure what has been added will not break any other functionality.&lt;/p>
&lt;h3 id="cost">Cost&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/cost-banner.png"
loading="lazy"
alt="Header image of Cost noting you should consider what else is needed to be paid for"
>&lt;/p>
&lt;p>Full testing every time you deploy an application is not only time-consuming, it can cost actual money. This is not only in the cost of the licensing or software but the infrastructure to run the operations.&lt;/p>
&lt;p>In the Power Platform, you have only so much capacity; this will have to be managed to prevent sprawling applications or increase the capacity you have available at an increased cost.&lt;/p>
&lt;p>There is also the time constraints. As your regression testing library grows, the time taken to deliver a project into an upstream environment can be detrimental to the SDLC you have deployed. When the testing is taking longer than the dev effort, you need to reconsider your strategy.&lt;/p>
&lt;h3 id="capability">Capability&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/Capability-banner.png"
loading="lazy"
alt="Header image of Capability noting it is an explanation of what skills your organisation needs"
>&lt;/p>
&lt;p>For Linda from accounts (a character that &lt;a class="link" href="https://twitter.com/ThatPlatformGuy" target="_blank" rel="noopener"
>Mr Huntingford&lt;/a> and I use to denote an IT literate, empowered app maker), solutions, environment strategy and ALM are not even words in her vocabulary. All Linda wants is to have the app she has made available to her colleagues in accounting.&lt;/p>
&lt;p>As your app complexity increases, the requirement for someone to configure and maintain deployment pipelines will increase, utilising the out-of-the-box &lt;a class="link" href="https://learn.microsoft.com/en-us/power-platform/alm/pipelines" target="_blank" rel="noopener"
>Power Platform pipelines&lt;/a> to full use of GitHub actions or Azure DevOps.&lt;/p>
&lt;p>Maintaining these processes in and of themselves can be a full-time role, particularly as more and more parts are added to the solution.&lt;/p>
&lt;h2 id="some-options-to-consider">Some Options to consider&lt;/h2>
&lt;h3 id="0---no-source-control-no-deployments">0 - No Source Control, no Deployments&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/0-NoALM.png"
loading="lazy"
alt="Diagram of no ALM process"
>&lt;/p>
&lt;p>Developing in production is normal; SharePoint, as an example, where you are editing lists, defining forms and doing so in the same environment as your users will be creating and editing data. Not to say there are mechanisms to put in ALM for SharePoint, but your usual developer will be updating and creating solutions in one environment.&lt;/p>
&lt;p>This will also apply to some Power Apps, anything you create in the default environment. You do have version control at this stage, being able to roll back versions of an app, but you are very limited.&lt;/p>
&lt;p>This state is only for personal productivity apps. Those that are very low on the complexity level, do not have any impact on your business (apart from an upset Linda 😘), come for free in terms of any additional cost and can be done by any app maker in your business&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/0-header.png"
loading="lazy"
alt="Diagram of the scores for No Source Control"
>&lt;/p>
&lt;h3 id="1---devprod-with-rudimentary-manual-deployments">1 - Dev/Prod with rudimentary, manual deployments&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/1-DevProd.png"
loading="lazy"
alt="Diagram of Dev/Prod with manual movement of application components"
>&lt;/p>
&lt;p>This is the first option where there is some thought: you have a dev environment separate from your app&amp;rsquo;s users. But simple deployments, copy/paste of list settings, duplication of configuration between two systems and, at the most, export of an app or one of its components and import into the higher environment. Your source control is the development environment, along with any files you have saved to move the apps to production.&lt;/p>
&lt;p>This will typically be where a citizen developer, directed by some control from your IT administrators starts. Apps that start and continue to be developed in the Personal Productivity environment are usually here.&lt;/p>
&lt;p>Again, this is not for critical apps. Don’t allow this simple process to happen for anything more than personal productivity, as the risk is too high with no control. Every app maker should be able to get behind this simple process, though, and there is minimal (Everyone can have a developer environment) cost to your organisation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/1-header.png"
loading="lazy"
alt="Diagram of the scores for rudimentary deployments"
>&lt;/p>
&lt;h3 id="2---devtestprod-with-solutions">2 - Dev/Test/Prod with solutions&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/2-DevTEstProdSol.png"
loading="lazy"
alt="Diagram of Dev/Test/Prod with manual movement of solutions"
>
Defining solutions, backed as you must with Dataverse, is probably the minimum you need to be doing for an app with more than a low criticality. Your solution control is still in versions of the solution you have saved in a file system, but you have a rollback via these.&lt;/p>
&lt;p>You also have the ability to create managed versions, controlling the changes that can be made in higher environments. This allows you to roll back with ease when something goes wrong.&lt;/p>
&lt;p>Your solutions are still moved and imported manually, and who ever is moving these solutions needs access to production, but business process in your organisation will decide when enough testing is done.&lt;/p>
&lt;p>DevOps, as a means of controlling the list of works, tends to start at this point. The use of a board to control the progress of stories and issues gives more visibility to the whole team, pushing away from the nightmare spreadsheet I remember in my early days.&lt;/p>
&lt;p>Most organisations will be utilising this as a standard when external or dedicated development projects exist. You will need the coordination and control managed solutions brings, at least knowing that you can revert back to the last know good state.&lt;/p>
&lt;p>With the introduction of solutions, a level of understanding and control needs to be added to your simple development process, which will minimally impact the complexity, cost and capability required.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/2-header.png"
loading="lazy"
alt="Diagram of the scores for Dev/Test/Prod with Solutions"
>&lt;/p>
&lt;h3 id="3---alm-with-solutions">3 - ALM with Solutions&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/3-ALMWithSolutions.png"
loading="lazy"
alt="Diagram of Dev/Test/Prod with Power Platform movement of solutions"
>&lt;/p>
&lt;p>As you get more complicated, this is where automation starts. Still working with solutions and the out-of-the-box tooling, you can put simple approval processes in place to control when solutions are moved to your other environments. This should be a business user or tester that has this approval.&lt;/p>
&lt;p>Utilising &lt;a class="link" href="https://learn.microsoft.com/en-us/power-platform/admin/managed-environment-overview" target="_blank" rel="noopener"
>Managed Environments&lt;/a> functionality, a simple DevOps &lt;a class="link" href="https://learn.microsoft.com/en-us/power-platform/alm/pipelines" target="_blank" rel="noopener"
>pipeline&lt;/a> can be created. It takes effort and administration, but it can also segment access to higher environments. The user that is running the deployment process and pushing the code to production does not have to be the developer.&lt;/p>
&lt;p>Managed Environments do allow you to trigger a Flow and work with more complex approvals and source code integrations, but not the complexity or control as shown in the next stage. These simplified pipelines also allow for prevalidation steps, including checks for dependencies, and environment variables. Versions of your applications are also stored as managed and unmanaged versions within the pipeline host environment.&lt;/p>
&lt;p>For most apps considered important to your organisations and need to separate access between development and production, this should be the starting point. The control presented, even though limited, allows approval automation, putting decisions to deploy away from a developer. Utilising Managed environments in itself does mean you need a license, but if you are using Dataverse in your solutions, this is part of the package. Somone does need to configure the pipeline, but as it is part of the application, it is a few clicks and decisions.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/3-header.png"
loading="lazy"
alt="Diagram of the scores for ALM with Solutions"
>&lt;/p>
&lt;h3 id="4---use-of-external-tooling">4 - Use of External Tooling&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/4-DevOpsALMwithSol.png"
loading="lazy"
alt="Diagram of Azure DevOps/Github pipelines"
>&lt;/p>
&lt;p>Azure DevOps, GitHub actions or any other ALM tooling provides a level of control that you don&amp;rsquo;t get in out-of-the-box tools. There are plenty of tutorials available on how you can create your own process.&lt;/p>
&lt;p>This allows a lot more flexibility to your ALM process and is the gateway to test automation. Azure DevOps and GitHub actions allow for periodic or multiple builds, which isn’t possible with the managed environment configurations.&lt;/p>
&lt;p>At this stage, you should not be utilising the solutions defined by your developers. This is where source control comes to the fore. Checking in the code, merging the components and then defining downstream builds from source control rather than solutions allows a granularity not achievable previously.&lt;/p>
&lt;p>Configuring these pipelines is time-consuming and needs a level of understanding different from Power Apps. People make great careers by specialising in DevOps. This, along with Azure DevOps or other tooling costs will add to your budget but brings more control and confidence in the build process.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/4-header.png"
loading="lazy"
alt="Diagram of the scores for ALM with Solutions"
>&lt;/p>
&lt;h3 id="5---full-alm-with-a-suite-of-tests">5 - Full ALM with a suite of Tests&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/5-ALMwithTest.png"
loading="lazy"
alt="Diagram of Azure DevOps/Github pipelines with Automated testing"
>&lt;/p>
&lt;p>Automatic testing is fundamental for most enterprise organisations, as it allows confidence that any improvements don’t break what has come before.&lt;/p>
&lt;p>Utilising regression test suites in your UAT environment or in an SIT (System Integration Testing) environment prior to UAT will reduce the risk of issues being found later down the chain. The only issue here is that you must maintain those test instructions while making changes to the codebase. If you have added a field to the view, the regression test to check the columns on the view needs updating. Adding a bit of logic or structure to a form will mean changing the script and checking that form over.&lt;/p>
&lt;p>The same goes for API calls and integrations; the expectations of the underlying code (date types and structures) will fundamentally change if you have introduced or changed an element.&lt;/p>
&lt;p>DevOps tooling from Automate tests with Azure Pipelines using classic editor - Power Apps | Microsoft Learn Microsoft is your starter here, as well as Playwright Automate tests with Azure Pipelines using classic editor - Power Apps | Microsoft Learn from Microsoft. Selenium has been the go to for some years and is pretty standard across most enterprises for web testing.&lt;/p>
&lt;p>This obviously adds an overhead to your dev cycle, as developers need to ensure they are communicating with the test team or maintaining the scripts themselves. Also, the time taken to run the scripts can affect how quickly a build can be pushed to production, with the knowledge that the likelihood of failure is significantly diminished when you get there.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/5-header.png"
loading="lazy"
alt="Diagram of the scores for ALM with Solutions"
>&lt;/p>
&lt;h3 id="6---enterprise-development">6 - Enterprise Development&lt;/h3>
&lt;p>&lt;img src="https://linked365.blog/images/2024/6-EntDev.png"
loading="lazy"
alt="Diagram of Enterprise pipelines with Automated testing"
>&lt;/p>
&lt;p>This is where it gets hard-core. Utilising aspects of everything, we are allowing multiple development streams, automation of development environments, and automation of code testing at the earliest stage available.&lt;/p>
&lt;p>Driven by Azure DevOps or a similar CI/CD platform, a developer will initiate an environment to add a new feature. They will update the Package Deployer template to automate the deployment of that feature (if necessary). All automated unit, integration, and acceptance tests will be written before a pull request is then created for the work.&lt;/p>
&lt;p>Pull requests will trigger a validation pipeline which will build and deploy the merge result of the developer’s branch with the main branch to a temporary test environment. All QA activities (including the execution of all automated tests) will happen in this environment before the feature is merged into the main branch. This ensures that every piece of work is independently regression tested and production-ready by the time it is merged. Deployments can happen to production anytime by taking any build from the main branch. Multiple releases can be supported easily with hotfixes as temporary environments can be created based on builds released into any environment (e.g. UAT or prod).&lt;/p>
&lt;p>At the far end of the ALM scale, the time and cost for this structure is significant. A DevOps expert will be required to create and maintain the pipelines. With validation in every PR, you add a time delay for the developer on checkin. You will also have a cost of the pipeline runs, and provisioning new environments can be expensive if you are at your user limit. These factors make this version only applicable to the mission critical projects, with numerous moving parts, to ensure the investment required can be recognised against the reduced risk of bugs creeping in.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/6-header.png"
loading="lazy"
alt="Diagram of the scores for Enterprise Development"
>&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>As you can see, there is a spectrum of options available to anyone considering developing solutions and managing their deployment. From none to a full suite of automation and testing, allowing multiple developers, multiple work streams, and full regression testing.&lt;/p>
&lt;p>Whilst there is never going to be a one-size-fits-all when it comes to CI/CD, I hope I have given you some thoughts to consider.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/solution-deployment.png"
loading="lazy"
alt="Diagram of the scoring altogether"
>&lt;/p>
&lt;p>This diagram consolidates all the considerations in one place. This really highlights how your thinking should be evolving as your application becomes more critical to your organisation.&lt;/p>
&lt;p>Special thanks to Max Ewing. He is the talent here. Max is a Senior Software Engineer at Capgemini and delivers Enterprise CI/CD for numerous clients. His continued push to improve the quality of our deliveries is beyond exemplary.&lt;/p></description></item><item><title>Flow Admin - Multiple Enable / Disable of Flows</title><link>https://linked365.blog/2024/01/07/flow-admin-multiple-enable-/-disable-of-flows/</link><pubDate>Sun, 07 Jan 2024 00:00:00 +0000</pubDate><guid>https://linked365.blog/2024/01/07/flow-admin-multiple-enable-/-disable-of-flows/</guid><description>&lt;img src="https://linked365.blog/images/2024/FlowAdmin-MultipleDisable.gif" alt="Featured image of post Flow Admin - Multiple Enable / Disable of Flows" />&lt;p>Just a quick post to highlight that the Flow Admin tool now allows you to enable and disable multiple flows at once.&lt;/p>
&lt;p>This update also aligns more with the OAuth login method and fixes some quirks with Solution selection.&lt;/p>
&lt;p>Get 1.2024.1.2 version of the tool at &lt;a class="link" href="https://www.xrmtoolbox.com/" target="_blank" rel="noopener"
>XrmToolBox&lt;/a> and let me know if you have any problems or think of things to add on &lt;a class="link" href="https://github.com/LinkeD365/Flow-Admin/issues" target="_blank" rel="noopener"
>GitHub&lt;/a>&lt;/p></description></item><item><title>Composable Architectures</title><link>https://linked365.blog/posts/EntDev/composablearch/</link><pubDate>Wed, 03 Jan 2024 00:00:00 +0000</pubDate><guid>https://linked365.blog/posts/EntDev/composablearch/</guid><description>&lt;img src="https://linked365.blog/images/2024/composablearch.gif" alt="Featured image of post Composable Architectures" />&lt;p>As an enterprise architect working with large, multi-national or multi-line of business organisations, ensuring that each application you create is part of the ecosystem, part of the whole, is essential.&lt;/p>
&lt;p>Every vendor has best-in-breed industry cloud applications, whether it is SAP or Power Platform, and large organisations use one, several or all of these in various ways. Whilst you could create one large solution, based on one architecture, it doesn’t mean you should. Every organisation has a sweet spot for which ERP suite suits them and which CRM or IoT vendor’s solution fits their requirements, driven by cost, technology and users, in an order or ratio defined by each organisation.&lt;/p>
&lt;p>When you have groups of organisations, whether that is in the same country with significantly different structures or drivers or multi-national businesses with slight variations due to tax, costs or other localised details, being flexible in your choices of point applications, with a basis of app integration is essential. This is where building a composable architecture as your core is essential.&lt;/p>
&lt;h2 id="an-overview">An Overview&lt;/h2>
&lt;p>Wikipedia defines &lt;a class="link" href="https://en.wikipedia.org/wiki/Composability" target="_blank" rel="noopener"
>Composablity&lt;/a> as&lt;/p>
&lt;blockquote>
&lt;p>Composability is a system design principle that deals with the inter-relationships of components. A highly composable system provides components that can be selected and assembled in various combinations to satisfy specific user requirements. In information systems, the essential features that make a component composable are that it be:&lt;/p>
&lt;p>• self-contained (modular): it can be deployed independently – note that it may cooperate with other components, but dependent components are replaceable&lt;/p>
&lt;p>• stateless: it treats each request as an independent transaction, unrelated to any previous request. Stateless is just one technique; managed state and transactional systems can also be composable, but with greater difficulty.&lt;/p>
&lt;p>It is widely believed that composable systems are more trustworthy than non-composable systems because it is easier to evaluate their individual parts.&lt;/p>
&lt;/blockquote>
&lt;p>To say it another way, I see it is similar to Lego, or any other building block toy you fancy. Like a honeycomb of interconnected solutions, it provides the opportunity to change one of the components with out impacting the whole.&lt;/p>
&lt;p>Imagine a small organisation, with an ERP, CRM, PoS and office systems. Each one is tightly coupled with the other as the business starts out, each one is pretty customised from it&amp;rsquo;s initial intention.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/composable-honeycombe1.png"
loading="lazy"
alt="Image showing initial set of apps for a small organisation"
>&lt;/p>
&lt;p>It comes to an inflexion point when the Loyalty system becomes cost-prohibitive or functionality inadequate and needs to be upgraded or expanded to accomodate true CRM functionality, such as Omnichannel or Marketing. Transformation of this one core part of the organisation is now restricted as we also need to change 3 different integrations.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/composable-honeycombe2.png"
loading="lazy"
alt="Image showing expanded set of apps for a medium organisation"
>&lt;/p>
&lt;p>As that application suite further expands, more change is needed to add in a proper CRM, Consumer research products and the like.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/composable-honeycombe3.png"
loading="lazy"
alt="Image showing expanded set of apps for a large organisation"
>&lt;/p>
&lt;p>In a composable architecture, each system has a common integration pattern, decoupled or divorced, from the main application. An integration layer, the purple in this diagram, adds the flexibility to integrate at will.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/composable-honeycombe4.png"
loading="lazy"
alt="Image showing expanded set of apps for a large organisation"
>&lt;/p>
&lt;p>A platform provides the integration between each application with a common, Industry-led data model. Replacing the CRM system now entails replacing the one set of integrations with the common standard, rather than the 4 previously.&lt;/p>
&lt;p>This platform is a solution in of itself, the glue linking each app, providing listeners and subscribers to data transaction, centred around your organisations view of data.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/composable-servicebus.png"
loading="lazy"
alt="Image showing expanded set of apps for a large organisation"
>&lt;/p>
&lt;p>Further, in a multi-business or multi-national organisation, separate entities could make their own choices on the systems they want to deploy, choosing the best fit for their particular needs. Starting with a chocolate box of choice of systems from your parent organisation you can swap out and add to as your business needs shift, underpinned with a common data and integration strategy.&lt;/p>
&lt;p>Expanding this analogy, if you want to introduce another actor in your ecosystem, implementing AI-led reporting, for example, you have a common starting point. Implement integrations between this norm rather than with all the other solutions. With the waves of technology coming faster and faster, the bedrock of a composable architecture is essential to ensure your business keeps up.&lt;/p>
&lt;h2 id="why">Why?&lt;/h2>
&lt;p>The why has already been stated, but to list them&lt;/p>
&lt;ul>
&lt;li>Flexibility – Quicker to swap in or add a new component to your company solution ecosystem without re-creating each integration.&lt;/li>
&lt;li>Freedom – Choose the best solution for your needs, don’t stick with one stack because you think you should, use best in breed for your price point.&lt;/li>
&lt;li>Stability – No dependency on one component&lt;/li>
&lt;/ul>
&lt;p>Most importantly, not everything will be suitable for your current technology stack. Don’t expect to re-invent the wheel each time in your low-code tool of choice, look at the market, what tools are your competitors using, what does Gartner say? Best in breed tools might not suit you right now, due to costs, talent, time etc, but be open to expanding your ecosystem if it makes technical sense, you have the skills required, matches your budget and will give you the ROI you need to improve your business.&lt;/p>
&lt;h2 id="steps-to-start">Steps to Start&lt;/h2>
&lt;h3 id="1define-your-data">1. Define your data&lt;/h3>
&lt;p>In the Power Platform world, there is a &lt;a class="link" href="https://learn.microsoft.com/en-us/common-data-model/%22" target="_blank" rel="noopener"
>Common Data Model&lt;/a> borne from Microsoft’s and Adobe’s partnership on common data patterns in the past. If you are coming from this stack, or any other, it is a great place to start.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2024/cdm-entities-v1.png"
loading="lazy"
alt="Image showing Microsoft&amp;rsquo;s Common Data Model"
>
Salesforce and SAP have their own variations on these, so depending on your core platforms, take their version as your starting point.&lt;/p>
&lt;p>What this gives you is a standard approach to most entities, such as account, contact or opportunity. Please, &lt;strong>please&lt;/strong> &lt;em>&lt;strong>please&lt;/strong>&lt;/em> don’t create another case/incident/request/certificate entity, re-use and relabel the standard one.&lt;/p>
&lt;p>These entities will have most of what your business needs – most organisations are not as unique as they think they are.
Using this base, create a model that is specific to your business. Have a shared understanding of what Account Number is for your business and how to associate contacts with cases. You should be creating data schemas in a functional or business focussed way, spreadsheets with columns and tables is just fine. A Visio with a visualisation of your ERD is enough to drive discussion and understanding.&lt;/p>
&lt;h3 id="2define-your-integration-layer">2. Define your integration layer&lt;/h3>
&lt;p>There are lots of ways to integrate systems, from Power Automate to Amazon Enterprise Service Bus or Boomi. Your integration layer choice will depend on your stack, like any business choice, but is crucial that it will meet your long term aims, as well as your first steps.
Power Automate can act like a bus, when a change is triggered in the source, make a change in the subscriber, but doesn’t have the complexities required for larger scale deployments.&lt;/p>
&lt;p>Azure Service Bus does pay as you go, Amazon has similar, which allows you to make those first movements. Using a bus will allow you to truly decouple your apps and the various subscribers that you will have.
Most people will also start with a central data repository as their first step. A data lake to hold the primary data versions for those entities that are shared across your organisation. Whilst this is not necessary, it opens up lots of opportunity for AI, BI and other intelligent operations.&lt;/p>
&lt;h3 id="3create-messages">3. Create messages&lt;/h3>
&lt;p>With your established organisation data model, create a message protocol for each and samples to aid understanding. Currently, this would be in JSON. Make sure you steer away from any alignment to one supplier, as these should be independent of the stack like the other components.
This will effectively be your start. Get ready for your first subscriber and publisher and test. Ensure you anticipate growth and capacity for your integration layer.&lt;/p>
&lt;h3 id="4enforce-decoupling">4. Enforce decoupling&lt;/h3>
&lt;p>If you don’t stop app devs directly integrating their SAP with the IoT solution they just purchased, Composability becomes as redundant as fax machines. Work with your technical leadership and product owners to drive understanding of the why and what of your architecture. Ensure you are augmenting your common data understanding with every new application, re-use what you have as much as possible and do any transformation specific to the new application rather than every integration you have already done.&lt;/p></description></item><item><title>Flow Administrator</title><link>https://linked365.blog/2023/12/18/flow-administrator/</link><pubDate>Mon, 18 Dec 2023 00:00:00 +0000</pubDate><guid>https://linked365.blog/2023/12/18/flow-administrator/</guid><description>&lt;img src="https://linked365.blog/images/2023/FlowAdmin.gif" alt="Featured image of post Flow Administrator " />&lt;p>This tool is a long time coming, and hope it helps anyone that is a clicky admin rather than PAC CLI&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>A new tool to administer your Power Automate flows - change owner, enable/disable etc.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>The screen is split into 3 main areas, as highlighted below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/1-FlowAdmin-MainScreen.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the main screen of Flow Admin Tool"
>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>List of all the flows in your environment, either in dataverse or outside via the Power Automate API&lt;/p>
&lt;/li>
&lt;li>
&lt;p>List of the Flow Runs - select Running, Succeeded, Cancelled, Failed or All.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://linked365.blog/images/2023/2-RunsMenu.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the options for the Flow Runs"
>&lt;/p>
&lt;ol start="3">
&lt;li>List of the Flow Owners&lt;/li>
&lt;/ol>
&lt;p>To get to this point, you need the app to have access to your Power Platform instance (via Dataverse or Flow API), the Flow API (for owners and updating) and Graph API (to get new owners etc). This is detailed in the Connecting to the APIs section below.&lt;/p>
&lt;h2 id="changing-a-flow-owner">Changing a Flow Owner&lt;/h2>
&lt;p>Select a flow in the left hand side.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/3-OwnersFunctionality.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the options for the Flow Owner"
>&lt;/p>
&lt;p>Once connected, in the right hand pane (1) you will see the current owners, you can click on the dustbin to remove the owner. Only owners which you can remove (not the creator of the flow) will be enabled for removal.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/4-RemoveOwnerConfirmation.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the remove owner confirmation message box"
>&lt;/p>
&lt;p>If you need to add an owner, click on the Add Owner button&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/5-AddOwnerDialog.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the add owner message box"
>&lt;/p>
&lt;p>This little dialog allows you to add one or more owners, after you have confirmed you are happy with it.&lt;/p>
&lt;h2 id="enabledisable-a-flow">Enable/Disable a Flow&lt;/h2>
&lt;p>Frequently, there is a need to disable a flow. Troublesome flows or just those that you no longer need, can be disabled or re-enabled once you are in a position to do so.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/6-DisableCancelOptions.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the disable/enable button and Cancel Flow Runs"
>&lt;/p>
&lt;p>The Enable/Disable button (1) will toggle depending on the current state of the flow selected.&lt;/p>
&lt;h2 id="cancel-flow-runs">Cancel Flow Runs&lt;/h2>
&lt;p>Flow runs in them selves can be problematic. Recurring flows that run away from themselves creating thousands of runs. These can then be cancelled in a couple of clicks by pressing the Cancel button and choosing to cancel all &amp;ldquo;Running&amp;rdquo; runs or those you have selected in the Runs grid.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/7-CancelRunsSelection.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the Cancel Runs popup"
>&lt;/p>
&lt;h2 id="demo">Demo&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowAdmin.gif?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="GIF showing the various options for Flow Admin"
>&lt;/p>
&lt;h2 id="connecting-to-the-apis">Connecting to the APIs&lt;/h2>
&lt;p>Most XrmToolBox tools are directly connected to your Dataverse environment, with the Flow Admin, the tool is reliant on the Power Automate API (to enable/disable as well as flow runs) as well as the &lt;a class="link" href="https://developer.microsoft.com/en-us/graph/rest-api" target="_blank" rel="noopener"
>Graph API&lt;/a> to retrieve properties of the new owners.&lt;/p>
&lt;p>Utlising these APIs requires a little more work and potentially a friendly Azure Administrator. What ever happens, you are utlising OAuth credentials to connect, so any user will only see and administer the flows they have access to.&lt;/p>
&lt;h3 id="configure-access-to-flow-api">Configure access to Flow API&lt;/h3>
&lt;p>When you click on the Connect to Flow API button or if you select one of the Flows in a list from Dataverse, you are presented with the FLow API connection dialog. Each one of these fields filling to allow you to connect to your environment&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/8-FlowAPIConnectionDialog.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the Flow Admin Connection Dialog"
>&lt;/p>
&lt;ol>
&lt;li>
&lt;p>This adds a configuration to the list (or removes the current one). Once saved, these connections are saved in a config file to retrieve next time round.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The next is a label for the connection, as you can have more&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The next field is the Client or App Id. These can be configured if you want to non-dev settings by creating an app registration&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>This is documented &lt;a class="link" href="https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app" target="_blank" rel="noopener"
>Here&lt;/a>&lt;/p>
&lt;p>You do need Read access to all flows in your configuration (if you want to override th permissions a user has normally)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-10.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the Read permissions for access to the Flow API"
>&lt;/p>
&lt;p>Once configured, back on the App registration, the image below highlights what needs mapping to the fields above&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/10-AzureConfig.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the values to fill in the Power Automate API"
>&lt;/p>
&lt;ol start="4">
&lt;li>
&lt;p>Tenant ID is in the list above too, if you are on that screen. Otherwise, it is on the main Azure Portal under Tenant Properties.&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Environment ID is next, which is retrieval by selecting the Developer Resources panel in any environment&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>&lt;img src="https://linked365.blog/images/2023/11-EnvId.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the Developer Information panel and the Environment ID"
>&lt;/p>
&lt;ol start="6">
&lt;li>
&lt;p>Return URL is part of the App Registration, and tends to be localhost&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Use Dev settings allows you to ease your pain and shortcut the issues somewhat. Highlighted &lt;a class="link" href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/xrm-tooling/use-connection-strings-xrm-tooling-connect" target="_blank" rel="noopener"
>here&lt;/a>, Microsoft allows you to their app registration, but then use OAuth to do the authentication. Makes life simpler and fills out the Return URL &amp;amp; App Id boxes. THis means you don&amp;rsquo;t need an app registration at all, if you have the appropriate admin rights on your system.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;p>Once you are set, you will be prompted to sign in using OAuth2, with a popup to add your credentials and MFA if enabled. Standard logging in stuff.&lt;/p>
&lt;h3 id="configure-access-to-graph-api">Configure Access to Graph API&lt;/h3>
&lt;p>Graph API is used to get the owner information and look for new owners. In Dataverse, this can be taken from the User table, but outside of Solutioned flows, you have to use Graph. This configuration is very similar to Power Automate API.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/12-GraphAPIConfig.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the values to fill in the Graph API"
>&lt;/p>
&lt;ol>
&lt;li>This adds a configuration to the list (or removes the current one). Once saved, these connections are saved in a config file to retrieve next time round.&lt;/li>
&lt;li>The next is a label for the connection, as you can have more&lt;/li>
&lt;li>This is the subsription we are working with. I am not sure this is needed, but need to check.&lt;/li>
&lt;li>This is the Client ID/ App Id, taken from when you register a App, as before.&lt;/li>
&lt;/ol>
&lt;p>You do need to ensure the app registration includes User.Read&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/13-GraphPermissions.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
alt="Image showing the permissions needed for app registration connected to the Graph API"
>&lt;/p>
&lt;p>&lt;style type="text/css">.notice{--root-color:#444;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#c33;--warning-content:#fee;--info-title:#fb7;--info-content:#fec;--note-title:#6be;--note-content:#e7f2fa;--tip-title:#5a5;--tip-content:#efe}@media (prefers-color-scheme:dark){.notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}}body.dark .notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}.notice{padding:18px;line-height:24px;margin-bottom:24px;border-radius:4px;color:var(--root-color);background:var(--root-background)}.notice p:last-child{margin-bottom:0}.notice-title{margin:-18px -18px 12px;padding:4px 18px;border-radius:4px 4px 0 0;font-weight:700;color:var(--title-color);background:var(--title-background)}.notice.warning .notice-title{background:var(--warning-title)}.notice.warning{background:var(--warning-content)}.notice.info .notice-title{background:var(--info-title)}.notice.info{background:var(--info-content)}.notice.note .notice-title{background:var(--note-title)}.notice.note{background:var(--note-content)}.notice.tip .notice-title{background:var(--tip-title)}.notice.tip{background:var(--tip-content)}.icon-notice{display:inline-flex;align-self:center;margin-right:8px}.icon-notice img,.icon-notice svg{height:1em;width:1em;fill:currentColor}.icon-notice img,.icon-notice.baseline svg{top:.125em;position:relative}&lt;/style>
&lt;div>&lt;svg width="0" height="0" display="none" xmlns="http://www.w3.org/2000/svg">&lt;symbol id="tip-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"/>&lt;/symbol>&lt;symbol id="note-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="warning-notice" viewBox="0 0 576 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="info-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/>&lt;/symbol>&lt;/svg>&lt;/div>&lt;div class="notice info" >
&lt;p class="first notice-title">&lt;span class="icon-notice baseline">&lt;svg>&lt;use href="#info-notice">&lt;/use>&lt;/svg>&lt;/span>Info&lt;/p>&lt;p>As with all access and configuration, check with your Entra Administrator first&lt;/p>&lt;/div>
5. Tenant ID is in the list above too, if you are on that screen. Otherwise, it is on the main Azure Portal under Tenant Properties.&lt;/p>
&lt;ol start="6">
&lt;li>
&lt;p>Return URL is part of the App Registration, and tends to be localhost&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Use Dev settings allows you to ease your pain and shortcut the issues somewhat. Highlighted &lt;a class="link" href="https://learn.microsoft.com/en-us/power-apps/developer/data-platform/xrm-tooling/use-connection-strings-xrm-tooling-connect" target="_blank" rel="noopener"
>here&lt;/a>, Microsoft allows you to their app registration, but then use OAuth to do the authentication. Makes life simpler and fills out the Return URL &amp;amp; App Id boxes. THis means you don&amp;rsquo;t need an app registration at all, if you have the appropriate admin rights on your system.&lt;/p>
&lt;/li>
&lt;/ol>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>So, where does the tool go from here? I have plans to make the add/remove owners and disable multi flows at once. There is also lots of extra bits that you can do via the Power Platform CLI &lt;a class="link" href="https://learn.microsoft.com/en-us/power-platform/developer/cli/introduction" target="_blank" rel="noopener"
>descibed here&lt;/a> that I should be able to include. &lt;a class="link" href="https://twitter.com/laskewitz" target="_blank" rel="noopener"
>Daniel Laskewitz&lt;/a> is doing a great job on guiding the development, but I am more of a clicky person.&lt;/p>
&lt;p>&lt;a class="link" href="https://github.com/LinkeD365/Flow-Admin/issues" target="_blank" rel="noopener"
>Let me know&lt;/a> what feature you need as well. Can&amp;rsquo;t promise to do it, but hey, do it yourself and create a pull request so we can share with the world!&lt;/p></description></item><item><title>Flow to Visio - Run History and Cancel Active Runs</title><link>https://linked365.blog/2023/03/12/flow-to-visio-run-history-and-cancel-active-runs/</link><pubDate>Sun, 12 Mar 2023 00:00:00 +0000</pubDate><guid>https://linked365.blog/2023/03/12/flow-to-visio-run-history-and-cancel-active-runs/</guid><description>&lt;img src="https://linked365.blog/images/2023/FlowToVisio-Cancelling.gif" alt="Featured image of post Flow to Visio - Run History and Cancel Active Runs" />&lt;p>Now and again a mistake at work triggers a solution. I inadvertently created a flow that was triggering too often, creating thousands of runs which only materialised in a testing environment.&lt;/p>
&lt;p>I have then realised there is no easy way to cancel thousands of flow runs. The standard solution only allows you to cancel 20 at a time. There is a &lt;a class="link" href="https://www.cloudfronts.com/power-automate/cancel-the-running-flows-with-javascript-code/" target="_blank" rel="noopener"
>JavaScript&lt;/a> and &lt;a class="link" href="https://ashiqf.com/2021/05/16/cancel-all-your-running-power-automate-flow-runs-using-m365-cli-and-rest-api/" target="_blank" rel="noopener"
>via PowerShell&lt;/a> methods, but surely there should be a way with your indispensable Swiss Army Knife &lt;a class="link" href="https://www.xrmtoolbox.com" target="_blank" rel="noopener"
>XrmToolBox&lt;/a>&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I have introduced a flow history button to allow display listing of the flow runs as well as the ability to cancel one or more runs.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>If you have connected to Dataverse or Flow API, there is now a new History column on the grid view.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowListwithHIstory.png"
loading="lazy"
alt="Image showing new History button on Flow To Visio tool"
>&lt;/p>
&lt;p>Clicking on the icon will prompt you to confirm the settings for access to the API. This is the same if you have looked at non-solutioned flows, the steps are show in the original article &lt;a class="link" href="http://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/#connect-to-power-automate-api" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;p>Once you have connected, wait for the api to do it&amp;rsquo;s magic &amp;amp; retrieve all the runs (in the last 30 days).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/LoadingRuns.png"
loading="lazy"
alt="Image showing loading runs"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowRunsDialog.png"
loading="lazy"
alt="Image showing all the flow runs"
>&lt;/p>
&lt;h3 id="cancelling-flow-runs">Cancelling Flow Runs&lt;/h3>
&lt;p>Select one or more flow runs, then hit the cancel button&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/CancelInstructions.png"
loading="lazy"
alt="Image showing instructions to cancel a flow"
>&lt;/p>
&lt;p>The main tool window will then show you progress,&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/CancelFlowProgress.png"
loading="lazy"
alt="Image showing cancelling flow progress"
>&lt;/p>
&lt;p>with the main window refreshed to display the current status&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/CancelledFlows.png"
loading="lazy"
alt="Image showing refreshed flow runs"
>&lt;/p>
&lt;p>I created a short gif highlighting the change&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowToVisio-Cancelling.gif"
loading="lazy"
alt="GIF showing changes to the tool"
>&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>This part of the tool is quite seperate to the Visio, only combined as I have done lots of the hard work in the original, easier to add than create again.&lt;/p>
&lt;p>I intend to split out and enhance the colour coding output. Any errors/enhancements, please log them on GitHub &lt;a class="link" href="https://github.com/LinkeD365/FlowToVisio/issues" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;p>Thanks to Mohamed Ashiq Faleel and his &lt;a class="link" href="https://ashiqf.com/2021/05/16/cancel-all-your-running-power-automate-flow-runs-using-m365-cli-and-rest-api/" target="_blank" rel="noopener"
>article&lt;/a> highlight the API calls needed.&lt;/p></description></item><item><title>Flow to Visio - Solutions</title><link>https://linked365.blog/2023/02/19/flow-to-visio-solutions/</link><pubDate>Sun, 19 Feb 2023 00:00:00 +0000</pubDate><guid>https://linked365.blog/2023/02/19/flow-to-visio-solutions/</guid><description>&lt;img src="https://linked365.blog/images/2023/FlowSolutions.gif" alt="Featured image of post Flow to Visio - Solutions" />&lt;p>I have finally found some time to work on my tools, and have added a request from &lt;a class="link" href="https://www.linkedin.com/in/themarkchristie/" target="_blank" rel="noopener"
>Mark Christie&lt;/a> to the &lt;a class="link" href="https://linked365.blog/FlowToVisio" >Flow to Visio tool&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I have added solution selection to the Flow to Visio tool &amp;amp; added a few new actions.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>If you have connected to Dataverse, there is now a new selection listing all the solutions in your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowtoVisio-solutionselection.png"
loading="lazy"
alt="Image showing Solution selection in Flow to Visio Tool"
>&lt;/p>
&lt;p>The flow list is then restricted to those that are part of the solution file. Selecting the top left will select all that are part of that solution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowtoVisio-filtered.png"
loading="lazy"
alt="Image showing reduced list of flows"
>&lt;/p>
&lt;p>When you hit Create Visio, the default name is the name of the solution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowtoVisio-Filedialog.png"
loading="lazy"
alt="Image showing save dialog box"
>&lt;/p>
&lt;p>Finally, the Visio is created with each select flow in a new tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowtoVisio-Visio.png"
loading="lazy"
alt="Image showing multiple tabs in Visio, one for each Power Automate selected"
>&lt;/p>
&lt;p>I created a short gif highlighting the change&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2023/FlowSolutions.gif"
loading="lazy"
alt="GIF showing changes to the tool"
>&lt;/p></description></item><item><title>A New Look</title><link>https://linked365.blog/2023/02/15/a-new-look/</link><pubDate>Wed, 15 Feb 2023 00:00:00 +0000</pubDate><guid>https://linked365.blog/2023/02/15/a-new-look/</guid><description>&lt;img src="https://linked365.blog/images/2023/darklight.png" alt="Featured image of post A New Look" />&lt;p>I have been getting reminders that the 3 year payment plan I had for my blog was getting renewed at the end of this month, and when I looked into it, wow that stuff is expensive.&lt;/p>
&lt;p>I know you get what you pay for, I work with Dynamics 365 &amp;amp; Power Platform and I am always pushing people to recognise the worth of a premium product.&lt;/p>
&lt;p>But, if I can save some of my kids inheritence, I will.&lt;/p>
&lt;p>So, I have copied &lt;a class="link" href="crmchap.co.uk" >Joe Griffin&lt;/a> (literally, if you havent noticed, just tweaked some colours) and created this new site as an &lt;a class="link" href="https://learn.microsoft.com/en-gb/azure/static-web-apps/overview?WT.mc_id=M365-MVP-5004075" target="_blank" rel="noopener"
>Azure Static Web App&lt;/a>, using &lt;a class="link" href="https://gohugo.io/" target="_blank" rel="noopener"
>Hugo&lt;/a> and a theme by Jimmy called &lt;a class="link" href="https://github.com/CaiJimmy/hugo-theme-stack" target="_blank" rel="noopener"
>Stack&lt;/a>&lt;/p>
&lt;p>I love the dark/light versions, the cleaniness and simplicity. I just have to get used to Markdown now.&lt;/p>
&lt;p>Please let me know when you fine some issues or something missing. The blog is a low priority around work, life, family, tools but at least it is a place to keep my stuff in one place.&lt;/p>
&lt;h2 id="acknowledgements">Acknowledgements&lt;/h2>
&lt;p>Mostly Joe was the help &amp;amp; inspiration and pointed me at the other bits.&lt;/p>
&lt;ul>
&lt;li>Joe Griffin for his &lt;a class="link" href="https://crmchap.co.uk/ive-thrown-away-my-wordpress-site-heres-why/" target="_blank" rel="noopener"
>article&lt;/a> explaining the process and some sage advise to just bite the bullet.&lt;/li>
&lt;li>Kendra Little for her &lt;a class="link" href="https://www.littlekendra.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/#overview-of-my-static-site-setup" target="_blank" rel="noopener"
>article&lt;/a> on setting this all up.&lt;/li>
&lt;li>lonekorean’s &lt;a class="link" href="https://github.com/lonekorean/wordpress-export-to-markdown" target="_blank" rel="noopener"
>Wordpress-export-to-markdown Tool&lt;/a> essential to ease the migration of articles from the old site.&lt;/li>
&lt;li>CaiJimmy’s &lt;a class="link" href="https://www.littlekendra.com/2021/05/03/moving-from-wordpress-to-an-azure-static-site-with-hugo/#overview-of-my-static-site-setup" target="_blank" rel="noopener"
>hugo-theme-stack Theme&lt;/a> I have made my own branch of this great work, to allow the tweaks in color schemes.&lt;/li>
&lt;/ul></description></item><item><title>BPFs to Visio - XrmToolBox tool</title><link>https://linked365.blog/2022/02/22/bpfs-to-visio-xrmtoolbox-tool/</link><pubDate>Tue, 22 Feb 2022 00:00:00 +0000</pubDate><guid>https://linked365.blog/2022/02/22/bpfs-to-visio-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2022/bpftovisio.png" alt="Featured image of post BPFs to Visio - XrmToolBox tool" />&lt;p>You have &lt;a class="link" href="https://twitter.com/Themarkchristie" target="_blank" rel="noopener"
>@TheMarkChristie&lt;/a> to blame for this. I have shied away from creating a tool that documented your Business Process Flows for a while. You would think it was easier than Power Automate documentation but the inconsistencies and difficulties in the format of the XML that is the BPF is quite something. Persumambly, it is logic Microsoft has just added to over the years.&lt;/p>
&lt;p>But, yep, it is done. BPF to Visio! Available in &lt;a class="link" href="http://xrmtoolbox.com" target="_blank" rel="noopener"
>XrmToolBox&lt;/a> alongside other great tools and my own.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/bpftovisio-1024x481.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>&lt;a class="link" href="https://twitter.com/Themarkchristie" target="_blank" rel="noopener"
>@MarkChristie&lt;/a> asked me to make a tool that created Visio documents out of a Business Process Flow and now you use it to hopefully save you minutes documenting your solutions.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>On opening the tool, you will be presented with a list of BPFs that are in your environment. Select one or more BPFs and select the Create Visio button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/bpftovisio2-1024x721.png"
loading="lazy"
>&lt;/p>
&lt;p>Select a file to save it as, and once it churns, it will prompt you if you want to open Visio.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/image.png"
loading="lazy"
>&lt;/p>
&lt;p>Opening Visio, you are presented with your BPF.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/image-1-1024x476.png"
loading="lazy"
>&lt;/p>
&lt;p>Like my other Visio Tools, there needs to be some adjusting once complete. It is very difficult to ensure in recursive code that you don&amp;rsquo;t have any children and I struggled to align accurately as you can see above.&lt;/p>
&lt;p>Take a little minute to adjust the alignment to suit your needs, including expanding some of the stages etc.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/image-2-1024x437.png"
loading="lazy"
>&lt;/p>
&lt;p>You can see I have documented the data, flow &amp;amp; workflow steps in each stage &amp;amp; the conditions.&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>Download the tool via XrmToolBox and let me know your thoughts on the socials. I have only got limited access to BPFs so I am sure I have not covered all possibilities, so expect bugs.&lt;/p>
&lt;p>Raise bugs &amp;amp; enhancements on GitHub &lt;a class="link" href="https://github.com/LinkeD365/BPFToVisio" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p></description></item><item><title>AZ-900 - Azure Fundamentals</title><link>https://linked365.blog/2022/01/09/az-900-azure-fundamentals/</link><pubDate>Sun, 09 Jan 2022 00:00:00 +0000</pubDate><guid>https://linked365.blog/2022/01/09/az-900-azure-fundamentals/</guid><description>&lt;img src="https://linked365.blog/images/2022/01image.png" alt="Featured image of post AZ-900 - Azure Fundamentals" />&lt;p>As a Power Platform / D365 solution architect a lot of the time you are being asked to think about integrations and creating applications on the outside of the core platform. Azure, for the most part, is the place where we will go to host external integrations and apps and is a smorgasbord of services to assist in making great applications.&lt;/p>
&lt;p>To keep myself progressing, I wanted to test my knowledge on Azure, and learn some of the fundamentals for the services or configurations that I have not come across (looking at you &lt;a class="link" href="https://azure.microsoft.com/en-gb/services/azure-sphere/" target="_blank" rel="noopener"
>Azure Sphere&lt;/a>).&lt;/p>
&lt;p>As usual, I made a &lt;a class="link" href="https://coggle.it/diagram/YcMd5NuO1etoetZZ/t/az-900-azure-fundamentals/dad22ede130357c153d2819a941ea68238b3726bbd9f49eb0070373bb432faeb" target="_blank" rel="noopener"
>mind map&lt;/a>. These visual representations are an aide-mémoire for me, forcing a commitment to memory by writing down key points and a quick way of reviewing before the exam. No guarantee of accuracy or completeness is inferred, if it triggers in you something that you didn&amp;rsquo;t know or forgotten, that is enough.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I did the &lt;a class="link" href="https://docs.microsoft.com/en-gb/learn/certifications/azure-fundamentals/" target="_blank" rel="noopener"
>Azure Fundamentals exam&lt;/a> &amp;amp; made a &lt;a class="link" href="https://coggle.it/diagram/YcMd5NuO1etoetZZ/t/az-900-azure-fundamentals/dad22ede130357c153d2819a941ea68238b3726bbd9f49eb0070373bb432faeb" target="_blank" rel="noopener"
>mind map&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2022/microsoft-certified-azure-fundamentals.png"
loading="lazy"
alt="Image showing Azure Fundamentals Badge"
>&lt;/p>
&lt;h2 id="my-thoughts">My Thoughts&lt;/h2>
&lt;p>For a fundamentals exam, I found the topic wide-reaching, touching every part of Azure. I assume that this is because of my lack of experience in various parts of the vast eco-system that is Azure. You do need to cover every aspect, as the questions are random. Getting a couple of questions on topics you are not familiar with maybe the difference between a pass and a fail.&lt;/p>
&lt;p>The learning path is mostly excellent, though there were a few missing parts that I had to research myself, particularly around Azure Synapse, Databricks &amp;amp; HDInsight.&lt;/p></description></item><item><title>PVA to Visio Builder - XrmToolBox Tool</title><link>https://linked365.blog/2021/12/24/pva-to-visio-builder-xrmtoolbox-tool/</link><pubDate>Fri, 24 Dec 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/12/24/pva-to-visio-builder-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2021/12-pva-flow2.png" alt="Featured image of post PVA to Visio Builder - XrmToolBox Tool" />&lt;p>Sorry, it has been quiet on the blog. When you create tools, as a hobby, the time to release new features or new tools is dictated by time spent and complexity. This means I don&amp;rsquo;t post as much as I want to.&lt;/p>
&lt;p>But, more importantly, I have a new tool available! Introducing PVA to Visio Builder!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/12-pva-flow-1024x480.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I have created a tool for the XrmToolBox which enables you to document your Power Virtual Agents.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>Install the tool, available in your XrmToolBox tools and open it up against your Dataverse environment where your PVA are.&lt;/p>
&lt;p>What you are presented with is a list of the Chat Bots that are in the system you have connected to.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/12-pva-flow1-1024x590.png"
loading="lazy"
>&lt;/p>
&lt;p>Select the PVA Bot you want to document, then choose one or more of the Topics associated with the bot. Here, you can see a lot of the out of the box ones that are created when you generate a new bot.&lt;/p>
&lt;p>Hit the Create Visio button. Choose where to save the file and hopefully you will get a prompt telling you it has been successful.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/12-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Open Visio and you have a version of the Topic as Visio. Like the &lt;a class="link" href="https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/" target="_blank" rel="noopener"
>Flow to Visio tool&lt;/a>, you may have to do some arranging, increasing size of boxes etc. but I hope I have saved you some time!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/12-image-1-1024x641.png"
loading="lazy"
>&lt;/p>
&lt;p>Hopefully it is self explanatory, here you can see the Visio representation of the standard Lesson 4 - A topic with a condition, variables and custom entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/12-pva-flow2-1024x379.png"
loading="lazy"
>&lt;/p>
&lt;p>In the above image, you can see the comparison of the PVA on the left and what it produces in Visio on the right.&lt;/p>
&lt;ol>
&lt;li>The Trigger phrases are inluded (if any)&lt;/li>
&lt;li>The Question and any options are displayed, along with the variable that is populated. I have increased the length of this box.&lt;/li>
&lt;li>All of the routes from this question are mapped, with the value criteria. The Default condition is not displayed, as there is no child action in the original (which means it is not in the JSON).&lt;/li>
&lt;/ol>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>Please let me know what you think, reach out on socials etc. I have only tested with topics I have generated, so I know there is a lot of complicated topics that I would love you to test.&lt;/p>
&lt;p>Let me know of any issues by logging them on GitHub &lt;a class="link" href="https://github.com/LinkeD365/BotToVisio/issues" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p></description></item><item><title>Nov 21 Updates to Flow To Visio</title><link>https://linked365.blog/2021/11/29/nov-21-updates-to-flow-to-visio/</link><pubDate>Mon, 29 Nov 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/11/29/nov-21-updates-to-flow-to-visio/</guid><description>&lt;img src="https://linked365.blog/images/2021/11-image.png" alt="Featured image of post Nov 21 Updates to Flow To Visio" />&lt;p>I have been busy on a new job, actually socialising and living life recently, but got back to doing some updates for the Flow to Visio tool. The main description is updated &lt;a class="link" href="https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/" target="_blank" rel="noopener"
>here&lt;/a> but I will just highlight the changes.&lt;/p>
&lt;h2 id="comments">Comments&lt;/h2>
&lt;p>Comments on Flows are a new, preview, a feature &lt;a class="link" href="https://cloudblogs.microsoft.com/powerplatform/2021/11/02/new-power-platform-capabilities-announced-at-microsoft-ignite/" target="_blank" rel="noopener"
>recently announced&lt;/a> at Ignite November 21. It only allows for comments in flows stored within a dataverse environment but is a great feature to collaborate with your fellow developers.&lt;/p>
&lt;p>I have introduced Comments as an option within the Options Menu, to allow you to add them or not.&lt;/p>
&lt;h2 id="community-updates">Community Updates&lt;/h2>
&lt;p>There is always that annoying friend, who thinks they are helping with coming up with good ideas. &lt;a class="link" href="https://twitter.com/D365Geek" target="_blank" rel="noopener"
>MCJ&lt;/a> is that friend for me. He created several requests for improvements and these, along with others were released altogether.&lt;/p>
&lt;p>This build includes&lt;/p>
&lt;ul>
&lt;li>Reduced the border to the bottom edge and corrected a few dimensions (&lt;a class="link" href="https://www.linkedin.com/in/ACoAAABuB8IBUzYf-_a2w9iIhX_i7O7zEqTZepU" target="_blank" rel="noopener"
>Jonas Rapp&lt;/a>) 🤘🏼&lt;/li>
&lt;li>SQL Actions with appropriate actions (&lt;a class="link" href="https://www.linkedin.com/in/ACoAAAChCqsBny4rLMFFJV07fEKmMmhO_z1YnNs" target="_blank" rel="noopener"
>Matt Collins-Jones&lt;/a>) 👏&lt;/li>
&lt;li>Append to String etc use proper icons (&lt;a class="link" href="https://www.linkedin.com/in/ACoAAAChCqsBny4rLMFFJV07fEKmMmhO_z1YnNs" target="_blank" rel="noopener"
>Matt Collins-Jones&lt;/a>) 😤&lt;/li>
&lt;li>Open file after creation (&lt;a class="link" href="https://www.linkedin.com/in/ACoAAAChCqsBny4rLMFFJV07fEKmMmhO_z1YnNs" target="_blank" rel="noopener"
>Matt Collins-Jones&lt;/a>) 🤬&lt;/li>
&lt;li>Multi-Select for creation of Visios (&lt;a class="link" href="https://www.linkedin.com/in/ACoAAARaDCoBtX0L-_xR0EiN44Z8npOacle1Fqc" target="_blank" rel="noopener"
>Michael LaMontagne&lt;/a>) 👍🏽&lt;/li>
&lt;li>Options drop-down for concurrent, tracked properties and many more 😍&lt;/li>
&lt;/ul>
&lt;p>P.S. Thanks to &lt;a class="link" href="https://twitter.com/CarinaMClaesson" target="_blank" rel="noopener"
>Carina&lt;/a> for nagging me to do this post.&lt;/p></description></item><item><title>Access Checker - XrmToolBox Tool</title><link>https://linked365.blog/2021/09/01/access-checker-xrmtoolbox-tool/</link><pubDate>Wed, 01 Sep 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/09/01/access-checker-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2021/09-access.jpg" alt="Featured image of post Access Checker - XrmToolBox Tool" />&lt;p>Frequently, my day job is inspiration to develop a tool and &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/mscrmtools.accesschecker/" target="_blank" rel="noopener"
>Access Checker&lt;/a> was just that. Though not mine, the great &lt;a class="link" href="https://twitter.com/TanguyTOUZARD" target="_blank" rel="noopener"
>@Tanguy Touzard&lt;/a> did the original, I felt that I could update it to include how the user has access.&lt;/p>
&lt;p>The original tool allowed you to select a record, select a user and be presented with what access that user had to that record. My enhancement is to present to the user how they gained that access. This was because we have come across a situation where it was unclear how a user got access to a record.&lt;/p>
&lt;p>Microsoft has now given us a &lt;a class="link" href="https://docs.microsoft.com/en-us/powerapps/user/access-checker" target="_blank" rel="noopener"
>Check Access&lt;/a> button on a record form, but I feel that this is a little clunky, particularly if you want to check multiple records, and the Access Checker also adds, for records that are accessible by inheritance, a link to the record that was shared.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I augmented the Access Checker tool to provide an explanation of how access has been granted.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-image.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-access-1024x486.jpg"
loading="lazy"
>&lt;/p>
&lt;p>Open the tool and select the Entity (damn, missed the opportunity to change to Table). If you know the record id then just paste it in, otherwise, select the Search button to use a view and find your record.&lt;/p>
&lt;p>The Lookup record window allows the selection of a view and searching using * as a wildcard.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>When you have your record, return to the main window and select Browse. The User selection allows a search and selection of a user.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Once done, select Retrieve Rights. The box at the bottom displays a grid showing you the rights that use has to the record. Standard Create, Read, Write, Delete, Append, Append To, Assign and Share derived by the Power Platform security principles.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Red means that the user has not got permission to do the action.&lt;/p>
&lt;p>Green means they do. Also, there is an icon and words to define how they got access.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-shared.jpg"
loading="lazy"
>&lt;/p>
&lt;p>The user has the record directly shared with them&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-related-record-3.jpg"
loading="lazy"
>&lt;/p>
&lt;p>The user has access from a share with a related (parent or higher) record.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-user-role-1.jpg"
loading="lazy"
>&lt;/p>
&lt;p>The user has access due to the role indicated&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/09-role-from-team.jpg"
loading="lazy"
>&lt;/p>
&lt;p>The user has a role from the team displayed giving them access&lt;/p>
&lt;h2 id="video-walkthrough">Video Walkthrough&lt;/h2>
&lt;div class="video-wrapper">
&lt;video
controls
src="https://linked365.blog/images/2021/09-accesschecker.mp4"
>
&lt;p>
Your browser doesn't support HTML5 video. Here is a
&lt;a href="https://linked365.blog/images/2021/09-accesschecker.mp4">link to the video&lt;/a> instead.
&lt;/p>
&lt;/video>
&lt;/div>
&lt;p>Please let me know what you think &amp;amp; log an enhancement/issue on GitHub &lt;a class="link" href="https://github.com/MscrmTools/MsCrmTools.AccessChecker" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p></description></item><item><title>Updates to Mind Maps</title><link>https://linked365.blog/2021/08/11/updates-to-mind-maps/</link><pubDate>Wed, 11 Aug 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/08/11/updates-to-mind-maps/</guid><description>&lt;img src="https://linked365.blog/images/2021/08-image.png" alt="Featured image of post Updates to Mind Maps" />&lt;p>Microsoft has introduced a &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/renew-your-microsoft-certification" target="_blank" rel="noopener"
>new&lt;/a> way of renewing certifications recently (well, December 2020) in that you don&amp;rsquo;t have to retake the whole exam.&lt;/p>
&lt;p>This is invaluable for those, like me, with limited time. In the past, you had to spend at least a couple of hours either virtually or in-person re-taking the whole exam. This change means you have to answer 20-25 questions and extend your certification by a year. Such a time-saving!&lt;/p>
&lt;p>But, it means I have not re-visited my mind maps in light of the changes in the functionality that comes because Microsoft is investing and continually improving the products.&lt;/p>
&lt;p>This became apparent when I did the re-take for &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/exams/mb-210" target="_blank" rel="noopener"
>MB-210 - Sales&lt;/a>. I thought I would take the exam and failed (bruising my ego). The re-take was full of Customer Insights and Sales Insights topics, which I don&amp;rsquo;t remember when I took the exam. The focus on these topics has certainly increased since I took my exam, nearly 2 years ago, and this is clear if you take a look at the exam outline.&lt;/p>
&lt;p>So, what I thought I would do was update my mind maps as I re-new my certifications. This will ensure I refresh my understanding, and hopefully will be of more help to those out there that like this type of aide-memoire for their learning.&lt;/p>
&lt;p>Also, my use of Freeplane was limiting, you had to download a program to access, and in these days of everything being online, I have always been on the lookout for a (free) alternative. Coggle has given me just that. I can make as many public diagrams as I like.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/08-image-1024x434.png"
loading="lazy"
alt="Screenshot of Coggle example"
>&lt;/p>
&lt;p>As I update the mind-maps, I will post links here and some notes on the catchup exam.&lt;/p>
&lt;h2 id="mb-210-sales">MB-210: Sales&lt;/h2>
&lt;p>&lt;a class="link" href="https://coggle.it/diagram/YQ1ftkzMKCfJtA9L/t/mb-210/4f4b3db574f592b8926878b9f892f2e6b851a4cc77a484bfb91f72acfe2d5a6c" target="_blank" rel="noopener"
>Mindmap&lt;/a>&lt;/p>
&lt;p>The re-take included a lot of Sales Insights and Customer Insights. Customer Insights is not mentioned that much in the exam outline, apart from the user case for it, so I assume the re-take has not caught up with it. New stuff for me was around the forecasting, which is much improved.&lt;/p>
&lt;h2 id="pl-600-power-platform-solution-architect">PL-600: Power Platform Solution Architect&lt;/h2>
&lt;p>&lt;a class="link" href="https://coggle.it/diagram/YRPTc4LB6mn9n7MG/t/pl-600-power-platform-solution-architect/4bfb6625ae7c407baf0b5a300f6943446b6416445abb13ea69d26cc9f3e2b71b" target="_blank" rel="noopener"
>Mindmap&lt;/a>&lt;/p>
&lt;p>This wasn&amp;rsquo;t a retake, rather the first time in a while I have sat an exam. I have done MB-600, the Dynamics CE equivalent, but have held back doing this one for various reasons, mostly finding the time.&lt;br>
To be honest, I found it very similar to MB-600. The content of the exam outline had very little link to the questions asked. You need to know a lot about the Power Platform - know enough about all the parts to be dangerous.&lt;br>
You won&amp;rsquo;t learn this in my mindmap above, it will be by being experienced, having hands-on experience with various aspects of the platform and doing the other exams which lead you to the PL-600. Matt Collins-Jones has a great audio description of the exam &lt;a class="link" href="https://youtu.be/Wk7B8fpnAeI" target="_blank" rel="noopener"
>here&lt;/a> so shout out to him.&lt;/p></description></item><item><title>Role Replicator - XrmToolBox Tool</title><link>https://linked365.blog/2021/06/22/role-replicator-xrmtoolbox-tool/</link><pubDate>Tue, 22 Jun 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/06/22/role-replicator-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2021/06-Role-Replicator.gif" alt="Featured image of post Role Replicator - XrmToolBox Tool" />&lt;p>Santosh, he of &lt;a class="link" href="https://linked365.blog/2020/12/22/role-documenter-xrmtoolbox-tool/" target="_blank" rel="noopener"
>Role Documenter&lt;/a> fame, highlighted to me that one of his tools has fallen by the wayside. He is a busy man and has not found time to keep this tool up to date. XrmToolBox and the underlying Microsoft tooling, has changed quite significantly over the years; like any software project, it needs to be updated regularly to keep in line. I have helped him out bring the tool back and this post is a walkthrough of it in use.&lt;/p>
&lt;p>&lt;a class="link" href="https://www.xrmtoolbox.com/plugins/RoleReplicator/" target="_blank" rel="noopener"
>Role Replicator&lt;/a> allows a user (If you have the correct &lt;a class="link" href="https://docs.microsoft.com/en-us/power-platform/admin/security-roles-privileges#assigning-security-roles" target="_blank" rel="noopener"
>permissions&lt;/a>) to select a user and duplicate their roles, teams and queues to one or more other users.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>&lt;a class="link" href="https://www.xrmtoolbox.com/plugins/RoleReplicator/" target="_blank" rel="noopener"
>Role Replicator&lt;/a> is an XrmToolBox that has not been updated for a while, I brought it back to life.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>Open the tool and select the source user. On the left side, each list shows the roles, teams and queues for the selected user.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/06-2021-06-22_16-08-44.jpg"
loading="lazy"
>&lt;/p>
&lt;p>Select one or more users to copy the role to using the Select check boxes. Define what you want to copy, using the option buttons highlighted in red. Then finally, hit the Run Copy button.&lt;/p>
&lt;p>You will be prompted to confirm the change, listing who you are going to be updating and what you are going to do.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/06-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>After a while of watching the spinning blue circle, you will get a prompt that is all succesful!&lt;/p>
&lt;p>Make sure you check the changes you have made to confirm we didnt break anything!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/06-Role-Replicator-1024x643.gif"
loading="lazy"
>&lt;/p></description></item><item><title>Using Power Automate and Graph API to manage External access to Teams</title><link>https://linked365.blog/2021/05/06/using-power-automate-and-graph-api-to-manage-external-access-to-teams/</link><pubDate>Thu, 06 May 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/05/06/using-power-automate-and-graph-api-to-manage-external-access-to-teams/</guid><description>&lt;img src="https://linked365.blog/images/2021/05-image-18.png" alt="Featured image of post Using Power Automate and Graph API to manage External access to Teams" />&lt;p>&lt;a class="link" href="https://twitter.com/D365Geek" target="_blank" rel="noopener"
>MCJ&lt;/a> and I presented &lt;a class="link" href="https://d365uguk-22-apr-2021.sessionize.com/session/244458" target="_blank" rel="noopener"
>API’s – The most powerful tool, anyone can use!&lt;/a> for D365 UG and Swiss Power Saturday recently and I thought it would be good to share the Cloud Flow I created to automate the onboarding of external users to a Microsoft Team.&lt;/p>
&lt;p>This is usually an admin driven activity - A team owner will have to type in the email address for each guest they want to add, rather than something you can push to external users and allow them to request access.&lt;/p>
&lt;p>By using the Graph API via a Custom Connector, Microsoft Forms and Power Automate, we are able to realise this quickly and save a lot of time and effort in the manual process.&lt;/p>
&lt;p>Also, I have been lucky to have this solution accepted as part of the samples in the &lt;a class="link" href="https://pnp.github.io/" target="_blank" rel="noopener"
>Microsoft Patterns And Practices&lt;/a> initiative, so the Flow, Custom Connector and implementation instructions are available in GitHub &lt;a class="link" href="https://github.com/pnp/powerautomate-samples" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I created a Power Automate Cloud Flow which allows an external user to request access to a Team, get approved by the owner of the team, invite the external user to your tenant and add them to the team.&lt;/p>
&lt;h2 id="getting-hands-on-with-graph">Getting hands on with Graph&lt;/h2>
&lt;p>The main part of this flow is numerous calls to the &lt;a class="link" href="https://docs.microsoft.com/en-us/graph/overview" target="_blank" rel="noopener"
>Graph API&lt;/a>. The Graph API is Microsoft&amp;rsquo;s standard endpoint to expose and interact with data relevant to your tenant. It includes Microsoft 365 (such as Teams, Exchange, SharePoint, Workspace Analytics), Enterprise and Mobility and even Windows 10 activities and devices. It really should be seen as a single stop shop for anything and everything in your tenant. The only thing it doesn&amp;rsquo;t expose is D365 data.&lt;/p>
&lt;p>There is a &lt;a class="link" href="https://docs.microsoft.com/en-us/connectors/microsoftgraphsecurity/" target="_blank" rel="noopener"
>Graph connector&lt;/a> already available in Power Automate, but it is very limited to Security considerations. Thankfully, the rest of the Graph API abilities are available, but you have to go via a custom connector. You could call these directly via an HTTP request action, but by wrapping the Graph API in a connector, you are enabling other members of your organisation to re-use the connector and security you establish.&lt;/p>
&lt;p>Microsoft also allows you to &amp;ldquo;play&amp;rdquo; with the Graph API as well, via the &lt;a class="link" href="https://developer.microsoft.com/en-us/graph/graph-explorer" target="_blank" rel="noopener"
>Graph Explorer&lt;/a>. This web interface shows you all the sample calls you can make and also what permissions you require to call it and allows you to set up a call without using Power Automate or configuring a connector. It really should be the starting point for any Graph Customer Connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-28_11-48-48-1-1024x520.png"
loading="lazy"
>&lt;/p>
&lt;p>If things go wrong, it is usually around the permissions. Within the Graph Explorer you can consent to these extra permissions on the fly, but more importantly, tells you what you need to configure in the permissions of your App registration to allow your connector the same access.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-28_12-00-14-1024x548.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="granting-permissions">Granting Permissions&lt;/h2>
&lt;p>Now that we understand what permissions that are needed to get at the actions required, let&amp;rsquo;s jump in and create an &lt;a class="link" href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app" target="_blank" rel="noopener"
>Azure App Registration&lt;/a>. This allows you to grant rights to a particular application, which presents a client secret and App ID as part of the request. By doing this registration, you establish trust between your app (Custom Connector in our case) and your tenant.&lt;/p>
&lt;p>Navigate to &lt;a class="link" href="https://aad.portal.azure.com/" target="_blank" rel="noopener"
>https://aad.portal.azure.com&lt;/a> and log in. Select Azure Active Directory then App registrations. Select New, give it an appropriate name then hit Register.&lt;/p>
&lt;p>In the next screen, record the Application Id, going to need it later. On the left, select Certificates &amp;amp; secrets&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-28_13-33-07-1-1024x364.png"
loading="lazy"
>&lt;/p>
&lt;p>Select New client secret give it a name &amp;amp; expiry date and select Save.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-28_13-39-03-1.png"
loading="lazy"
>&lt;/p>
&lt;p>Ensure you copy the Value here, you will only be able to see this for a short while, if you navigate away it will be gone. Not a big deal, just recreate the client secret, but you will need it later. Now select API permissions. This will list what permissions this registration has, and by inference, the caller using the client secret/application id.&lt;/p>
&lt;p>Select the Add a permission button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-30_11-18-14-1024x484.png"
loading="lazy"
>&lt;/p>
&lt;p>This presents a choice of which API to expose. The first on the list is Microsoft Graph, the one we want.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Delegated Permissions (Custom connectors doesnt support Application permissions yet, will run in the context of the person who runs the flow, so use an admin/system account) then type in the permission you want, listed here.&lt;/p>
&lt;ul>
&lt;li>Directory.ReadWrite.All&lt;/li>
&lt;li>User.Invite.All&lt;/li>
&lt;li>User.ReadWrite.All&lt;/li>
&lt;/ul>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Add Permissions to return you to the Configured permissions screen, then select Grant Admin consent button. This shortcuts and pre-approves the app.&lt;/p>
&lt;p>Leave this tab open and let&amp;rsquo;s go and define our custom connector.&lt;/p>
&lt;h2 id="defining-the-custom-connector">Defining the Custom Connector&lt;/h2>
&lt;p>Jan Bakker has done an excellent job of walking you through this, &lt;a class="link" href="https://powerusers.microsoft.com/t5/Power-Automate-Community-Blog/Build-a-custom-connector-for-Microsoft-Graph-API/ba-p/647492" target="_blank" rel="noopener"
>here&lt;/a>. His article goes into a lot of detail, so I will just take you through what is needed for this project.&lt;/p>
&lt;p>In make.powerapps.com, select the appropriate environment and chose Custom Connectors under Data. Then select New custom connector. You can import from various sources, but we want to create from blank, give it a name then fill out the next page.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-30_12-00-33-1024x435.png"
loading="lazy"
>&lt;/p>
&lt;p>On the next screen, there are four tabs, which we need to step through. First the General Tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>Other stuff is nice to have and you &lt;em>should&lt;/em> document your work. Ensure Scheme is HTTPS and Host/Base URL are populated.&lt;/p>
&lt;ul>
&lt;li>Host - graph.microsoft.com&lt;/li>
&lt;li>Base URL - /v1.0&lt;/li>
&lt;/ul>
&lt;p>Select the Security Tab next, Authentication type is OAuth 2.0. You should be presented with the below screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, this is where we need to use the values you saved (you did save them?) when you were registering your app up &lt;a class="link" href="#Granting-Permissions" >here&lt;/a>. Client Id is populated with the Application (client) ID, the Client secret is populated with the Value from the Client Secret grid. Login URL will be populated for you. The Resource URL value should be &lt;a class="link" href="https://graph.microsoft.com" target="_blank" rel="noopener"
>https://graph.microsoft.com&lt;/a>.Select Create Connector now, as you need the Redirect URL, created when you create the connector to put back into your App registration to complete the security process.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>I &lt;em>think&lt;/em> that this is now standard, but just in case, copy the Redirect URL and go back to your App Registration in Azure AD. Click on the link highlighted.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-2021-04-30_14-03-22-1024x347.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Add a platform then chose Web. Enter the Redirect URL from the Custom Connector. Now we are ready to define the actions for our connector.&lt;/p>
&lt;h3 id="creating-the-actions">Creating the Actions&lt;/h3>
&lt;p>For our flow, we need 3 actions, Get the owners of a team, Get a user and Invite a User. This is where Graph Explorer and Postman help. You need to establish what you are sending and what you expect back for each action. For example, lets walk through the Get Owners of a team.&lt;/p>
&lt;p>Select New Action and Populate General section. The Operation ID needs to be unique and is what appears within Power Automate when you select it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>I usually use the same for each, but be creative and descriptive. Select Import from sample then use the url below as the URL and select Get as the Verb.&lt;/p>
&lt;p>URL - &lt;a class="link" href="https://graph.microsoft.com/v1.0/groups/%7bteamId%7d/owners" target="_blank" rel="noopener"
>https://graph.microsoft.com/v1.0/groups/{teamId}/owners&lt;/a>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>By placing teamid in curly brackets { } you denote to the custom connector you want to use a parameter in that URL. You can call &lt;a class="link" href="https://graph.microsoft.com/v1.0/groups/%7bteamId%7d" target="_blank" rel="noopener"
>https://graph.microsoft.com/v1.0/groups/{teamId}&lt;/a> (without the /owners) but that will return the detail from the group. In this I want get associated data, hence the /owners.&lt;/p>
&lt;p>Select Import. You are returned to the definition screen, where we can see that the request has been populated for us.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>We are ready to test our Get Owners now. Update the connector once more then head over to the Test tab. You will have to create a connection if not already done, which prompts you to establish who you are running the connector under (only for testing). Then supply a team id. These can be found by using Graph Explorer to find all teams. Hit the Test operation and if everything is working you will get a 200 response with some JSON in a body showing you all the information about the owners.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>To just define the others&lt;/p>
&lt;h4 id="get-user">Get User&lt;/h4>
&lt;p>Verb: Get, URL: &lt;a class="link" href="https://graph.microsoft.com/v1.0/users?$filter=" target="_blank" rel="noopener"
>https://graph.microsoft.com/v1.0/users?$filter=&lt;/a>&lt;/p>
&lt;h4 id="invite-user">Invite User&lt;/h4>
&lt;p>Verb: Put, URL: &lt;a class="link" href="https://graph.microsoft.com/v1.0/invitations" target="_blank" rel="noopener"
>https://graph.microsoft.com/v1.0/invitations&lt;/a>, Body is below, as you need to define a new invite, with the required parameters. The data doesn&amp;rsquo;t matter, just the parameters that you need to pass.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;invitedUserEmailAddress&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;emailaddress&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inviteRedirectUrl&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://myapp.contoso.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;invitedUserDisplayName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Testy McTest&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;sendInvitationMessage&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Make sure you test all your actions and lets move on to the Form.&lt;/p>
&lt;h2 id="microsoft-form-to-capture-information">Microsoft Form to capture information&lt;/h2>
&lt;p>Not going to dwell here, as others are doing a much better job at describing Forms. Basically, a simple form to define First and Last name, the email address and a choice field to define which team the user wants access to.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-18-1007x1024.png"
loading="lazy"
>&lt;/p>
&lt;p>The teams list will have to be maintained to those that you want the public to be able to request access to.&lt;/p>
&lt;p>Finally, lets take a look at the flow.&lt;/p>
&lt;h2 id="power-automate-definition">Power Automate Definition&lt;/h2>
&lt;p>This Flow is triggered by a new response being submitted against the Form defined above. Next, get the response details.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, retrieve all the Teams in your environment. This will return a JSON object which defines an array of Team definitions. We need to filter that to the one the user selected so that we can get the team id.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>To do this, I use the Filter Array action, pass in the output from the List Teams and ensure we select where team Name is equal to the team selected (the Which Team? field in my case).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, is a compose statement. I do that just to simplify the way the flow works, as the return of filter array is an array, and I just want the first one.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-22.png"
loading="lazy"
>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="err">body(&amp;#39;Filter_array&amp;#39;)&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">?&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Next, lets get the Owners of the team selected, using the Id just retrieved. This is the first time using the Custom Connector, it is available under the Custom Tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>Selecting the connector will show the actions or triggers available.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>The parameters are those that were defined in the Custom connector, passing in the output from the compose above.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, the response back from Get Owners is a JSON object, so next, Parse the JSON so there is a list of JSON objects for the flow to use. All that is needed in the approval that comes next is the email address(es) of the return from the owners call. But the approval needs a semi-colon separated list of emails. To achieve this, firstly use a Select to just return the email address from the JSON object, then join the output to that with a semi colon.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, start an approval. This is populated to let the owner know who has asked for access to the team and which team.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-28.png"
loading="lazy"
>&lt;/p>
&lt;p>Check whether the response is positive. If this was for production, I would probably send an email to the requesting user to let them know that they were denied access. You could also use the response written in the rejection.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-29-1024x171.png"
loading="lazy"
>&lt;/p>
&lt;p>In the Yes path, call the Custom connector again to check if the user is already a part of your organisation as a guest user. As the parameter is expecting a query, use the expression below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>mail eq &amp;lsquo;Email Parameter from the Form response&amp;rsquo;&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="err">mail&lt;/span> &lt;span class="err">eq&lt;/span> &lt;span class="err">&amp;#39;Email&lt;/span> &lt;span class="err">Parameter&lt;/span> &lt;span class="err">from&lt;/span> &lt;span class="err">the&lt;/span> &lt;span class="err">Form&lt;/span> &lt;span class="err">response&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Next, check the length of the returned object from the custom connector. This basically checks if the user already belongs to your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-32.png"
loading="lazy"
>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">length(outputs(&amp;#39;GetUser&amp;#39;)?[&amp;#39;body/value&amp;#39;])
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>If there is a value in the return, use the return to invite the user to the team.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-33.png"
loading="lazy"
>&lt;/p>
&lt;p>The User id is returned by using the expression below&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="err">body(&amp;#39;GetUser&amp;#39;)?&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;value&amp;#39;&lt;/span>&lt;span class="p">][&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">]&lt;/span>&lt;span class="err">?&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;id&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>On the negative side, firstly invite the user to your organisation by using the final action of the custom connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>And finally, use the response from your custom connector, the invited user to the team.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/05-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Thats it! There is a lot of configuration here, but you can see how you can extend your usage of Power Automate to automate a function usually confined to manual work by the team owner.
&lt;style type="text/css">.notice{--root-color:#444;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#c33;--warning-content:#fee;--info-title:#fb7;--info-content:#fec;--note-title:#6be;--note-content:#e7f2fa;--tip-title:#5a5;--tip-content:#efe}@media (prefers-color-scheme:dark){.notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}}body.dark .notice{--root-color:#ddd;--root-background:#eff;--title-color:#fff;--title-background:#7bd;--warning-title:#800;--warning-content:#400;--info-title:#a50;--info-content:#420;--note-title:#069;--note-content:#023;--tip-title:#363;--tip-content:#121}.notice{padding:18px;line-height:24px;margin-bottom:24px;border-radius:4px;color:var(--root-color);background:var(--root-background)}.notice p:last-child{margin-bottom:0}.notice-title{margin:-18px -18px 12px;padding:4px 18px;border-radius:4px 4px 0 0;font-weight:700;color:var(--title-color);background:var(--title-background)}.notice.warning .notice-title{background:var(--warning-title)}.notice.warning{background:var(--warning-content)}.notice.info .notice-title{background:var(--info-title)}.notice.info{background:var(--info-content)}.notice.note .notice-title{background:var(--note-title)}.notice.note{background:var(--note-content)}.notice.tip .notice-title{background:var(--tip-title)}.notice.tip{background:var(--tip-content)}.icon-notice{display:inline-flex;align-self:center;margin-right:8px}.icon-notice img,.icon-notice svg{height:1em;width:1em;fill:currentColor}.icon-notice img,.icon-notice.baseline svg{top:.125em;position:relative}&lt;/style>
&lt;div>&lt;svg width="0" height="0" display="none" xmlns="http://www.w3.org/2000/svg">&lt;symbol id="tip-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"/>&lt;/symbol>&lt;symbol id="note-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="warning-notice" viewBox="0 0 576 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M569.517 440.013C587.975 472.007 564.806 512 527.94 512H48.054c-36.937 0-59.999-40.055-41.577-71.987L246.423 23.985c18.467-32.009 64.72-31.951 83.154 0l239.94 416.028zM288 354c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/>&lt;/symbol>&lt;symbol id="info-notice" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet">&lt;path d="M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z"/>&lt;/symbol>&lt;/svg>&lt;/div>&lt;div class="notice warning" >
&lt;p class="first notice-title">&lt;span class="icon-notice baseline">&lt;svg>&lt;use href="#warning-notice">&lt;/use>&lt;/svg>&lt;/span>Warning&lt;/p>&lt;p>Adding guest users to your Teams is only available if your administrator has configured it. This logic will not override that and will only produce errors if it has been disabled.&lt;/p>&lt;/div>
&lt;/p></description></item><item><title>Site Map Documenter</title><link>https://linked365.blog/2021/04/20/site-map-documenter/</link><pubDate>Tue, 20 Apr 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/04/20/site-map-documenter/</guid><description>&lt;img src="https://linked365.blog/images/2021/04-SiteMap-Export.gif" alt="Featured image of post Site Map Documenter" />&lt;p>In my never-ending journey to document everything in the Power Platform, I thought I would take a crack at Site Maps. You know, the list of stuff on the left-hand side of a model-driven app. Again, as a consultant, it needs documenting and Microsoft doesn&amp;rsquo;t provide a tool to do so.&lt;/p>
&lt;p>&lt;a class="link" href="https://twitter.com/TanguyTOUZARD" target="_blank" rel="noopener"
>Tanguy Touzard&lt;/a>, the wizard behind XrmToolBox has already got an app to edit Site maps, which I piggy backed on, as there is no point reinventing the wheel and most of the work will have already been done this way.&lt;/p>
&lt;p>The tool is now available by XrmToolBox &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/MsCrmTools.SiteMapEditor/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Walkthrough of the new capability added to Site Map Editor XrmToolBox tool to export Site Maps to Excel.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>First of all, what is a Site Map? It is the fancy name for the navigation you see when you open any Model Driven App.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-image.png"
loading="lazy"
>&lt;/p>
&lt;p>The Red area is the site map. Each yellow area is the group, which is just the secondary headings. The green are called Sub Areas but are the actual menu items that drive users to content within your app. Finally, other areas can be defined, shown in purple at the bottom.&lt;/p>
&lt;p>In the Site Map editor within a Model-driven app, the same Site Map looks like this, with the colour boxes denoting the same parts.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-image-1-1024x290.png"
loading="lazy"
>&lt;/p>
&lt;p>Each Sub Area is associated with a dashboard, table (still labelled entity), Web Resource or URL. Further, you can configure properties depending on what you choose.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>Under Advanced Parameters, you can see the configuration for privileges (visibility of the item depending on access to a table), different translations for an item and other properties. Not the subject of the article, but just to note that the configuration can be complex, and documenting what you have done is paramount in a lot of scenarios.&lt;/p>
&lt;h2 id="site-map-editor">Site Map Editor&lt;/h2>
&lt;p>Site Map Editor does what it says on the tin (and also exports to Excel now!). It allows you to edit, save and import a site map from the comfort of your XrmToolBox, great for when you have to clone them or do significant editing.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-image-3-1024x526.png"
loading="lazy"
>&lt;/p>
&lt;p>More importantly, you can save and export the map as an Xml file to allow you to clone Sitemaps between environment. This also allows manual editing within the Xml file itself if you need to do more copy/paste of functionality between site maps.&lt;/p>
&lt;h2 id="export-to-excel">Export to Excel&lt;/h2>
&lt;p>The bit I have added is the little Export To Excel button on the main menu bar.&lt;/p>
&lt;p>Clicking on the button prompts for a file to save the Excel as and once done, you are prompted whether to open the Excel file.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-SiteMap-Export.gif"
loading="lazy"
>&lt;/p>
&lt;p>Each sheet in the Excel file represents an Area within the application. Each sheet contains a listing of the groups, the sub-areas that form part of the group and the properties of both the sub-area and the groups.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/04-image-4-1024x463.png"
loading="lazy"
>&lt;/p>
&lt;p>Let me know of any issues with this tool on GitHub &lt;a class="link" href="https://github.com/MscrmTools/MscrmTools.SiteMapEditor/issues" target="_blank" rel="noopener"
>here&lt;/a> and hope it saves you some time now or in the future.&lt;/p></description></item><item><title>Mockaroo Data Munger - Data Sets</title><link>https://linked365.blog/2021/03/08/mockaroo-data-munger-data-sets/</link><pubDate>Mon, 08 Mar 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/03/08/mockaroo-data-munger-data-sets/</guid><description>&lt;img src="https://linked365.blog/images/2021/03-Munger-Sets-sml.gif" alt="Featured image of post Mockaroo Data Munger - Data Sets" />&lt;p>Working with demo or test data, you normally need a set of data rather than one table. For instance, for a Customer Insights demo, I would want hundreds of accounts, thousands of contacts associated with those accounts and tens of thousands of cases associated with the contacts. This will have to be realistic, randomised data that shows the last 3-6 months rather than a stale set of data. The same with Opportunities - create a realistic data set of accounts, contacts, opportunities, orders and the associated product lines. Rinse and repeat next time you need a new demo as your trial has expired.&lt;/p>
&lt;p>With this in mind, I created Data Sets for the &lt;a class="link" href="https://linked365.blog/2020/08/27/mockaroodatamunger/" target="_blank" rel="noopener"
>Mockaroo Data Munger tool&lt;/a> for the XrmToolBox. It is available with the rest of the great tools &lt;a class="link" href="https://www.xrmtoolbox.com/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I have updated the Mockaroo Data Munger with Data Sets. This article walks through how to use this new bit of functionality.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>Firstly, you need to create and save your data inserts. Let us assume that we want the scenario above, Accounts, Contacts and Cases. Creating the Account is straight forward, with standard options.&lt;/p>
&lt;p>Contacts are where it becomes tricky, as you want to create contacts associated with the newly created Accounts. For this, I have created From Set option. This will populate the field with the GUID of the primary key of any record created previously in the set. So the contacts will be associated with one of the accounts we created in the set. This will use the whole of the selected table if you don&amp;rsquo;t use it as part of a set.&lt;/p>
&lt;p>For Contact, there is a Customer Type field, which allows you to associate with a Contact or Account, so I give you both options here.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-image.png"
loading="lazy"
>&lt;/p>
&lt;p>The same applies with Case, it too has a Customer field, which can be both Account or Contact.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-image-1.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="create-your-set">Create your Set&lt;/h2>
&lt;p>Once I have created my maps, with all the relevant options, I need to create the Set. This is available via the Create Data Set button in the tool bar&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Up pops the data set creation tool.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>On the left are all your saved maps. Bring them into your set by selecting one and choosing the Right arrow, remove it from the set by choosing the left arrow. Re-arrange the maps in the set by using the up/down buttons.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-Sets.gif"
loading="lazy"
>&lt;/p>
&lt;p>Once you are happy with the configuration, hit OK and you are ready to run. This screen also allows you to update an existing set as well.&lt;/p>
&lt;h2 id="creating-the-data">Creating the Data&lt;/h2>
&lt;p>Now you are ready, hit the Play Set button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>This can take a while, depending on the amount of data you are creating, but you should get a success message and the data will be created in your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/03-Munger-Sets-sml.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="whats-next-for-the-munger">What&amp;rsquo;s next for the Munger?&lt;/h2>
&lt;p>Like with the &lt;a class="link" href="https://linked365.blog/2020/07/06/erd-visio-builder-xrmtoolbox-addon/" target="_blank" rel="noopener"
>ERD tool&lt;/a>, I want to allow export/saving of maps and data sets. Other feature requests are being accepted over at &lt;a class="link" href="https://github.com/LinkeD365/MockarooDataMunger/issues" target="_blank" rel="noopener"
>GitHub&lt;/a>&lt;/p></description></item><item><title>PL-200 - Power Platform Functional Consultant</title><link>https://linked365.blog/2021/02/12/pl-200-power-platform-functional-consultant/</link><pubDate>Fri, 12 Feb 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/02/12/pl-200-power-platform-functional-consultant/</guid><description>&lt;img src="https://linked365.blog/images/2021/02-51h0GIYIjPL._SX404_BO1,204,203,200_.jpg" alt="Featured image of post PL-200 - Power Platform Functional Consultant" />&lt;p>I have finally got round to taking this exam, I have only just (well it feels like) passed MB-200 and so when this exam was announced, I was a bit &amp;ldquo;meh&amp;rdquo; about it.&lt;/p>
&lt;p>Thankfully, the amazing &lt;a class="link" href="https://twitter.com/juliandynamics" target="_blank" rel="noopener"
>Julian Sharp&lt;/a> asked for people to review his new book &lt;a class="link" href="https://www.amazon.co.uk/Microsoft-Power-Platform-Functional-Consultant/dp/1838985689/ref=tmm_pap_swatch_0?_encoding=UTF8&amp;amp;qid=1613146093&amp;amp;sr=8-1" target="_blank" rel="noopener"
>Microsoft Power Platform Functional Consultant: PL-200 Exam Guide&lt;/a> and I jumped at the opportunity.&lt;/p>
&lt;p>As ever, I used &lt;a class="link" href="https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/" target="_blank" rel="noopener"
>Mind Maps&lt;/a> to assist me in remembering key facts, the one for PL-200 can be found &lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21298589&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2021/02-power-platform-functional-consultant-600x600__1_.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="the-exam">The Exam&lt;/h2>
&lt;p>It is a wide-ranging exam, from canvas app button functionality to recommended data repositories and AI builder techniques and everything in-between. I found my selection of questions focused on Business Process Flows quite a lot as well as Power Virtual agents.&lt;/p>
&lt;p>Basically, ensure you read the exam outline and know the fundamentals of each area.&lt;/p>
&lt;h2 id="the-book">The Book&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2021/02-51h0GIYIjPL._SX404_BO1,204,203,200_.jpg"
loading="lazy"
>&lt;/p>
&lt;p>Julian has done a wonderful job bringing all the aspects of the exam in one readable volume. His understanding of the intricacies of the Power Platform shines through strong with every page.&lt;/p>
&lt;p>This is not a mere &amp;ldquo;learn these facts to win&amp;rdquo; book, the reader is given a deep understanding of the platform. Starting with ensuring his readers get practical, hands-on experience by signing up a for a trail, he then guides them through what to expect from the exam. He also highlights some of the history, tools and initiatives in and around the platform to ensure the reader has a rounded understanding.&lt;/p>
&lt;p>Each area of the exam outline is then documented to a great extent, with screenshots and steps to complete the task at hand. Each chapter has a series of questions to test your knowledge. As a seasoned Power Platform professional, some of these were tricky and ensured I had the knowledge required to pass.&lt;/p>
&lt;p>Overall, a great book, which I highly encourage people to purchase if they are working towards this qualification.&lt;/p></description></item><item><title>Logic Apps to Visio - XrmToolBox Tool</title><link>https://linked365.blog/2021/02/06/logic-apps-to-visio-xrmtoolbox-tool/</link><pubDate>Sat, 06 Feb 2021 00:00:00 +0000</pubDate><guid>https://linked365.blog/2021/02/06/logic-apps-to-visio-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2021/02-Logic-App.gif" alt="Featured image of post Logic Apps to Visio - XrmToolBox Tool" />&lt;p>So, we all know Power Automate Cloud Flows are basically Logic Apps right? Which means I should be able to document them and convert to Visios in the same way as my &lt;a class="link" href="https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/" target="_blank" rel="noopener"
>Flow To Visio Tool&lt;/a> right?&lt;/p>
&lt;p>Actually, it is true! After numerous requests, I finally got round to doing it.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I have included the ability to document Logic Apps in the Flow to Visio tool.&lt;/p>
&lt;h3 id="document-logic-apps-beta">Document Logic Apps (BETA)&lt;/h3>
&lt;p>First, let me stress this is VERY BETA. I do not have many (any) Logic Apps I can point this at. If you come across any issues with it, please let me know by raising issues on GitHub &lt;a class="link" href="https://github.com/LinkeD365/FlowToVisio/issues" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>To connect to the Azure Logic Apps, there is a new button available in the toolbar. But first, you need to amend or add an app registration to allow access to Logic Apps.&lt;/p>
&lt;p>Register or amend an App registration. API Permissions required are Azure Service Management/user impersonation&lt;/p>
&lt;p>&lt;a class="link" href="https://user-images.githubusercontent.com/43988771/107113837-75a41e00-6859-11eb-954c-aecbdc253857.png" target="_blank" rel="noopener"
>&lt;img src="https://linked365.blog/images/2021/02-107113837-75a41e00-6859-11eb-954c-aecbdc253857.png"
loading="lazy"
>&lt;/a>&lt;/p>
&lt;p>In the application, select the Connect to Logic Apps button&lt;/p>
&lt;p>&lt;a class="link" href="https://user-images.githubusercontent.com/43988771/107113888-c9af0280-6859-11eb-9bae-327743f74da2.png" target="_blank" rel="noopener"
>&lt;img src="https://linked365.blog/images/2021/02-107113888-c9af0280-6859-11eb-9bae-327743f74da2.png"
loading="lazy"
>&lt;/a>&lt;/p>
&lt;p>Populate the API connection pop up with the appropriate settings. &lt;/p>
&lt;p>Firstly, the Subscription Id can be found on your Logic App Overview, the purple box here&lt;/p>
&lt;p>&lt;a class="link" href="https://user-images.githubusercontent.com/43988771/107113966-4d68ef00-685a-11eb-850e-fbbfe0e9740d.png" target="_blank" rel="noopener"
>&lt;img src="https://linked365.blog/images/2021/02-107113966-4d68ef00-685a-11eb-850e-fbbfe0e9740d.png"
loading="lazy"
>&lt;/a>&lt;/p>
&lt;p>Next, the Application Id and Tenant Id both are available on the App Registration page, the red and yellow items here&lt;/p>
&lt;p>&lt;a class="link" href="https://user-images.githubusercontent.com/43988771/107114017-a5075a80-685a-11eb-9723-b4686c7e11c7.png" target="_blank" rel="noopener"
>&lt;img src="https://linked365.blog/images/2021/02-107114017-a5075a80-685a-11eb-9723-b4686c7e11c7.png"
loading="lazy"
>&lt;/a>&lt;/p>
&lt;h2 id="httpsgithubcomlinked365flowtovisiothe-return-url-needs-to-be-specified-as-a-mobile-and-desktop-application-1the-return-url-needs-to-be-specified-as-a-mobile-and-desktop-application">&lt;a class="link" href="https://github.com/LinkeD365/FlowToVisio#the-return-url-needs-to-be-specified-as-a-mobile-and-desktop-application-1" target="_blank" rel="noopener"
>&lt;/a>&lt;strong>The Return URL needs to be specified as a Mobile and Desktop application&lt;/strong>&lt;/h2>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2021/02-Logic-App.gif"
loading="lazy"
>&lt;/p></description></item><item><title>Role Documenter - XrmToolBox Tool</title><link>https://linked365.blog/2020/12/22/role-documenter-xrmtoolbox-tool/</link><pubDate>Tue, 22 Dec 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/12/22/role-documenter-xrmtoolbox-tool/</guid><description>&lt;img src="https://linked365.blog/images/2020/12-RoleDocumenter.gif" alt="Featured image of post Role Documenter - XrmToolBox Tool" />&lt;p>As you can see from the various &lt;a class="link" href="https://linked365.blog/tag/xrmtoolbox/" target="_blank" rel="noopener"
>tools&lt;/a> I have produced this year, documentation is the bane of my life. I love developing, coding and producing solutions, but invariably end up at a customer with the unenviable task of documenting either the solution we have developed or one that has been in situ for a while.&lt;/p>
&lt;p>One of those daunting documentation tasks is security roles. Imagine being able to click a button and get an excel spreadsheet of a role you have just published, allowing you to stop taking screenshots or spending half a day losing the will to live in filling out a spreadsheet. This is where the Role Documenter comes in.&lt;/p>
&lt;p>This tool is different from the rest, as there was a tool in existence. Santosh Bhagat, a wonderful D365 developer from Gurgaon had created the &lt;a class="link" href="http://dotnetdeveloper2012.blogspot.com/2018/09/dynamics-crm-export-security-role.html" target="_blank" rel="noopener"
>Role Documenter&lt;/a> back in 2018, and for lots of reasons, was not kept up to date. So, rather than recreating the wheel, I reached out to Santosh, asked to help him bring his tool back to the masses and this is the result. I am grateful to Santosh for allowing me to continue with his brilliant idea and expand it&amp;rsquo;s capabilities.&lt;/p>
&lt;p>If you have any requests or bugs, please let us know on GitHub &lt;a class="link" href="https://github.com/santoshCRM/Export-Security-Role" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I brought back a Security Role documenter to the XrmToolBox to allow documentation of the Security Roles in your Dataverse projects.&lt;/p>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>Load the tool from XrmToolBox, under Role Documenter. Connect to your environment and select a role.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/12-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>At the top are 2 buttons, Export will create an Excel file with all the tables and miscellaneous privileges in 2 tabs.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/12-image-2-1024x497.png"
loading="lazy"
>&lt;/p>
&lt;p>Selecting the other button, Export D365 Layout (I realise this should be Dataverse nowadays) an Excel with the tabs that mimic those available in the Dataverse role screen is generated.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/12-image-3-1024x682.png"
loading="lazy"
>&lt;/p>
&lt;p>As simple as that!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/12-RoleDocumenter.gif"
loading="lazy"
>&lt;/p>
&lt;p>There is also options to toggle between Display names and logical names.&lt;/p>
&lt;p>I hope this helps those that are stuck with documentation and all the praise needs to go to Santosh!&lt;/p></description></item><item><title>Fundraising and Engagement for D365 Sales</title><link>https://linked365.blog/2020/11/30/fundraising-and-engagement-for-d365-sales/</link><pubDate>Mon, 30 Nov 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/11/30/fundraising-and-engagement-for-d365-sales/</guid><description>&lt;img src="https://linked365.blog/images/2020/11-image-2.png" alt="Featured image of post Fundraising and Engagement for D365 Sales" />&lt;p>There is a new app on the block. At the end of October, Microsoft &lt;a class="link" href="https://cloudblogs.microsoft.com/dynamics365/bdm/2020/10/21/announcing-the-new-fundraising-and-engagement-solution-from-microsoft/" target="_blank" rel="noopener"
>announced&lt;/a> their latest pitch to drive adoption of Dynamics in the Non-Profit sector. They have been using their Tech for Social Impact initiative to brilliant effect over the last couple of year, introducing and encouraging adoption of a Common Data Model across development partners, not just Microsoft, to reduce the burden of integrating systems for these traditionally financially restricted organisations.&lt;/p>
&lt;p>Fundraising and Engagement for Dynamics 365 Sales (like a long title don&amp;rsquo;t they) is the next step on their philanthropic journey. Using IP created by Mission CRM and their experience, they have produced an app which sits on top of a standard D365 Sales implementation, providing a solution dedicated to the non-profit sector.&lt;/p>
&lt;p>In this blog post, I will run through some of the highlights of this new application and how you can configure it to your charities needs.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>Microsoft has announced a new Fundraising and Engagement solution to build on their CDM for non-profits. A walkthrough on the highlights of the application and some configuration.&lt;/p>
&lt;h3 id="installation">Installation&lt;/h3>
&lt;p>All I have done to show you the screens and functionality here is to go through the steps mentioned &lt;a class="link" href="https://appsource.microsoft.com/en-us/product/dynamics-365/msnfp.msftnonprofitfundraisingandengagement" target="_blank" rel="noopener"
>here&lt;/a> to install the sample application. If you were doing this as a customer, there are quite a few hoops to go through, particularly on the configuration of payment gateways and parts of the application in Azure.&lt;/p>
&lt;p>The default configuration is readily available in &lt;a class="link" href="https://github.com/microsoft/fundraising-and-engagement" target="_blank" rel="noopener"
>GitHub&lt;/a>, open-source, and steps to deploy to Azure are available. You are reliant on Azure to host the services the app requires. Microsoft states that the required Azure credits you need for a typical implementation are covered by the free Azure credits available to not for profits. If you are unsure about deployment or cost, please reach out to a partner. There are some big names that are building teams to deploy this solution and I am sure there is someone at every price point.&lt;/p>
&lt;h2 id="development">Development&lt;/h2>
&lt;p>The application has 6 areas, Development, Fundraising, Gifts, Events, Reports and Configuration.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Starting with Development, which is equivalent to Sales within a standard Sales deployment, the solution provides a dashboard. The Development Overview shows large gifts received, open opportunities and other charts to highlight areas of concern for the organisation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-1.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="contacts">Contacts&lt;/h3>
&lt;p>Contacts have had a makeover, building on the CDM for Fundraising published separately and discussed in my previous posts &lt;a class="link" href="https://linked365.blog/2020/07/09/accelerators-nonprofit-fundraiding/" target="_blank" rel="noopener"
>here&lt;/a>. Firstly, the main Contact form has a new section in the middle. This is a web page, provided as part of the solution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>The central column, called the Contact Snapshot, highlights some great stats and information on the Contact. First up, the latest, active opportunity. These opportunities can be those that are associated with a pledger or a receiver, as both are tracked as opportunities within the CDM.&lt;/p>
&lt;p>The content of this panel can be configured (parts can be turned on and off) in the configuration, but this shows the whole amount of detail available. The next section highlights gift statistics for the individual.&lt;/p>
&lt;p>Household details highlights the members of the household, each tab and totals for the household giving.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>There is also a shortcut button to update the Address of the household. This brings up a webpage allowing a selection of the household address from the addresses of the contacts associated with the household.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Across the top of the Contact record is a series of new buttons. Some of these can be toggled in settings.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>Update Address repeats the functionality above, and it updates the Household address.&lt;/p>
&lt;p>The rest are pretty self explanatory, and will be highlighted further down in the article.&lt;/p>
&lt;h3 id="organisations">Organisations&lt;/h3>
&lt;p>Like the accelerator CDM, accounts are split between organisations (companies who give or receive donations) and households (links between contacts which you need to be aware of when communicating with them).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>The organisation again has the Snapshot panel, highlighting the Opportunity (Discovery which is a new term) and history of gifts for the organisation. The Add to Discovery button at the top indicates that there is currently no opportunity active for this organisation and allows you to create one.&lt;/p>
&lt;p>There does seem to be a reload script, as if you change the form at the top, you get a reload back to the appropriate form.&lt;/p>
&lt;h3 id="households">Households&lt;/h3>
&lt;p>Households, as already discussed, are groups of contacts to ensure you have a good understanding of interactions between contacts to allow you to see similar interests and opportunities to increase funding.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>The snapshot is present, but there are fewer options on the top bar to create gifts etc as these are on the Contact rather than the household.&lt;/p>
&lt;h3 id="opportunities">Opportunities&lt;/h3>
&lt;p>Opportunities have had a make over as well. There is a lot of the CDM now available on the first tab, Summary.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>The Preferences tab has 2 web pages embedded, showing the existing and ability to add Preferences or objectives applicable to the Opportunity. When adding these, they also add to the associated contact or organisation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>The next tab is Reporting Plan. Reporting is essential to the fundraising industry to ensure donors are told how their money is spent and also to ensure the governance and transparency of the spending to everyone concerned. The solution has added another web resource to allow you to create these easily.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>Stage History is an example of great use of existing data and presenting it in a way that makes sense and highlights the progress of the opportunity. Simple, but effective use of a web resource.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>Designation Plan is another web resource, where you can split the opportunity amount to different recievers. With big donations, ensuring the projects receive the appropraite amounts is essential part of the process.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>The screen allows you to create designations and show the percentage or amount to split. It also allows groupings of designations to split appropriately.&lt;/p>
&lt;h3 id="transactions">Transactions&lt;/h3>
&lt;p>Transactions are the heart of any fundraising organisation (let&amp;rsquo;s not debate volunteers vs money priority). Microsoft (well Mission) has done some great work to really easy the pain in processing gifts and contributions. This part is really reliant on the Azure services, processing transactions is not a simple thing.&lt;/p>
&lt;p>As you can see, the first tab is populated with a large web form. This allows you to easily create and process the transaction.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>Designations, how the donation is split is the next tab. Another web resource to allow easy data entry.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-15.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="donor-commitments">Donor Commitments&lt;/h3>
&lt;p>Pledges are another vital part of the fundraising landscape. Keeping a strong pipeline of donations is vital for cashflow and continued funding of projects.&lt;/p>
&lt;p>The solution allows quick processing of the gift with a web resource improving data entry.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-16.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="payment-schedule">Payment Schedule&lt;/h3>
&lt;p>Once we have a commitment, payments can come in monthly, quarterly or any sort of structure. This generation of schedules has always been a pain, with the donor wanting flexibility and the charity wanting structure.&lt;/p>
&lt;p>The solution again is a custom web resource which highlights the key data entry parts and pushes the processing to the back end.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-17.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="fundraising">Fundraising&lt;/h2>
&lt;p>Another area that is part of the application if Fundraising. This area focuses more on marketing of fundraising rather than the selling done in the Development area. The bigger picture, how organisations pitch their programmes and campaigns.&lt;/p>
&lt;p>The Dashboard available gives a great overview of the campaigns and bigger picture of raised funds.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>The first group of functionality has already been demonstrated, namely Contact, Organisations and Households. Manage Campaigns includes Campaigns, Appeals and Packages. These look like standard CDM based forms with nothing implicitly added by the solution. If anyone knows any more, then let me know.&lt;/p>
&lt;h2 id="events">Events&lt;/h2>
&lt;p>A great way of generating donations are events. Whether it is a big, tabled fundraiser or a small online meeting, management of the activity, selling packages to participate and, crucially, generating revenue from these is essential.&lt;/p>
&lt;p>The Events dashboard is simply a list of the current events and their revenues.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Next up, there is Contacts, Households and Organisations again. There is also Campaigns and Lists, pretty standard fair.&lt;/p>
&lt;h3 id="event-setup">Event Setup&lt;/h3>
&lt;p>Event setup is where Microsoft has added detail to drive event registrations. It has a lot of grids for associated records to allow the functionality on event registration to work.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>The second tab is full of details on the venue. The third tab is where it gets interesting. Event Components has a bunch of secondary grids where you configure parts of the event, from Disclaimers (to ensure each donor registration has the proper agreement from the donor) through to Donations (add on to supplement the event registration).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>This configuration comes into it&amp;rsquo;s own when you register a contact for an event. From the top of a contact, you can use the Add Registration button. Select the Event and we then can step through the various parts of the registration, starting with confirming the declaration is accepted.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>The top line is a business flow like. Hardcoded, but walks you through the available options for the events, starting with Sponsors. The number of sponsors for an event are shown as well as the ability to connect the contact to the sponsorship.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>Next is the ticket options, either a table or individual tickets in this case, but you establish on the event configuration what is available. The options you select here feed into the next screens. Here, I have selected a table of 5 and one single ticket.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>As I selected tickets in the previous screen, attendees is next. If there was no tickets selected, you are taken straight to Products.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-28.png"
loading="lazy"
>&lt;/p>
&lt;p>Once you have entered each of the attendees, you are presented with the Preferences screen, defining any peculiarities for catering for these high value attendees&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>If you click Any Allergies, the resulting text box becomes required.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>Products is next, merchandising can bring in big contributions to a charity and so upselling these at the point of registration, small items when they are buying high value could be beneficial.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, it the Purchase section. You can take part or full payment while you are entering data.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-33.png"
loading="lazy"
>&lt;/p>
&lt;p>Each of the payment types presents different forms, here you can see the Credit/Debit card entry screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>Once this is all done, the Azure deployed API will generate all the required records for you, creating a Registration Package and other associated records&lt;/p>
&lt;h3 id="ticket-registrations">Ticket Registrations&lt;/h3>
&lt;p>Ticket Registrations hold the link between an individual and a ticket. A package has many registrations to link the package and the person who bought it with the people that will be attending.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/11-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Here, on the right, you can see the preferences that were recorded. Tables are recorded separately, to record who is on which table as part of the package.&lt;/p>
&lt;h2 id="overall">Overall&lt;/h2>
&lt;p>The Fundraising and Engagement app is a great example of a knowledgeable partner, both in terms of the industry and experience in extending Dynamics 365 is able to do. There is a lot of capabilities that I haven&amp;rsquo;t covered, payments are managed and can be linked to a provider for example, but you can tell anyone in the fundraising space should try and utilise this package, at least in some part in their deployments.&lt;/p></description></item><item><title>MB-220 - Dynamics 365 Marketing</title><link>https://linked365.blog/2020/11/10/mb-220-dynamics-365-marketing/</link><pubDate>Tue, 10 Nov 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/11/10/mb-220-dynamics-365-marketing/</guid><description>&lt;img src="https://linked365.blog/images/2020/11-dynamics365-for-marketing-functional-consultant-associate-600x600-1.png" alt="Featured image of post MB-220 - Dynamics 365 Marketing" />&lt;p>Microsoft has 4 main functional exams, each focused on a separate application. Sales, Service and Field Service are all parts of the suite that I have worked in anger (deployed at a client) but the fourth in the series, Marketing is an application that I never have had much involvement with.&lt;/p>
&lt;p>Yes, I know what it is capable of, as a Technical or Solution Architect, you are expected to at least know the concepts of every application, but the stars never lined up to give me an exposure of it in a real-world situation.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>Short description of my experience of the D365 Marketing exam and links to my Mind Map.&lt;/p>
&lt;h2 id="exam-content">Exam Content&lt;/h2>
&lt;p>Microsoft has changed the content to include Customer Voice rather than Forms Pro recently, so make sure you are looking at the correct version.&lt;/p>
&lt;p>&lt;a class="link" href="https://docs.microsoft.com/en-gb/learn/certifications/exams/mb-220" target="_blank" rel="noopener"
>https://docs.microsoft.com/en-gb/learn/certifications/exams/mb-220&lt;/a>&lt;/p>
&lt;p>Like all the new exam, Marketing starts with some scenarios. Each lengthy scenario discusses a project you, as the Marketing Functional consultant is to be part of, then asks you various questions on the aspects of the project. I have found that some are relevant, and some are just fluff, like the person who wrote the question was paid by the word. As I gain experience in these exams, I skim each of the pages describing the project before digging into the questions. The questions sometimes just have a tenuous link to the project, others you need to rely on the content provided, to determine the customer&amp;rsquo;s views on compliance, for example.&lt;/p>
&lt;p>The rest of the questions do cover the whole remit of marketing. You work through creating segments, sending out emails, creating events, defining subscription centres and generating leads. I didn&amp;rsquo;t receive anything on the GPDR constraints available, though that might be because of the exam is global rather than EU focused or just the luck of the draw.&lt;/p>
&lt;p>I didn&amp;rsquo;t get any content block questions or advanced template creation topics either. They are in the outline, so again, luck of the draw.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/" target="_blank" rel="noopener"
>Like the rest of my exams&lt;/a>, I created a Mind Map for Marketing, which is the way I process content to ensure I have covered everything and a quick revision aid hours before the exam. This is available &lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21295621&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p></description></item><item><title>Flow to Visio - XrmToolBox Addon</title><link>https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/</link><pubDate>Wed, 14 Oct 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/</guid><description>&lt;img src="https://linked365.blog/images/2020/10-FlowToVisio.gif" alt="Featured image of post Flow to Visio - XrmToolBox Addon" />&lt;p>Sorry, the blog has been quiet, there is only so much time to spend on out of work activities, and this tool has been my time sink in the last 6 weeks. Not complaining, loved getting back to my routes.&lt;/p>
&lt;p>Documentation for many consultants is the worst part. Implementing stuff is fun, taking the same amount of time documenting what you have delivered is not. With this in mind, I created the &lt;a class="link" href="https://linked365.blog/2020/07/06/erd-visio-builder-xrmtoolbox-addon/" target="_blank" rel="noopener"
>ERD Visio Builder – XrmToolBox addon&lt;/a>. After this, and knowing that creating Visio was pretty straight forward, I turned to another part of the Power Platform that looks a bit like a Visio diagram - Power Automate Flows.&lt;/p>
&lt;p>When you store Flows in Solutions (and you should) they are kept in the CDS environment as a JSON text field. This allows me to parse the JSON, generate appropriate Visio shapes and give you a copy of a Flow as a document you can use as a snapshot in time of what the flow was like. Obviously doesn&amp;rsquo;t replace the editor, but gives you all the information you coded as a reference which is certainly better than a bunch of screenshot images.&lt;/p>
&lt;p>In addition, for those flows not in solutions, or environments that there is no CDS, there is the option to connect directly with the Flow API, using an App and tenant ID as well as an OAuth token. Not the prettiest of solutions, but required to get at the flows that are not in solutions.&lt;/p>
&lt;p>The tool can be found &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/LinkeD365.FlowToVisio/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I created a tool to generate Visio diagrams from your Power Automate Flows.&lt;/p>
&lt;h2 id="new-features-170223">New features 17/02/23&lt;/h2>
&lt;p>As highlighted &lt;a class="link" href="https://linked365.blog/2023/02/19/flow-to-visio-solutions/" >here&lt;/a> I have added Solutions to the tool, so that you can select a solution &amp;amp; create a Visio with all the flows in it in a couple of clicks.&lt;/p>
&lt;p>This update also added more actions that were missing appropriate images.&lt;/p>
&lt;h2 id="new-features-281121">New Features 28/11/21&lt;/h2>
&lt;p>The ability to document any Comments, a preview feature from the Power Automate team. has been added.&lt;/p>
&lt;p>Also, several Community features including&lt;/p>
&lt;ul>
&lt;li>Reduced the border to the bottom edge and corrected a few dimensions&lt;/li>
&lt;li>SQL Actions with appropriate actions&lt;/li>
&lt;li>Append to String etc use proper icons&lt;/li>
&lt;li>Open file after creation&lt;/li>
&lt;li>Multi-Select for creation of Visios&lt;/li>
&lt;li>Options drop-down for concurrent, tracked properties&lt;/li>
&lt;/ul>
&lt;h2 id="walkthrough">Walkthrough&lt;/h2>
&lt;p>Load the tool and you should be present all the flows in your environment that are solution-based. This is reading from the WorkFlow entity in CDS.&lt;/p>
&lt;p>Choose a file to save the flow as.&lt;/p>
&lt;p>Hit Create Visio and that&amp;rsquo;s it. All being well, should get a prompt telling you it has generated your Visio. Go find the file and open it.&lt;/p>
&lt;h2 id="demonstration">Demonstration&lt;/h2>
&lt;p>The flow I created for connecting Alexa to Field Service looks like this.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image.png?fit=1024%2C661&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>If you expand the first Scope, there is a condition in there&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-1.png?fit=1024%2C553&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The detail for the second condition statement has a Switch statement within it, each setting a variable before responding to the user.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-2.png?fit=1024%2C349&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>As Flows go, this is not that complicated, but documenting it, opening up each of the actions, taking screenshots, is painful, and as you can see by the last screen shot, requires a magnifying glass.&lt;/p>
&lt;p>With my tool, I generate a Visio diagram. The equivalent is shown with some highlights here. Each shape is made up of several other shapes to allow me to template them. In the HTTP Request, you can see that the schema is truncated. I have &amp;ldquo;stolen&amp;rdquo; the shape to prevent overflow here &lt;a class="link" href="http://visguy.com/vgforum/index.php?topic=7997.0" target="_blank" rel="noopener"
>http://visguy.com/vgforum/index.php?topic=7997.0&lt;/a>. Thanks to Yacine for the assist.&lt;/p>
&lt;p>You can change each shapes size to fit your data, and drag that yellow dot up or down depending on whether the information is relevant to you.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see from the next picture, if you expand some of the shapes, they can contain a lot of information, in this case, the schema of the triggering call. Up to you if you want to include this, but the data is there if you do.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>Each action in the flow is documented, either with a template or generic action (no pretty colours or logo) where I have not managed to go through all the actions and possibilities. I do believe this will be like painting the Forth bridge, a never ending task.&lt;/p>
&lt;p>There are some special ones, Scope is the first. In Flow, it is a box around your actions. I decided to just place a Scope marker at the top and bottom of the actions that are grouped together. In this image, you can also see the If condition. I document both sides and have an end If action to show you where the actions for each stop, bringing together connections.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>In the next image, you can see a switch statement. This also highlights one of the limitations. If you have lots of actions, not connected, on the same line, they can overlap. Easily fixed in Visio by using Design/Re-Layout Page option. I have options to resolve this but will take a little more time.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Pre Re-layout page, with overlap&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Post Re-layout page, no overlap&lt;/p>
&lt;p>Each case statement has the condition that it is matching on and comes together with a closure action.&lt;/p>
&lt;h2 id="connect-to-power-automate-api">Connect to Power Automate API&lt;/h2>
&lt;p>Not everyone uses solutions, not everyone can as Solutions are only available on those environments with a CDS backing it. That is why I have also provided an option to connect to the Power Automate API.&lt;/p>
&lt;p>Firstly, you need to register an Application in your Azure tenant. This is documented &lt;a class="link" href="https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app" target="_blank" rel="noopener"
>here&lt;/a>. The only caveat is that the permissions required is Read on Flow, using the Flow service.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>When you click on connect to Flow API, you get a little popup box where you populate the guids from the configuration. As you can have many environments, you also have the ability to add multiple connections. Hit the + to add your first, or select one of the saved ones to edit. The label is a name for the connection.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>In Azure, Client / App Id is the yellow redacted line, Tenant is the red&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>The Environment comes from your URL that is shown when editing a flow, the purple bit below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Lastly, the Return URL is the one listed against an App configuration. You can use any url, even localhost.&lt;/p>
&lt;p>WARNING&lt;/p>
&lt;p>This needs to be a desktop application, rather than a web application!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>Once you are done, populated all the fields something like this. The&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit OK, where you will be presented with an OAuth screen, asking to login with an account.&lt;/p>
&lt;p>Choose the appropriate account or use another account and login. If all is well, you will be presented with a list of flows not in a solution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/10-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>And then you are able to document those flows too!&lt;/p>
&lt;p>You can also use the dev App Config. This is for development/testing only, so don&amp;rsquo;t use to connect to production environment, but eases the complexity. You only need the Environment and Tenant Id for this.&lt;/p>
&lt;h2 id="connect-to-logic-apps">Connect to Logic Apps&lt;/h2>
&lt;p>As Logic Apps are the big brother of Power Automate Flows, you can also use this tool to document Logic Apps.&lt;/p></description></item><item><title>Accelerators: Nonprofit - Part 3 - Awards</title><link>https://linked365.blog/2020/09/13/accelerators-nonprofit-part-3-awards/</link><pubDate>Sun, 13 Sep 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/09/13/accelerators-nonprofit-part-3-awards/</guid><description>&lt;img src="https://linked365.blog/images/2020/09-image-15.png" alt="Featured image of post Accelerators: Nonprofit - Part 3 - Awards" />&lt;p>This is the third post in the series looking at one of Microsoft&amp;rsquo;s Solution Accelerators, namely the Nonprofit version. This article will be discussing the Awards app. This app revolves around distributing funds to various projects and includes tracking of the associated programme delivery.&lt;/p>
&lt;p>I have already discussed installing and the Fundraising app in &lt;a class="link" href="https://linked365.blog/2020/07/09/accelerators-nonprofit-fundraiding/" target="_blank" rel="noopener"
>part 1&lt;/a> and the Constituents App in &lt;a class="link" href="https://linked365.blog/2020/07/30/accelerators-nonprofit-part-2-constituents/" target="_blank" rel="noopener"
>part 2&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>Walkthrough of the Awards application which is part of the Microsot Nonprofit Industry Accelerator for Dynamics 365.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;p>Objectives are the highest levels of goals, strategies or priorities for the charity, heady ideals that the charity was formed to support. These are defined with a time frame, and have a hierarchy, as you can see from the Active Objectives view.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Here, the global objective for 2019 has 3 child objectives which support it. The detail on the Opportunity is pretty sparse, though you can link to an account and define a type.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>As an example, if the charity was helping disadvantaged children, the global objective for the year could be &amp;ldquo;reduce poverty and homelessness within the charities area&amp;rdquo;. Under that global objective, this could be split to &amp;ldquo;increase number of registered foster parents in the local area&amp;rdquo;, &amp;ldquo;improve access to food banks&amp;rdquo; and &amp;ldquo;improve number of shelter spots for homeless families&amp;rdquo;.&lt;/p>
&lt;h2 id="delivery-frameworks">Delivery Frameworks&lt;/h2>
&lt;p>In the previous article on this accelerator, I briefly mentioned delivery frameworks. They can be a grouping of works or activities in IATI denoting projects and resources required to complete a project which will form some action for the charity, aiming towards the larger objectives of the charity.&lt;/p>
&lt;p>Continuing our example, the first child of the main goal is &amp;ldquo;increase number of registered foster parents in the local area&amp;rdquo;. The delivery frameworks could establish projects to &amp;ldquo;Market the positives of foster parenting&amp;rdquo; and &amp;ldquo;Provide training for new foster parents&amp;rdquo;.&lt;/p>
&lt;p>The view shows the associated accounts, start and end dates as well as the scope and the type of the framework.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-2.png?"
loading="lazy"
>&lt;/p>
&lt;p>The Delivery Framework screen allows you to enter details about the project or program to indicate the periods for the project, where the project is targetting, and a description. The Goal tab just contains the goal field, to highlight what is the full goals for the project.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>The IATI (International Aid Transparency Initiative) highlights lots of fields to document the activity in the terms that this international standard requires.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Delivery Frameworks are associated with one or more Delivery Framework Contact (the external team associated with the project) which is a thick many-to-many relationship between Contact and Delivery Framework. Also, the framework may have one or more descriptions, which document the steps and requirements for the project or programme. It also is associated with many records which will be discussed later, firstly Budgets.&lt;/p>
&lt;h2 id="budgets">Budgets&lt;/h2>
&lt;p>Budgets are pretty straight forward, a pot of cash to spend on a project.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The budget form highlights the total amount and the associated currency fields. It also denotes a name and description along with the start and end time.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>Further detail on the IATA is the second tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>Budgets can have a parent hierarchy to split them up more. Further, the budget is linked to a Disbursement via a Disbursement distribution.&lt;/p>
&lt;h2 id="dockets">Dockets&lt;/h2>
&lt;p>Dockets are groupings of requests for funding or leads towards the same. Having a high-level linking of the requests, information about multiple rewards can be combined and monitored.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>The docket can be linked to an account (Fiscal Sponsor) and a Award Recipient (which is either an account or contact).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Dockets are linked to Reviews and Requests predominately, which are discussed later.&lt;/p>
&lt;h2 id="inquiries">Inquiries&lt;/h2>
&lt;p>Inquiries are based on Leads, which we looked at last time. These are indications that an organisation or individual would like to be a beneficiary of funds.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>My previous post &lt;a class="link" href="https://linked365.blog/2020/07/30/accelerators-nonprofit-part-2-constituents/" target="_blank" rel="noopener"
>highlighted&lt;/a> the Lead record usage.&lt;/p>
&lt;h2 id="recommendations">Recommendations&lt;/h2>
&lt;p>Recommendations are used to indicate steps for a recipient of an award or record the recommendations from reviews by internal staff. This keeps the information separate from the award, which could be useful for security or data protection reasons.&lt;/p>
&lt;p>The recommendation is pretty simple, with a channel, description date &amp;amp; status. Recommendations usually come from a contact or on behalf of an organisation, so you can link them back to the recommendation here.&lt;/p>
&lt;p>![]images/2020/09-image-11.png)&lt;/p>
&lt;h2 id="requests">Requests&lt;/h2>
&lt;p>A Request is the core of any non-profit - individuals or organisations requesting to receive funds from the charity. These requests are the start of the award process, applications for funding. This is a more formal application than an inquiry or letter of interest (or Lead in the system). The default view is pretty plain.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-12.png1"
loading="lazy"
>&lt;/p>
&lt;p>The Request screen is data entry mainly, with details about the request available, including how much was requested, what is recommended and the overall project budget, including the amount that won&amp;rsquo;t be met by the charity. The request has a type and stage, to show whether it has been approved or still under review.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-13.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="ofac-match">OFAC Match&lt;/h3>
&lt;p>An important part of the Request is that the money is not used inappropriately, particularly on assets that are under question politically. In the US this is managed by adhering to the Office of Foreign Assets Control (OFAC) rules. By recording any searches against the request using the associated OFAC Match form, you can track the progress against this process.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-14.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="awards">Awards&lt;/h2>
&lt;p>An Award is the representation of the agreed funding for a request. Each Award is the grouping of all the disbursements and requests that make up the award.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>The Award screen allows the user to enter detail on the award. You can link the award to the request and docket as well as the recipient. The Award sponsor as well as now and when the award was given are also present.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>The other tabs highlight secondary information for the Award. Starting with Award Versions.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-17.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="award-versions">Award Versions&lt;/h3>
&lt;p>Award versions are a snapshot of the award at a particular point. As this accelerator is a basis for ISVs or customers to build on, I would expect a Power Automate or Workflow to generate these rather than manually creating these records. It does and distinct information on top of the award, highlighting performance measures and the status of the award.&lt;/p>
&lt;p>![]((images/2020/09-image-18.png)&lt;/p>
&lt;h2 id="disbursements">Disbursements&lt;/h2>
&lt;p>Disbursements are the actual payments that are made, with usually more than one per award, depending on the reporting and payment schedule.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Each disbursement details information on the amount, current etc as well as the link to the Award. There is also information to record when the financial aspect of the transaction is completed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>As already discussed, the information required for IATI rules are captured in the second tab.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>The related records allow the user to document the financial transaction associated with the award. Disbursements have a lot of additional data to track the accounting connected as related records.&lt;/p>
&lt;h2 id="reviews">Reviews&lt;/h2>
&lt;p>Awards will be frequently reviewed to ensure compliance with the award rules and disbursement triggers. This information is vital to ensure the donations are appropriately and safely distributed to the programmes.&lt;/p>
&lt;p>![]((images/2020/09-image-22.png)&lt;/p>
&lt;p>The Review screen allows a reviewer to link to the award and a version as well as the originating request. The status and Report are key fields too.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-23.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="reports">Reports&lt;/h2>
&lt;p>The final main entity is Reports. These are records of the information that has been sent by the entity that received an award to confirm that their progress is as expected and they are meeting the conditions of the Award. These documents are critical to the review process. I would expect reports to have a document repository associated with it to store the actual document.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>Each report has information about the provider of the report and when it was received.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/09-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>By the way, the Tab tab was not my doing. Little slip!&lt;/p></description></item><item><title>Mockaroo Data Munger - XrmToolBox Addon</title><link>https://linked365.blog/2020/08/27/mockaroo-data-munger-xrmtoolbox-addon/</link><pubDate>Thu, 27 Aug 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/08/27/mockaroo-data-munger-xrmtoolbox-addon/</guid><description>&lt;img src="https://linked365.blog/images/2020/08-Munger-1.gif" alt="Featured image of post Mockaroo Data Munger - XrmToolBox Addon" />&lt;p>Another tool I am pleased to announce - Mockaroo Data Munger!&lt;/p>
&lt;p>This tool is an interface between &lt;a class="link" href="https://mockaroo.com/" target="_blank" rel="noopener"
>Mockaroo&lt;/a> and your CDS environment. Mockaroo is an excellent random data generator which has been my go to source for data over the last couple of years for building demo or test data sets. I found myself regularly configuring Mockaroo data exports, creating Excel spreadsheets and then importing them to the latest demo environment.&lt;br>
As Mockaroo has an API, the next logical step is to bring this API to the XrmToolBox. This is so I can cut out the middle man - no need to do the export to Excel, map the data in a CDS import and wait for the import, let a tool do it for me.&lt;/p>
&lt;p>(Blame &lt;a class="link" href="https://twitter.com/TATTOOEDCRMGUY" target="_blank" rel="noopener"
>Chris Huntingford&lt;/a> for the name)&lt;/p>
&lt;h2 id="tldr">TLDR;&lt;/h2>
&lt;p>I created a tool to allow creation of random data using the Mockaroo API available in XrmToolBox &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/LinkeD365.MockarooDataMunger/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h3 id="walkthrough-of-the-tool">Walkthrough of the Tool&lt;/h3>
&lt;p>First of all, you will need a Mockaroo Key. Go &lt;a class="link" href="https://mockaroo.com/users/sign_up" target="_blank" rel="noopener"
>here&lt;/a> and sign up. A Mockaroo account is free, if you can cope with 200 requests a day, 1000 rows per request. Pretty impressive for free. In all my testing, I have never scratched these limits. As Mockaroo paid plans are intended to be used by testers, calling the api for a single record multiple times etc, for our usage, the free plan is more than enough.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/08-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>Once you have an account, go to My Account and grab your API Key.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/08-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>In the Tool, enter this in the toolbar.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/08-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>You can save this key along with your map by hitting the Save Current Map button.&lt;/p>
&lt;p>Next, select an entity. The fields that are displayed are those that are available for entry when a record is created. Certain fields aren&amp;rsquo;t, like the Create and modified Dates and users. Others are calculated/roll up fields.&lt;/p>
&lt;h2 id="choose-your-mock-types">Choose your Mock Types&lt;/h2>
&lt;p>Mockaroo provides various types of data, from address information to car makes, MAC addresses and other useful information. Useful to someone, maybe not you. These are listed &lt;a class="link" href="https://mockaroo.com/api/docs#request_body:~:text=One%20of%20Mockaroo%27s%20143%20data%20types%3A" target="_blank" rel="noopener"
>here&lt;/a>. I have transitioned those to selectable types in the grid.&lt;/p>
&lt;p>Choose a row and hit the checkbox. This will populate the mock types that are relevant to your selection - even I try to prevent text going into numbers. If there is any options for you to choose from or configuration of the type, the Options field is populated with the defaults. You can change these defaults by clicking on the little grey box (not to self, add an icon).&lt;/p>
&lt;p>A small form will pop up, allowing you to make modifications to the default selections. This could be selecting one or more choices for a picklist, setting the minimum or maximum for numbers or the number of paragraphs of random text you need for your memo.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/08-Munger2.gif"
loading="lazy"
>&lt;/p>
&lt;p>Once you are happy with your data configuration, it is time to call the API. Select the number of records you desire and hit Get Mockaroo Data.&lt;/p>
&lt;h3 id="mocked-data">Mocked Data&lt;/h3>
&lt;p>After hitting the button, the Results tab becomes available. This lists the data that has been generated for you, before you insert it in your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/08-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The raw values are displayed, as in the numeric value for any picklists and guids for any lookups. On the road map to show the friendly versions of these records.&lt;/p>
&lt;p>If you are happy, hit Create Data. This will insert the data and present any issues that are returned in doing so.&lt;/p>
&lt;p>Creating data has a lot of issues, most are down to the data. You can not assign records to users without the appropriate security rights for example. There are a multitude of rules that CDS has, particularly when using the first party apps like Sales or Field Service. These are not usually for data integrity reasons, but business logic, fired prior to the record being created.&lt;br>
Unfortunately, all I can do is present the issues to you so you can fix the data.&lt;/p>
&lt;h3 id="next-steps">Next Steps&lt;/h3>
&lt;p>I want to add Resolving cases and other business logic that is done after the record is created normally to allow simple creation of these records. I am also looking for suggestions how it can be improved, particularly around the types of data you need to generate - combining fields for example.&lt;/p>
&lt;p>Go over to the GitHub page to raise an issue &lt;a class="link" href="https://github.com/LinkeD365/MockarooDataMunger/" target="_blank" rel="noopener"
>https://github.com/LinkeD365/MockarooDataMunger/&lt;/a> and let me know what you think.&lt;/p></description></item><item><title>PL-100 - Microsoft Power Platform App Maker</title><link>https://linked365.blog/2020/08/17/pl-100-microsoft-power-platform-app-maker/</link><pubDate>Mon, 17 Aug 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/08/17/pl-100-microsoft-power-platform-app-maker/</guid><description>&lt;img src="https://linked365.blog/images/2020/08-microsoft-certified-associate-badge.png" alt="Featured image of post PL-100 - Microsoft Power Platform App Maker" />&lt;p>One of the newest exams on the block is &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/exams/pl-100" target="_blank" rel="noopener"
>PL-100 Power Platform App Maker&lt;/a>. This exam is targeted at individuals who are currently making apps for their company and want to certify their talents. I saw this exam similar to the &lt;a class="link" href="https://docs.microsoft.com/learn/certifications/exams/mb-200?WT.mc_id=techcom_learn-blog-wwl" target="_blank" rel="noopener"
>MB-200&lt;/a> exam, which is soon to be replaced with &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/exams/pl-200" target="_blank" rel="noopener"
>PL-200&lt;/a>, but I was wrong.&lt;/p>
&lt;p>The qualification associated with this exam is &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/power-platform-app-maker" target="_blank" rel="noopener"
>Power Platform App Maker Associate&lt;/a>. The exam is still in beta, so hopefully I will add this qualification to my list when it comes out of beta.&lt;/p>
&lt;p>PL-100 is really an exam for the citizen developer, a doer. It delves deep into several areas, beyond a functional consultant role and more into the nitty-gritty of developing across the Power Platform. It is still CDS (or whatever it is called today) heavy, with no mention of SharePoint apart from in one of the scenarios.&lt;/p>
&lt;p>It also covers everything, unlike &lt;a class="link" href="https://thecrm.ninja/pl-100-microsoft-power-platform-app-maker-exam/" target="_blank" rel="noopener"
>EY&lt;/a> when he took it with only a few questions on the topic, I got several Power BI questions. This is definitely not in my comfort zone, so I am glad I did some research on it before I took the exam.&lt;/p>
&lt;p>One thing it didn&amp;rsquo;t really cover, even though it says in the &lt;a class="link" href="https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE4wo07" target="_blank" rel="noopener"
>Skills Outline&lt;/a> that it is 10-15% of the exam was the soft skills. Nothing really on high-level design, components, or functional skills. May have been the random set of questions I got. Like EY didn&amp;rsquo;t get Power BI, maybe I was &amp;ldquo;lucky&amp;rdquo; not to get questions on these.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/" target="_blank" rel="noopener"
>Like the rest of my exams&lt;/a>, I did a Mind Map to help me ensure I have covered all the basis for the exam, driven by the skills outline. The Mind Map for PL-100 is &lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21288972&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://docs.microsoft.com/en-us/media/learn/certification/badges/microsoft-certified-associate-badge.svg"
loading="lazy"
>&lt;/p></description></item><item><title>Accelerators: Nonprofit - Part 2 - Constituents</title><link>https://linked365.blog/2020/07/30/accelerators-nonprofit-part-2-constituents/</link><pubDate>Thu, 30 Jul 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/07/30/accelerators-nonprofit-part-2-constituents/</guid><description>&lt;img src="https://linked365.blog/images/2020/07-image-48.png" alt="Featured image of post Accelerators: Nonprofit - Part 2 - Constituents" />&lt;p>This is the second post in a series as a tool to educate me and document the functionality in the Microsoft Industry Accelerators. This post will dig a little deeper into the Nonprofit accelerator, with the second model app available to you, namely&lt;/p>
&lt;p>Installing and a guide to the Fundraising app can be found &lt;a class="link" href="https://linked365.blog/2020/07/09/accelerators-nonprofit-fundraiding/" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Walkthrough of the Constituents application which forms a central part of the Microsoft Nonprofit industry accelerator.&lt;/p>
&lt;h2 id="constituent">Constituent&lt;/h2>
&lt;p>A constituent is a fancy term for a anyone and anything that can donate or deliver services for a charity. In typical CRM terms, they are split between Contacts - Individuals, Donors, Volunteers and Benefit Recipients and Accounts - Households, Accounts and Organisations. We also have a Leads which will qualify to Donors and Organisations in a typical CRM manner.&lt;/p>
&lt;h3 id="individual">Individual&lt;/h3>
&lt;p>Individuals are the common name for contacts. Each Contact has a Constituent type, but Individuals are all of them grouped together.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/07/image-19.png?fit=1024%2C522&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Within the My Active Contacts and Active Contacts views, an extra column is present to denote the primary constituent type, which is also present on all the forms within the header. Constituents can be Advocate, Beneficiary, Board Member, Donor, Member, Partner or Volunteer out of the box. These types are used to filter the other views available when you select a Donor or Volunteer.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>The main contact form has been tweaked to include some additional fields typical in charity situations, namely Age, Birth Month &amp;amp; Year, Primary Constituent Type, Reports to (a link to another contact) and Contact Account Number.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-21.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="donors">Donors&lt;/h3>
&lt;p>Donors are a type of contact, denoted by the Constituent type. A view is provided for Active Donors.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>As you drill down into a donor, the form has a few extra fields, notably Anonymous? and Deceased? The anonymity of donations is a must for a lot of people so this will be a very obvious indication that no publicity should be done for this donor. Deceased, though morbid, is an essential property for legacy donations or planned giving.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>Donor is the hub to donor commitments and lots of other parts of the application. There are a whole host of related entities associated with it, which are covered in other posts.&lt;/p>
&lt;h3 id="volunteers">Volunteers&lt;/h3>
&lt;p>Volunteers are a crucial part of any non-profit, essential to reduce the overheads of the charity on completing their aims and evangelising the charity. There is a simple view of Active Volunteers, filtered where the primary type is Volunteer.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>The Volunteer form has Deceased? added to it too. It also has a Related tab, listing Salutations and Preferences.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-26.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="salutations">Salutations&lt;/h4>
&lt;p>When working with volunteers or any contact, ensuring you are addressing them in the appropriate manner is essential. Donors can be very particular about how they are presented in official communications or even on the phone. They could be a Count, Sir, Senator or President and it is essential that the relationship between the charity and the donor is not spoilt by using a term that is not acceptable to them.&lt;/p>
&lt;p>From my previous experience working with charities, salutations can make or break a relationship. Donors want to be treated appropriately and with respect and any slight deviation from this can result in the donation or sponsor disappearing, leaving the charity with lost relationship and a fight to rebuild the relationship.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see there are a lot of fields on this form, all to ensure you address them correctly. Also, the type denotes where this salutation should be used, from formal and informal names to statements and how to address in public. They may want to be called Dave in an informal setting, but The Rt Hon Sir David Duncan MP, Secretary of State for Fungus in a formal setting or letterhead. &lt;a class="link" href="https://www.debretts.com/" target="_blank" rel="noopener"
>Debrett&amp;rsquo;s&lt;/a> have made a whole industry out of it in the UK. I assume the rest of the world has its own rules, maybe not as extensive as ours.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-28.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="preferences">Preferences&lt;/h4>
&lt;p>Just as important to a donor is to ensure their dietary or other preference on their interaction with the non-profit. The documentation also states that this should be used to denote any type of information that can be associated with a Contact or Account but not directly on the record, such as personal interests, indications on receiving communication types. They are key to drive a relationship forward - understanding that they like golf, and more importantly, they like this topic to be discussed is essential to maintaining long term relationships with donors.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>Confidence denotes whether this information is just inferred, for internal use or confirmed via some means.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>Key and priority denote the ranking on this information, as well as the weight, which is numeric to highlight information that should drive the conversation. There are also dates on here, to denote those bits of information that are temporary.&lt;/p>
&lt;h2 id="households">Households&lt;/h2>
&lt;p>Households are based on the account entity. They are defined around the premise that many contacts reside in a household, but have no organisation other than that group. A view is made available for Active Households.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>The form on the account entity has some additional fields, such as Account Type, which is used to filter the above view. The form is really a stripped-down version of the standard account form, with information irrelevant to a household hidden. The details tab does hold account type and when the Household was acquired or became of interest to the nonprofit.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-32.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="address">Address&lt;/h3>
&lt;p>Though it is mentioned heavily in the documentation, Addresses are not available in the Related navigation. It might be my environment, it might be my mistake. There is an awful lot of related entities available, which would have no relevance to a Household. I would hope that this is my mistake and not how Microsoft wants it to appear.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see, the Address form has some significant fields added to it. Dates for a start. The addresses maybe temporary for summer housing etc. so they have added a Start and End date to the form. These dates are also augmented with a Seaosonal start/end month/day which indicates that this address is normally the&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Households are built up of contacts of various types, as we have discussed, Salutations, for when you address the household group, Addresses and connections.&lt;/p>
&lt;h2 id="organisations">Organisations&lt;/h2>
&lt;p>Organisations are a type of Account. They have their own view, driven by the Account Type field.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-40.png"
loading="lazy"
>&lt;/p>
&lt;p>The Organisation form is pretty vanilla, with a couple of extra fields, Acquisition Date/Source and Constituent Type. My option sets are tied to local options sets rather than global, this may be a corruption of my environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-41.png"
loading="lazy"
>&lt;/p>
&lt;p>There is an additional tab, IATI. This stands for &lt;a class="link" href="https://en.wikipedia.org/wiki/International_Aid_Transparency_Initiative" target="_blank" rel="noopener"
>International Aid Transparency Initiative&lt;/a> which is a campaign to create transparency in the spending and receiving of aid money. This global set of rules defines what to document and how to ensure any money is spent on the intended recipient.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-42.png"
loading="lazy"
>&lt;/p>
&lt;p>Organisations are completed with Addresses, salutations, connections and preferences as already discussed.&lt;/p>
&lt;h2 id="benefit-recipient">Benefit Recipient&lt;/h2>
&lt;p>As a nonprofit takes in contributions, they have to ensure the funds get disbursed to the relevant organisation or individual. These are called Benefit Recipients in the accelerator.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-43.png"
loading="lazy"
>&lt;/p>
&lt;p>The form is pretty sparse. Most of the detail is in the associated records. You can see though there is a hierarchical relationship on benefit recipients, as well as a type. You can associate a benefit recipient with either an account or contact. If the benefit recipient is not an account or contact but a thing such as an area or animal then the recipient is associated with a Resource Catalog.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-44.png"
loading="lazy"
>&lt;/p>
&lt;p>Like I have already alluded to, the Benefit Recipient is a simple entity, the linked entities is where the information is held. I wonder why Microsoft did not include more of the secondary records on the main form rather than relying on the Related fields. I assume, as the accelerator is meant to be a starting template, each nonprofit would have their own requirements for which grids would be used, and it is simpler to allow customisation from a blank slate.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-45.png"
loading="lazy"
>&lt;/p>
&lt;p>Benefit Recipients displays any child records associated with this record. Delivery Frameworks indicate the project or programme to which the funds will be given. Disbursements are indicators of actual funds that went out to a recipient. Indicator Values are measures that trigger the benefit recipient. Each of these entities is part of a larger application so will delve into their detail in subsequent posts.&lt;/p>
&lt;h2 id="leads">Leads&lt;/h2>
&lt;p>With any organisation, Leads are an essential way of bringing in new opportunities to an organisation. In the nonprofit world, Leads are defined around bringing in new donors and organisations, and to a lesser extent volunteers. They can also be used to indicate interest in an award or grant from the nonprofit via a delivery framework, less formal than a Request.&lt;/p>
&lt;p>On the form, there are several fields for where the lead is to become a beneficiary of funds, indicated in the Red boxes below. The expected amount, when they want the funds, how long for are listed. The Application deadline and letter of intent date, request type and is a renewal fields are available to denote information about applications. Dockets are a groupings of leads to be discussed at a programme board or similar where decisions on individual applications are made.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-47.png"
loading="lazy"
>&lt;/p>
&lt;p>The orange box indicates fields relevant when the lead is for a benefactor individual or organisation.&lt;/p>
&lt;p>The other tabs are standard D365 information. Leads are the starting point for many things, so are related to the entities that a lead converts to as well as entities that track the donation as it progresses through your organisation as well as entities that ensure the funds are received and distributed accurately and transparently.&lt;/p>
&lt;h2 id="dashboards">Dashboards&lt;/h2>
&lt;p>There are a couple of Constituent dashboards, around Households and Organisations&lt;/p>
&lt;h3 id="households-1">Households&lt;/h3>
&lt;p>The first set of graphs are breaking down Active Donor commitments by Household broken down by household then by commitment type. The bar chart breaks down active commitments per household, broken down by campaign.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-48.png"
loading="lazy"
>&lt;/p>
&lt;p>The next graph shows each household and the value committed over time. The final list shows donor commitments associated with households.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-49.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="organisations-1">Organisations&lt;/h3>
&lt;p>The organisation dashboard is very similar, indicating commitments associated with an organisation rather than a household.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-50.png"
loading="lazy"
>&lt;/p>
&lt;p>The left pie chart highlights the number of pledges by organisations and the right shows those pledges by commitment type.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-51.png"
loading="lazy"
>&lt;/p>
&lt;p>The final pair of graphs highlight the pledges per organisation by campaign and the value of those pledges per organisation over time.&lt;/p></description></item><item><title>Accelerators: Nonprofit - part 1 - Fundraising</title><link>https://linked365.blog/2020/07/09/accelerators-nonprofit-part-1-fundraising/</link><pubDate>Thu, 09 Jul 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/07/09/accelerators-nonprofit-part-1-fundraising/</guid><description>&lt;img src="https://linked365.blog/images/2020/07-image-68.png" alt="Featured image of post Accelerators: Nonprofit - part 1 - Fundraising" />&lt;p>Microsoft Dynamics is a great set of tools, which cover a lot of the requirements for most situations. These Sales and Service tools tend to focus on a generic requirement rather than those that can be specific to an industry. To get a more specific version of the application, one that is more suited for an industry vertical, Microsoft provides several Accelerators.&lt;/p>
&lt;p>The accelerators are a set of content to transpose your environment to be a starting point, tweaking the standard offerings towards an industry standard. These solutions have been designed with industry experts to enable a quick, easy starting point for many verticals, with functionality specific to them.&lt;/p>
&lt;p>As I know very little, apart from that they are there, I wanted to learn about the functionality in each and share my experience with you, starting with the Nonprofit accelerator.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Microsoft provides several industry-specific groups of functionality, called Accelerators. This post highlights the functionality available to you within the nonprofit accelerator, starting with how to get it for free and the Fundraising application.&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>The Dynamics 365 Nonprofit Accelerator is available on Appsource &lt;a class="link" href="https://appsource.microsoft.com/en-gb/product/dynamics-365/msnfp.msftnonprofitcommondatamodel?src=office&amp;amp;tab=Overview" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-68.png"
loading="lazy"
>&lt;/p>
&lt;p>The packages are also available on GitHub, the AppSource version allows for an installation of all the components easily. This accelerator is also available for a Test Drive. this allows you to log in a pre-configured environment to take a look around the available functionality, without introducing it to any of your own systems.&lt;/p>
&lt;p>As it takes longer than the 24 hours duration of the test drive for me to get to write a blog post, I am going to install the application on a trial environment, so select Get It Now.&lt;/p>
&lt;p>Fill out a simple form and accept the terms.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-69.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit continue and select an appropriate environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-70.png?fit=1024%2C497&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Accept the required permissions and you are presented by the following screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-71.png"
loading="lazy"
>&lt;/p>
&lt;p>I selected those that were available to me, no PSA in my standard, blank environment. Now we get an install initiated screen and we wait&amp;hellip;.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-72.png"
loading="lazy"
>&lt;/p>
&lt;p>When you now launch D365, you get several new applications, firstly Fundraising.&lt;/p>
&lt;h2 id="fundraising">Fundraising&lt;/h2>
&lt;p>The fundraising app is designed around raising money for your charity or nonprofit. It revolves around donation commitments. These are the high-level commitments agreed. Each commitment may have one or more scheduled payments, leading to transactions. Each commitment is associated with an Account or Contact.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-73.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="commitment-screen">Commitment Screen&lt;/h3>
&lt;p>Drilling down into a Commitment, you get a screen with 3 columns. In the first column, is the name and description of the commitment. Anonymity, a yes/no picklist allows the pledge to remain anonymous, great for the high rollers I guess. Next comes the date when the commitment was made. The Commitment type is a choice of Sustainer, Installment or In-kind. Sustainer pledges are those where you commit to a regular payment, indefinitely. A monthly donation to a charity would be considered a Sustainer Pledge. Instalment is a one-off commitment, over one or more payments, but there is a set timeframe for the obligation. Finally, In-kind pledge indicates a product or service committed by the donor, which is not cash. The commitment can also be marked as bookable. This is for use in the Volunteer management section of the app.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-82.png"
loading="lazy"
>&lt;/p>
&lt;p>The second section denotes whether this commitment came from a planned giving, where a donor includes the charity in their will. You also indicate which account and/or contact the pledge was made by and it may also be on behalf of another account. Next are a set of fields to indicate the total amount, payment dates and amounts as well as the currency.&lt;/p>
&lt;p>The final column shows where the pledge came from, the campaign, and where it is going to. Designations are projects with specific funding that may arise to pledges being designated directly to them rather than the charity as a whole.&lt;/p>
&lt;h3 id="iati">IATI&lt;/h3>
&lt;p>The next tab allows the user to log details about the donation to ensure the transparency of donations. &lt;a class="link" href="https://en.wikipedia.org/wiki/International_Aid_Transparency_Initiative" target="_blank" rel="noopener"
>International Aid Transparency Initiative&lt;/a> (IATI) is a campaign to ensure transparency in recording and spending donations to charities. This standard indicates the information that a non-profit should record when logging donations and spending them.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-83.png"
loading="lazy"
>&lt;/p>
&lt;p>The final tab highlights the created and modified info for the commitment.&lt;/p>
&lt;h3 id="payment-schedule">Payment Schedule&lt;/h3>
&lt;p>Associated with Commitments are payment schedules. These indicate the series of payments that will form the total for the commitment. This screen highlights all the information of an expected payment, how often, when it starts and how many payments.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-84.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="transactions">Transactions&lt;/h3>
&lt;p>Transactions are actual payments received. These can be linked to pledges, where the donation was planned or directly to an account for when they are not. Each transaction has an amount, currency, booked and received dates and a type of entry (either data entry or via an integration). The transaction can also be anonymous if required. As everyone makes mistakes this transaction can be an adjustment to previous transactions.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-85.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="planned-giving">Planned Giving&lt;/h3>
&lt;p>Planned giving is a pledge to bequeath an amount, either money or assets, in the will of a donor on their death. This part of fundraising is significant for charities which provide support for individuals in times of hardship and makes up a large proportion of giving across the charitable sector. Planned giving could also be Living trusts.&lt;/p>
&lt;p>The main screen allows data entry of the details for the planned giving, with links to Household and campaign, as well as fields for Amount, stage and the type of bequest being available. Further, feels to account for capital gains tax as well as deductions are available.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>The Details tab highlights more detail about the giving and has fields to denote market values for assets that have been bequeathed, rather than cash.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The Trust tab defines more fields to document a Living Trust, such as how much of the trust is pledged and distribution dates.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>The Giving tab highlights information about the payments that will be part of the Planned Giving.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>A method of donating via Planned Giving is to gift a Life Insurance policy, where it has been nearly paid up and hence it is of value to the charity. The Insurance tab highlights some fields to detail this contribution.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, details about when Planned giving was triggered. A bit morbid, but essential with the bequeaths.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>The Planned Giving can be associated with commitments which detail payments and converts the planned to the actual. It can also be linked to a Payment Asset where the payment is not a cash payment rather whole or part of an asset with value.&lt;/p>
&lt;h3 id="membership">Membership&lt;/h3>
&lt;p>A lot of fundraising is conducted by offering the pledger services or products in exchange for their donation. This can be in the form of a membership to the organisation, with each membership having a category and associated with products. For example, offering access to a garden or listed building for the year would be a membership donation.&lt;/p>
&lt;p>The Membership screen is quite simple, indicated the start and end date of the membership as well as the status and a link to the contact or account that has the membership.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>Each membership can be associated with one or membership Categories. These are grouping of products to define the offer to the customer.&lt;/p>
&lt;h3 id="designations">Designations&lt;/h3>
&lt;p>A commitment can be allocated to a certain project within the charity, these are called Designations. Each designation can be part of a larger project, there is a parent-child connection between designations.&lt;/p>
&lt;p>The designation screen defines the details on the project including the Geneal Ledger information for accounting purposes.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>Sometimes, a donor may state that rather going to one designation, the donation is split between projects and as such, the designation can be associate with one or more commitments via the designation plan when this occurs.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-15.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="campaigns">Campaigns&lt;/h2>
&lt;p>A large proportion of a fundraisers role is targeted marketing of the charity across numerous mediums to improve the donation rate. Campaigns for Not for Profit are based around standard Marketing Campaigns with some tweaks for the Nonprofit sector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-17.png"
loading="lazy"
>&lt;/p></description></item><item><title>ERD Visio Builder - XrmToolBox addon</title><link>https://linked365.blog/2020/07/06/erd-visio-builder-xrmtoolbox-addon/</link><pubDate>Mon, 06 Jul 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/07/06/erd-visio-builder-xrmtoolbox-addon/</guid><description>&lt;img src="https://linked365.blog/images/2020/07-ERD-Visio.gif" alt="Featured image of post ERD Visio Builder - XrmToolBox addon" />&lt;p>As with my &lt;a class="link" href="https://linked365.blog/2020/06/18/d365-org-db-settings-xrmtoolbox-addon/" target="_blank" rel="noopener"
>Org Settings&lt;/a> tool, creating Visio diagrams to represent and document your entities and relationships in Dynamics has long been on my list to find a better solution than making them yourself.&lt;/p>
&lt;p>There is already a couple of Entity visualisers in the XrmToolBox suite, but non that output to Visio.&lt;/p>
&lt;p>The project is available in &lt;a class="link" href="https://www.xrmtoolbox.com/plugins/LinkeD365.ERDVisioBuilder/" target="_blank" rel="noopener"
>XrmToolBox&lt;/a>, source &lt;a class="link" href="https://github.com/LinkeD365/ERDVisioBuilder" target="_blank" rel="noopener"
>here&lt;/a> and I am indebted to &lt;a class="link" href="https://twitter.com/saveenr/" target="_blank" rel="noopener"
>Saveen Reddy&lt;/a> for his code to automate the creation of Visio diagrams, &lt;a class="link" href="https://github.com/saveenr/VisioAutomation.VDX" target="_blank" rel="noopener"
>here&lt;/a>. Also, &lt;a class="link" href="https://twitter.com/rappen" target="_blank" rel="noopener"
>Jonas Rappen&lt;/a>, again, supported me. We have discussed bring Visio to his &lt;a class="link" href="https://jonasr.app/uml/" target="_blank" rel="noopener"
>UML Diagram Generator&lt;/a> and merge the two. When I say merge, I mean I piggyback on all his more excellent work with the bit I did.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I created a tool to allow users to document their entities and relationships within the Common Data Service producing Microsoft Visio documents.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-38.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="update-9223">Update 9/2/23&lt;/h2>
&lt;p>It seems that it takes me a while to update tools (well, significant change) and I am writing 18 months after the last update to tell you of a new change.&lt;/p>
&lt;p>This one brings 2 new features, brought about by Dani Kahil. He did a great article on how you can make use of my tool to improve the requirements &amp;amp; design process of your app.&lt;/p>
&lt;p>&lt;a class="link" href="https://danikahil.com/2022/07/making-entity-relationship-diagrams-erd-easier-to-understand.html" target="_blank" rel="noopener"
>Making “Entity Relationship Diagrams (ERD)” easier to understand – Mastering requirements, ideation and design for Microsoft Business Applications (danikahil.com)&lt;/a>&lt;/p>
&lt;p>To support some of the change Dani has asked for, it was necessary to update my code to the same way the &lt;a class="link" href="https://linked365.blog/2020/10/14/flow-to-visio-xrmtoolbox-addon/" target="_blank" rel="noopener"
>Flow to Visio – XrmToolBox Addon&lt;/a> works and use the new Visio XML document format. This is now visible as an option under&lt;/p>
&lt;p>In the article, Dani creates areas around his tables to make the ERD clearer to read, I have added that as containers.&lt;/p>
&lt;p>In the top of the app is the Containers tab, where you can establish a name &amp;amp; colour (hex only for now). Once done, the container can be selected in the list of tables you have added.&lt;/p>
&lt;p>When you create the Visio, Containers now appear with the selected tables inside of them.&lt;/p>
&lt;p>Comments &amp;amp; criticism always welcome!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-ERD-Builder-1024x576.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="update-1721">Update 1/7/21&lt;/h2>
&lt;p>Wow, looking at this blog post I realise how long this tool has been around! It was in desperate need of a re-vamp, learning from my experiences over the last year. I was pushed to deliver asks from the community (well, nags from &lt;a class="link" href="https://twitter.com/D365Geek" target="_blank" rel="noopener"
>MCJ&lt;/a>) I have added Columns to the output as well as tidying up the interface to work more like you would expect.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-ERD-Visio-1024x643.gif"
loading="lazy"
>&lt;/p>
&lt;p>I also realise the Save Config / Export and Import are not documented. This was done back in February, so my bad for not documenting it.&lt;/p>
&lt;p>Simply put, Save a configuration (your current selections) with the Save Config button. You can also Export a settting as an XML file, which can then be brought into your tool with the import button.&lt;/p>
&lt;p>I have updated the content of the walkthrough to match the new version.&lt;/p>
&lt;h2 id="update-29720">Update 29/7/20&lt;/h2>
&lt;p>I have added a few things to the application. Firstly, swapped the Entity selection to separate buttons and added some icons. I have also added a search at the top. There is a Select All toggle as well, that was a feature request, can you believe! (just excited people are using it really!)&lt;/p>
&lt;p>Many-To-Many relationships are now available. I have also added Custom Properties to document the relationships. In Visio, under View/Task Panes should be Shape Data. Enable this to display a little panel. In it are details of what is linking up the lines, showing you parent/child/field/relationship date for one-to-many and many-to-one and the entities and the navigation for many-to-many.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-39.png"
loading="lazy"
>&lt;/p>
&lt;p>I have also added App Insights, for my own gratification, which is monitoring the number of Visio diagrams created as well as the number of entities that were documented for my little tool. This can be seen in the &lt;a class="link" href="https://linked365.blog/tools/" target="_blank" rel="noopener"
>Tools - Statistics&lt;/a> page.&lt;/p>
&lt;p>Finally, I have prefixed each of the fields with Primary Key (PK) or Foreign Key (FK) notation.&lt;/p>
&lt;h2 id="walkthrough-of-the-application">Walkthrough of the Application&lt;/h2>
&lt;p>The app is pretty basic looking to start, I wanted to get the core ability out there without bells and whistles, like any good Agile project. To get started, you need to load the entities you are interested in. Choosing From Solution allows you to choose one or more solutions to retrieve Entities from.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image.png"
loading="lazy"
>&lt;/p>
&lt;p>If you choose All Entities, the list is populated with all the entities in your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-1-1024x510.png"
loading="lazy"
>&lt;/p>
&lt;p>In the left Tables grid, you can then choose one or more tables. The ones you choose are highlighted in Selected Tables. As you select a table, the right grid will update to show you the Columns for that table. As you select columns, the Selected Tables grid is updated to indicate which columns will also be added to your ERD.&lt;/p>
&lt;p>Top right of this window is where you decide which relationships to document. Only Between Selected Entities does what it says on the tin, it will only document the relationships between the entities you have selected.&lt;/p>
&lt;p>Above that is a selection on the number of levels you want to go down. Only applies when you select One-To-Many or Many-To-One or Many-To-Many selections. This means, if you select 2 levels, it will document the table selected, any child tables and any child tables of those child tables. Be careful here, as you can get lots of tables and lots of relationships!&lt;/p>
&lt;p>There is also a toggle switch at the top of the toolbar, which will exclude a list of entities that are associated with an entity by default. There are relationships for the created user and modified user for example, which are probably not relevant to your documentation.&lt;/p>
&lt;p>When you select Create Visio, with a file chosen, a VDX file will be created. This is the XML format of the previous version, superseded by VSDX. As VSDX is also XML, there are components available that can create these directly, but the library Saveen created wraps up all the stuff I need in a package I can understand.&lt;/p>
&lt;h2 id="show-and-tell">Show and Tell&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-ERD-Visio-1-1024x643.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="saving-configs">Saving Configs&lt;/h2>
&lt;p>Once you are happy with what you have got, and to save you re-doing all those clicks, you can Save Config. Hit the button to be prompted for a name.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Give it a name to create a new map or update an existing map. This will save the map to your XrmToolBox settings and be there when you re-open the application.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-2021-07-02_10-00-40.jpg"
loading="lazy"
>&lt;/p>
&lt;p>Also, you can select Export. Choose one of your configurations and this will create an XML file in the given place for you to pass to whoever you want!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/07-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Import will prompt for an XML file and add it into your current configs. Simples!&lt;/p>
&lt;h2 id="next-steps">Next steps&lt;/h2>
&lt;p>My immediate priority is to add a better interface, to allow for more detail selection of the properties the code generates,. I also need to display Many-To-Many relationships effectively. Also, allow users to select all the attributes and maybe generate them more like the UML versions Jonas has made. Done!&lt;/p>
&lt;p>Please let me know of your suggestions too, particularly bugs, and I will do my best to correct them. Create an issue on the GitHub page &lt;a class="link" href="https://github.com/LinkeD365/ERDVisioBuilder/issues" target="_blank" rel="noopener"
>here&lt;/a> or pull the code and help me out!&lt;/p></description></item><item><title>Adding to Calendars using Power Automate</title><link>https://linked365.blog/2020/06/24/adding-to-calendars-using-power-automate/</link><pubDate>Wed, 24 Jun 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/06/24/adding-to-calendars-using-power-automate/</guid><description>&lt;img src="https://linked365.blog/images/2020/06-image-81.png" alt="Featured image of post Adding to Calendars using Power Automate" />&lt;p>D365 Customer Service and Field Service both use Calendars associated with resources to schedule working time. This is accessible via the resource calendar and typically relies on the individual working a set time frame each week. Fiona works Monday to Friday, 8-5.&lt;/p>
&lt;p>When you are working with volunteers, this doesn&amp;rsquo;t work. Each volunteer will have an inconsistent schedule, with most of the time not being available. Rita has just volunteered for a couple of hours next Thursday.&lt;/p>
&lt;p>A recent client project to improve their scheduling of resources and was definitely in the second scenario. It wanted volunteers to sign up for times using simple time entry on a portal and transfer these times to the scheduling board.&lt;/p>
&lt;p>As Calendar is available as an entity, my initial thoughts that these would be a simple integration using Flow, unfortunately, not. This post details my findings and how I achieved creating sporadic &amp;ldquo;On Time&amp;rdquo; in Field Service or Customer Service.&lt;/p>
&lt;p>All credit for this discovery goes &lt;a class="link" href="https://www.linkedin.com/in/david-bostock-b097a730/" target="_blank" rel="noopener"
>Dave Bostock&lt;/a>, my colleague at Avanade, but judicious use of F12. Thanks to &lt;a class="link" href="https://twitter.com/JasonAAlmeida" target="_blank" rel="noopener"
>Jason Almeida&lt;/a> and &lt;a class="link" href="https://www.linkedin.com/in/robdawson/" target="_blank" rel="noopener"
>Rob Dawson&lt;/a> for their support and experience to nudge me to the solution.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>How to create calendar entries in D365 for resources using an unbound action in Power Automate.&lt;/p>
&lt;h2 id="manual-configuration-of-calendar-entities">Manual configuration of Calendar Entities&lt;/h2>
&lt;p>Every bookable resource has a calendar associated with them. This Calendar has several rules which establish the working pattern for the resource. A rule, normally, would say &amp;ldquo;This resource works Monday to Friday, 9 to 5&amp;rdquo; or something similar.&lt;/p>
&lt;p>From the Resource, you can get to a calendar view by selecting Show Work Hours, highlighted below. It may also be available as a tab on the main form, depending on whether you are using Field Service or not. For me, I am still using the Customer Service version.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-74.png?fit=1024%2C602&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Top left, you can alter the default rule for the user by adding a new weekly schedule, add an update to a single day or add time off for the resource.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-75.png"
loading="lazy"
>&lt;/p>
&lt;p>Selecting New Weekly Schedule and populating the next screen is the standard way resource get a weekly schedule.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-76.png"
loading="lazy"
>&lt;/p>
&lt;p>For volunteer management, resource tends to have a blank calendar. This is done by deleting all the calendars associated with the resource. From there, a volunteer would sign up for periods or shifts. This, on the face of it, just sounds like data entry, easily achieved via Powe Automate.&lt;/p>
&lt;h2 id="creating-rules-via-power-automate">Creating Rules via Power Automate&lt;/h2>
&lt;p>If you use either of the Common Data Service connectors to create a calendar rule, you will be presented with this error.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-77.png"
loading="lazy"
>&lt;/p>
&lt;p>This is because calendarrule is not a real entity, rather it is an aggregate entity. You can not create or update them directly. The only way you will get around this is to use the unbound action, msdyn_SaveCalendar.&lt;/p>
&lt;p>To demonstrate this, I have created a simple Schedule entity. This is a child of Contact, with 2 datetime fields, start and end. The premise is the Resource, via a portal, will be allowed to add to their schedule by signing up for predefined slots, but this will mean that there is a schedule for each contact.&lt;/p>
&lt;p>When a schedule record is created, we need to create the corresponding CalendarRule to show that this resource is available in the calendars used for planning.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-79.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, retrieve the calendar for this resource. The schedule is linked to a Contact, so use the Id to find the Bookable Resource.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-80.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, call the action. It is in a loop as the List records always returns 1 or more records.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-81.png"
loading="lazy"
>&lt;/p>
&lt;p>This is a JSON snippet, creating an object to add to the calendar.&lt;/p>
&lt;p>CalendarId is the Resources calendar, ObjectTypeCode defines this as a Bookable resource, displayed &lt;a class="link" href="http://www.dynamicscrm.blog/object-type-codes-cheat-sheet-for-dynamics-365/" target="_blank" rel="noopener"
>here&lt;/a>. TimeZoneCode is obvious, this points us to UTC. StartDate I have populated with the start of the schedule.&lt;/p>
&lt;p>The next is a list of rules to add to this Calendar, you could create more than one here, but we don&amp;rsquo;t have to. Start and End time are taken directly from the Schedule record. Duration is the time in minutes for the scheduled appointment. This can be calculated by firstly converting both to ticks (seconds) and reconverting to minutes. I got this from an excellent response to a forum question &lt;a class="link" href="https://powerusers.microsoft.com/t5/Building-Power-Apps/how-to-get-difference-between-two-dates-in-flow/td-p/283186" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">div&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">div&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">mul&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">sub&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ticks&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">triggerOutputs&lt;/span>&lt;span class="p">()?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">cc_end&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">]),&lt;/span>&lt;span class="n">ticks&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">triggerOutputs&lt;/span>&lt;span class="p">()?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">cc_start&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">])),&lt;/span>&lt;span class="m">100&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="m">1000000000&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="m">60&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Effort, timecode and subcode are required, defaulted to indicate a working period (timecode 0) and 100% effort (Effort 1).&lt;/p></description></item><item><title>D365 Org DB Settings - XrmToolBox addon</title><link>https://linked365.blog/2020/06/18/d365-org-db-settings-xrmtoolbox-addon/</link><pubDate>Thu, 18 Jun 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/06/18/d365-org-db-settings-xrmtoolbox-addon/</guid><description>&lt;img src="https://linked365.blog/images/2020/06-OrgSettings.gif" alt="Featured image of post D365 Org DB Settings - XrmToolBox addon" />&lt;p>Regular readers (Hi Mum) will remember I have done several articles on Org DB Settings. I have got 2 pages in the top bar dedicated to a description of each setting, the &lt;a class="link" href="https://linked365.blog/2019/10/01/d365-org-db-settings-email/" target="_blank" rel="noopener"
>first&lt;/a> all about the various Email Settings you can tweak, the &lt;a class="link" href="https://linked365.blog/2019/11/03/d365-org-db-settings-other/" target="_blank" rel="noopener"
>second&lt;/a> covering the rest of them. Both articles continue to be readily used by people, assume looking for a better understanding, as the Microsoft documentation is a little slim.&lt;/p>
&lt;p>I also did a project to bring the setting of the options to a &lt;a class="link" href="https://linked365.blog/2019/10/16/d365-org-db-settings-canvas-app/" target="_blank" rel="noopener"
>Canvas app&lt;/a>. This is also one of the most visited posts. The only issue is that you need a custom connector, and this needs installing separately and then configuring. It isn&amp;rsquo;t a simple install process.&lt;/p>
&lt;p>Since that second project, I have meaning to create a new version of the application but use the &lt;a class="link" href="https://www.xrmtoolbox.com/" target="_blank" rel="noopener"
>XrmToolBox&lt;/a> framework. It has taken a while, as unlike Power Apps &amp;amp; Power Automate, I can not turn development on and off, I need to sit and focus, so finding a dedicated couple of hours to work on it has been a struggle. Thanks to COVID-19, my commute has disappeared and I purposefully dedicated this time to sitting down and working through my project.&lt;/p>
&lt;p>The project is now available in XrmToolBox, source &lt;a class="link" href="https://github.com/CooksterC/OrgSettings" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>I created a tool for updating Org Setting available on &lt;a class="link" href="https://www.xrmtoolbox.com/" target="_blank" rel="noopener"
>XrmToolBox&lt;/a>. It allows updating of Org Settings on any D365 instance and includes the ability to back up current options and copy from other systems.&lt;/p>
&lt;h2 id="update-031020">Update 03/10/20&lt;/h2>
&lt;p>I have added the ability to compare your settings with another environment. This also allows copying between the primary and the secondary environment.&lt;/p>
&lt;h2 id="update-290920">Update 29/09/20&lt;/h2>
&lt;p>I have been working on this a little bit. First of all, I added a search just above the grid of settings. I have also added App Insights, which is just for my satisfaction really to see who is using the tool and where. The &lt;a class="link" href="https://linked365.blog/tools/" target="_blank" rel="noopener"
>Tools - Statistics&lt;/a> page shows this.&lt;/p>
&lt;p>Finally, I have added a second description tab. My documentation on Org settings for &lt;a class="link" href="https://linked365.blog/2019/10/01/d365-org-db-settings-email/" target="_blank" rel="noopener"
>Email&lt;/a> and &lt;a class="link" href="https://linked365.blog/2019/11/03/d365-org-db-settings-other/" target="_blank" rel="noopener"
>Other&lt;/a> is available on the blog, but I thought it would be an idea to get this information into the app to support the official description from Sean. My description includes images as well as an alternative explanation of what the setting does. As there is a lot of settings, I am using App Insights to work out which settings people are editing to highlight which settings I should ensure I put a description in first.&lt;/p>
&lt;h2 id="walkthrough-of-the-application">Walkthrough of the Application&lt;/h2>
&lt;p>The use of my tool comes without any warranty or support. Please ensure you have a copy of your current configuration before altering any settings. Also, only change a setting that you have a specific reason for, as altering a setting may have a detrimental outcome on your environment.&lt;/p>
&lt;p>The app is split into two main panes. On the left is a grid showing all the available settings for you to tweak. This is taken directly from Sean McNellis&amp;rsquo;s &lt;a class="link" href="https://github.com/seanmcne/OrgDbOrgSettings" target="_blank" rel="noopener"
>GitHub&lt;/a> repository for his tool, the original OrgDbOrgSettings. By re-using Sean&amp;rsquo;s file, I can ensure when an update to the settings is made or added, my app will reflect it as well. A big thank you to Sean for providing this resource openly.&lt;/p>
&lt;p>It is also filtered by the min and max version of the setting as defined by Sean. I have not got an on-premise version to connect to test but would look forward to work with anyone who wants to be a guinea pig.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-OrgSettings.gif?fit=1024%2C720&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This grid is sortable, useful to quickly see the current changes or those that you have made or those that you are making. Current values are highlighted in green, uncommitted changes are red.&lt;/p>
&lt;p>On the right is where you can set the value. The control available changes depending on what the type of change is. You can also remove the value, clearing out the configuration for an individual setting.&lt;/p>
&lt;p>Down the bottom is also a documentation section, taken from Sean&amp;rsquo;s file, linking back to a Microsoft KB article or another page if available. It also shows the default, type of field, min &amp;amp; max versions. The big area is the description taken from file to give the Microsoft version of the setting.&lt;/p>
&lt;p>At the top, are simple Refresh and Commit buttons. If you have a change, hit the Commit to update your configuration.&lt;/p>
&lt;p>There is also a Add Connection button which establishes a second connection and displays the settings for the second environment. Commit buttons are now labelled to highlight which environment you are adding to.&lt;/p>
&lt;p>Once connected to a second environment, you can clone the settings of the primary to the secondary.&lt;/p>
&lt;h3 id="manual-update">Manual Update&lt;/h3>
&lt;p>On numerous occasions, when you have multiple systems, you want to copy org settings between environments. Using Sean&amp;rsquo;s tool, that would mean installing the application in multiple environments. In my tool, you can copy settings between environments.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-67.png"
loading="lazy"
>&lt;/p>
&lt;p>You can also manually create your own xml configuration, but please use the tool. I don&amp;rsquo;t want to be blamed for corrupt systems!&lt;/p>
&lt;h2 id="next-steps">Next Steps&lt;/h2>
&lt;p>I have started this project to learn XrmToolBox and get back to my roots for Windows App development. I plan to elaborate this with the ability to compare two systems and copy configuration between environments.&lt;/p>
&lt;p>I would also like to incorporate my explanations for each setting to elaborate the impact of each change.&lt;/p>
&lt;p>Please let me know via &lt;a class="link" href="https://twitter.com/LinkeD365" target="_blank" rel="noopener"
>Twitter&lt;/a> if this tool is useful and raise bugs or enhancements in &lt;a class="link" href="https://github.com/CooksterC/OrgSettings" target="_blank" rel="noopener"
>GitHub&lt;/a>.&lt;/p>
&lt;p>A final thought, I have checked, double and triple-checked my spelling and capitalisation of XrmToolBox throughout this article. Please report to &lt;a class="link" href="https://twitter.com/rappen" target="_blank" rel="noopener"
>Jonas Rapp&lt;/a> if you find any incorrect ones.&lt;/p></description></item><item><title>Approvals - Showing History in SharePoint</title><link>https://linked365.blog/2020/06/07/approvals-showing-history-in-sharepoint/</link><pubDate>Sun, 07 Jun 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/06/07/approvals-showing-history-in-sharepoint/</guid><description>&lt;img src="https://linked365.blog/images/2020/06-Annotation-2020-06-04-091056.png" alt="Featured image of post Approvals - Showing History in SharePoint" />&lt;p>Last week, I took part in the Microsoft 365 Virtual Marathon. This was a branch out for me, as it wasn&amp;rsquo;t specifically Dynamics 365 or Power Platform related, though everything is one now right?&lt;/p>
&lt;p>My talk was around Approvals, displaying 3 types of approvals, from a Send with Options to Adaptive cards, topics I have covered in my &lt;a class="link" href="https://linked365.blog/2020/04/02/quick-approvals-send-with-options/" target="_blank" rel="noopener"
>blog&lt;/a> &lt;a class="link" href="https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/" target="_blank" rel="noopener"
>before&lt;/a>.&lt;/p>
&lt;p>During the sessions, one of the questions was around tracking approvals. Even in the Approvals app, it is very difficult to track who has approved and when including the comments. If you want to see this in combination to the thing you were approving, it means swapping between apps and ensuring you know what record you are looking at.&lt;/p>
&lt;p>I took this as a challenge, and decided to use the Power Apps in SharePoint form to display Approvals.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Display of Approvals in SharePoint or and Power Platform application is not intuitive. I use a Power App to display approvals against items on a SharePoint document library.&lt;/p>
&lt;h2 id="form-in-action">Form in Action&lt;/h2>
&lt;p>Before I run through the detail, check out the form in action below. As you show more details and display the associated Power Apps form, a list of the approvals is shown. If you drill into the approvals, more details about who it was sent to and how they responded are available.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-approvals1.gif"
loading="lazy"
alt="GIF showing Approvals in SharePoint"
>&lt;/p>
&lt;h2 id="simple-approval">Simple Approval&lt;/h2>
&lt;p>To get some approvals, I created a flow which is triggered when a file is added to the SharePoint folder. Obviously, this could be a lot more complex than this, but this simple one is to get some data in my approvals to show in SharePoint.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-50.png"
loading="lazy"
>&lt;/p>
&lt;p>The critical part of this is the item link. You need a method of linking your approvals with the item it corresponds to, and MS does not provide you with a key field. You could create an approval, update a bespoke field on the document meta with the approval id, but I did not want to create unnecessary fields. I ensure that the item link will take me to the document in SharePoint.&lt;/p>
&lt;h2 id="sharepoint-form">SharePoint form&lt;/h2>
&lt;p>First of all, using Power Apps in SharePoint is not the same as a standard Power App. It frightened me when you start the Power App that it dumps you into the Default Instance. Also, these applications are not solution aware. I don&amp;rsquo;t think you can share the forms either. It is certainly not what I am used to. Not sure why this is the case. Let me know if you know any different.&lt;/p>
&lt;p>In the document library, select Power Apps, customise forms.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-48.png"
loading="lazy"
>&lt;/p>
&lt;p>The form I created has a SharePointIntegration property in it, which is the context that is passed in. The form is linked to that record, in my case a document.&lt;/p>
&lt;p>There are a couple of triggers on the integration which are used to force the display of the first screen when this is triggered. If you don&amp;rsquo;t apply this logic, the screen that was displayed last will return to the user, meaning the user tends to be left in the second, approval details screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-63.png"
loading="lazy"
>&lt;/p>
&lt;p>I have added a couple of fields to the top half of the form, which represents some of the core fields you need. Below that, I have added a gallery.&lt;/p>
&lt;p>Also, to use later, onvisible takes the document that is passed in or the first in the list and sticks it in a local variable&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/06/image-51.png?fit=1024%2C174&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The Gallery Items is a filtered list of the Approvals entity within your CDS environment.&lt;/p>
&lt;p>Here, you can see that I am filtering the Approvals entity by the item link, using the base SharePoint URL and the full path to the file. This isn&amp;rsquo;t the full path, just the bit after your site collection.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/06/image-52.png?fit=1024%2C575&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>In the gallery Item are 3 fields. The first field is a visual indicator of the current status of approval. It is a combination of the Status reason as well as the result.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/06/image-53.png?fit=1024%2C425&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This label is also coloured to show Approved as green, Pending as black &amp;amp; Rejected as Red.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/06/image-54.png?fit=1024%2C90&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The next fields is just a display of who created the approval and when.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-55.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-56.png"
loading="lazy"
>&lt;/p>
&lt;p>I added a second screen to my app, so you can see the detail of the approval, navigated to by selection of the approval.&lt;/p>
&lt;h3 id="approval-detail">Approval Detail&lt;/h3>
&lt;p>This form is pretty simple looking, with just a gallery. On visible of the form, two collections are populated, which are filtered lists of Approval Requests and Approval Responses. Working with local collections is a lot easier, particularly if you need to reference them multiple times.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/06/image-59.png?fit=1024%2C84&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The gallery is connected to the requestList, filtered by the previous step.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-60.png"
loading="lazy"
>&lt;/p>
&lt;p>The name of the approver is taken from the owner of the request. I added a timestamp as well.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/06/image-58.png?fit=1024%2C188&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The third field combines several, depending on whether there are any responses to the particular request by the user. Also, the status, even for those that have been classified as rejected, is Active. There does not seem to be any direct link between the request and its response. I am assuming that each request can only have 1 response by 1 person, so filter the already filtered responses by the user who is the approver. Colour coding on the value again gives a more visual representation.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">If&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">IsEmpty&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Filter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">responsesList&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Owning&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="n">Full&lt;/span> &lt;span class="n">Name&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">ThisItem&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Owning&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="n">Full&lt;/span> &lt;span class="n">Name&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">If&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Status&lt;/span> &lt;span class="n">Reason&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="s">&amp;#34;Active&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;Pending&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Status&lt;/span> &lt;span class="n">Reason&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Text&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">First&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Filter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">responsesList&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Owning&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="n">Full&lt;/span> &lt;span class="n">Name&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="p">=&lt;/span> &lt;span class="n">ThisItem&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Owning&lt;/span> &lt;span class="n">User&lt;/span>&lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="n">Full&lt;/span> &lt;span class="n">Name&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">).&lt;/span>&lt;span class="n">Response&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>There are a couple of other fields on the grid, firstly the Comments entered if there are any. This comes from the response. I trigger the visibility of this field depending on whether it has a value.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-61.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, who re-assigned the request. Here I use a lookup, which allows a traversal to the the users name.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-62.png"
loading="lazy"
>&lt;/p></description></item><item><title>Customer Service Insights</title><link>https://linked365.blog/2020/06/04/customer-service-insights/</link><pubDate>Thu, 04 Jun 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/06/04/customer-service-insights/</guid><description>&lt;img src="https://linked365.blog/images/2020/06-icons8-team-r-enAOPw8Rs-unsplash-1.jpg" alt="Featured image of post Customer Service Insights" />&lt;p>Following on my series of posts about &lt;a class="link" href="https://linked365.blog/tags/Insights/" >Sales Insights&lt;/a>, I thought I would learn more about Customer Service Insights.&lt;/p>
&lt;p>Sales Insights, in my view, is all around making the sales process more effective reducing the time spent editing data, highlighting activities that a sales user should be doing and tracking activity with your customer. Sales Insights includes forecasting and predictions as well to allow a better understanding of what makes a sale and what is preventing closing deals.&lt;/p>
&lt;p>Customer Service Insights seems to be a more typical &amp;ldquo;Insights&amp;rdquo; application where a service manager can get an overview of the current state of the Service team, measure the level of KPIs and drive understanding of the bottlenecks.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Customer Service Insights provides a great suite of reports to visualise a servicing centre. It allows AI categorisation and grouping of cases to highlight patterns in your case resolution, ensuring you can quickly reduce bottlenecks. It also highlights areas where you should create FAQs or Virtual agents for your more frequent case categories.&lt;/p>
&lt;p>At £56.60 per user per month, it is not an application you would give to all your support users, but service managers would definitely benefit from the insight into their organisation it brings. With the ability to generate your own reports via Power BI, one license could open up possibilities for combining this data with other sources in your board packs or daily reporting scenarios.&lt;/p>
&lt;h2 id="setup">Setup&lt;/h2>
&lt;p>Start with a trial. It is free to sign up. Head over to the Microsoft site &lt;a class="link" href="https://dynamics.microsoft.com/en-gb/ai/customer-service-insights/" target="_blank" rel="noopener"
>here&lt;/a> and select Get started.&lt;/p>
&lt;p>Choose the region and select Get started.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-232.png"
loading="lazy"
>&lt;/p>
&lt;p>Now you need to connect your data. Good to see Salesforce and other data sources are coming soon. I selected the only choice, Dynamics 365. This then prompts you for an instance to use, select the most appropriate.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-234.png"
loading="lazy"
>&lt;/p>
&lt;p>It then goes and looks at your data. Nice animation!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-235.png"
loading="lazy"
>&lt;/p>
&lt;p>Once done, you are presented with the base screen for Customer Services Insights, with a banner warning you that it is not quite ready yet.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-236.png?fit=1024%2C896&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>It is that simple! Unfortunately for me, I am working with OOTB demo data. My data range is very limited. This is where I rely on Power Automate to generate some case data. I documented this in my previous post &lt;a class="link" href="https://linked365.blog/?p=1517" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>Now that the data is available, time to walkthrough the application and it&amp;rsquo;s features and benefits.&lt;/p>
&lt;p>The information is refreshed daily. Be patient, particularly if you are changing things. The date of the last refresh is visible in all the screens, top left.&lt;/p>
&lt;h2 id="home">Home&lt;/h2>
&lt;p>The home page has lots of useful stats on your topics and tools to help you. Top right, you can define the timeline between 3 options.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/06/image-30.png?fit=1024%2C690&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The first section is Topics to Watch. This gives you 3 topics that are high in a combination of the number of cases, negative CSAT score and an increasing volume of the number of cases over the time period you select. So, over the last 30 days, App sulfamethoxazole/trimethoprim damaged was highest overall. You can also see the 3 ratings below.&lt;/p>
&lt;p>Next comes Topics Impacting resolution time. This shows the highest time to resolution for these topics, with shortest, average and longest time period show. Drill down to the topic to see who is performing well in this topic and do a bit of cross-learning for those that aren&amp;rsquo;t.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>The next section highlights topics that could be automated. This means that the resolution time is quick (or simple) and the number of cases is high. Automating these cases could drastically reduce the impact on your support desk.&lt;/p>
&lt;p>Next shows the impact of channels on the CSAT score. Ensure your users are trained and skilled in responding effectively in each medium. It also shows the channels that problems are surfacing on. Be careful to ensure the channel has the appropriate time to react.&lt;/p>
&lt;p>Finally, the time at which cases are raised over the last month is shown. In my data, as I mentioned, the create time was not used, so shows as blank. This little graph shows you the peaks and troughs in case creation which allows you to alter shift patterns to increase the helpdesk users at those times.&lt;/p>
&lt;p>Drilling into the topic presents you with Topic analytics page.&lt;/p>
&lt;h3 id="topic-analytics">Topic Analytics&lt;/h3>
&lt;p>This gives you a snapshot of all scores gained from analysis of the cases and insights into how this type of case is fairing in your business. In the top right, you have the option to Automate this topic (only sends you to the website, does not bring anything through from the topic) and to rename the topic. Here you can re-label the generated topics, to ease the tracking etc. This applies throughout the application once done.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/06/image-33.png?fit=1024%2C734&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;ol>
&lt;li>In the top zone, you can filter the results to a given time frame, product, channel, BU, and owner of the case. These lists filter by those that apply rather than all the available channels.&lt;/li>
&lt;li>The second zone shows some simple stats from the case topic. It also has how this category affects the overall figures.&lt;/li>
&lt;li>Essential to any service desk is the satisfaction rating an end user gives the company on the back of this case. This can come from various sources but is an immediate rating of your customer support desk and broader, to your organisation. This, broken down by product and channel and includes statistics on the resolution time and the average CSAT score for each. Also, it shows how this case has impacted the average CSAT score for all the cases.&lt;/li>
&lt;li>The next section shows these cases by agent, highlighting those with the highest number of open cases, longest resolution time and lowest CSAT score. This data shows little in my created data as my user account owns everything, but you can quickly see those underperforming support users, or who needs a little training.&lt;/li>
&lt;li>The final area shows the impact of cases by product and channel on the resolution time. Here you can see that some cases take a lot longer than others, which is something you may need to provide training on.&lt;/li>
&lt;/ol>
&lt;p>Below the final area is a graphical representation of the makeup of the cases that are in the timeframe that selected. This shows how each channel flows through to its current state.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/06/image-34.png?fit=1024%2C361&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Remember, this is Power BI so the usual tools to export the data and show the table of records is all there.&lt;/p>
&lt;h2 id="kpi-summary">KPI Summary&lt;/h2>
&lt;p>The KPI summary view shows your progress against resolution and escalation SLAs and how topics, priority, channels etc affect this.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/06/image-36.png?fit=1024%2C559&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;ol>
&lt;li>Again, the top area is to allow you to filter the data, with timeframe, channel, product, BU and team.&lt;/li>
&lt;li>This area shows core stats on the cases. This includes the number of cases, number of resolved cases, number of escalations, the number of cases that are compliant in the SLAs that are associated with the case, the average time to solve a case and the average CSAT score.&lt;/li>
&lt;li>This lists the case topics with a volume for each. The link takes you to the Topic analysis screen.&lt;/li>
&lt;li>This set of graphs shows you some insights in cases.
&lt;ol>
&lt;li>The first graph shows you the new cases in the period and the cases that were still open when the period started.&lt;/li>
&lt;li>This show the breakdown of the priority of your cases.&lt;/li>
&lt;li>Finally, the case channel with a breakdown with the status.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>Emerging topics shows a change in the cases data for each topic over the current period and the previous ones. Here you can see the case topics that are increasing, maybe a product role out or a new software patch will drive more calls to your contact centre.&lt;/li>
&lt;li>The final area is two graphs, the first showing you the number of cases per day raised in the period as well as those that are resolved. The last chart shows the time to resolve cases and the count for each period.&lt;/li>
&lt;/ol>
&lt;p>These graphs can be selected, filtering the other graphs as you go around.&lt;/p>
&lt;h2 id="new-cases">New Cases&lt;/h2>
&lt;p>The next tab focus on cases created over the period.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/06/image-37.png?fit=1024%2C564&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;ol>
&lt;li>Again, this is a set of filters available for you to interrogate the data further.&lt;/li>
&lt;li>This section groups the cases created in the timeframe into topics and shows the percentage of each, the number of each, the increase in volume since the last period, the average resolution time, percentage of cases closed and the average satisfaction rating. The link takes you to the Topic analysis page for each.&lt;/li>
&lt;li>These graphs show
&lt;ol>
&lt;li>Cases by day by priority&lt;/li>
&lt;li>Cases by day by channel&lt;/li>
&lt;li>Case creation time over the period by channel (again my data is all created at midnight)&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>The final area shows cases that have an increased number over the period. This shows the volume of cases per topic, the number of new cases, the volume change, the average time to resolution, how many are closed and the average customer satisfaction&lt;/li>
&lt;/ol>
&lt;h2 id="customer-satisfaction">Customer Satisfaction&lt;/h2>
&lt;p>The next panel is a selection of statistics related to customer satisfaction and topic affect on overall CSAT score.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/06/image-38.png?fit=1024%2C561&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;ol>
&lt;li>Again, this is a set of filters available for you to interrogate the data further.&lt;/li>
&lt;li>This list shows topics with their average CSAT score, worst at the top. It shows the percentage volume of cases, number of closed cases, number of CSAT scores recorded, the Average CSAT score, and the impact those results have on the overall average.&lt;/li>
&lt;li>These two simple numbers show the number of surveys completed (cases with a CSAT score) and the percentage collection rate.&lt;/li>
&lt;li>These graphs show
&lt;ol>
&lt;li>Average CSAT score across the period&lt;/li>
&lt;li>Breakdown of score per channel&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;h2 id="resolutions">Resolutions&lt;/h2>
&lt;p>The final report section of the application is Resolutions. This details insights across resolved cases and the length of resolution cases.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/06/image-39.png?fit=1024%2C576&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;ol>
&lt;li>Again, this is a set of filters available for you to interrogate the data further.&lt;/li>
&lt;li>This is a list of topics with the volume of case topics, the average resolution time per topic and the impact on the average resolution time for that topic. The detail link takes you to the Topic Analytics page.&lt;/li>
&lt;li>These two graphs show
&lt;ol>
&lt;li>the agents with the longest resolution time in the period&lt;/li>
&lt;li>the new cases logged in the period vs the resolution time&lt;/li>
&lt;/ol>
&lt;/li>
&lt;li>These graphs show
&lt;ol>
&lt;li>Number of open/closed cases per agent (my data is all owned by me&lt;/li>
&lt;li>New vs resolved escalations over the time period.&lt;/li>
&lt;/ol>
&lt;/li>
&lt;/ol>
&lt;h2 id="configuring-your-data">Configuring your data&lt;/h2>
&lt;p>There are several options to configure your data, available in the customer service insights settings, top right.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-40.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="data-mapping">Data Mapping&lt;/h3>
&lt;p>Data mapping allows customisation of the mapping of the fields required by CSI to your data. By default, this maps the OOTB fields on the Case entity to those expected. You could use a different entity to case in your organisation or map topic to a separate field, for instance.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-41.png"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on the pencil to edit the configuration firstly allows selection of an entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-42.png"
loading="lazy"
>&lt;/p>
&lt;p>Once this is done, hit Next to map the fields that are required, on the left, to those in the entity selected.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-43.png"
loading="lazy"
>&lt;/p>
&lt;p>To ensure effective use of the tool, make sure all 15 fields are mapped correctly. This is pretty straight forward if you use the OOTB Case (Incident) entity and fields.&lt;/p>
&lt;h3 id="case-title-cleaning">Case Title cleaning&lt;/h3>
&lt;p>A lot of organisations have a set configuration for their case titles. This is typical when the title is populated with parts of the case such as subject or category selection. CSI allows you to denote these parts so that they are ignored when it builds up the topic categorisation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-44.png"
loading="lazy"
>&lt;/p>
&lt;p>By default the whole of the title is used, but you can state that you use tags before, after or both the main part.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-45.png"
loading="lazy"
>&lt;/p>
&lt;p>This then allows you to highlight what tags you use to separate the topic from the tags. CSI will then ignore suffixes and prefixes to your title, anything after or before one of the tags.&lt;/p>
&lt;h3 id="topic-granularity">Topic Granularity&lt;/h3>
&lt;p>CSI uses the title to group topics. It could use all the words as a unique sentence, but filler words would also be used, which would not group them correctly.&lt;/p>
&lt;p>Consider this sample topic that was created using my random data. It is effectively creating a topic from the drug name I used in the centre, rather than taking the whole sentence as the topic. Filler words and their uniqueness is defined by the topic granularity. If you used the highest level of granularity, very high, each unique case title would be used as a topic, reducing the effectiveness of the insights you want to achieve.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-46.png"
loading="lazy"
>&lt;/p>
&lt;p>It will be down to your data and the fields you are using to decide on the best setting for your granularity. As you change the slide value to high, the groupings become smaller and more unique, using more of the title to drive that uniqueness.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-csi1.gif"
loading="lazy"
>&lt;/p>
&lt;h3 id="export-data">Export Data&lt;/h3>
&lt;p>This feature is still in preview. This feature allows an external connector to use the data, to go above and beyond the reports given in the OOTB CSI configuration.&lt;/p>
&lt;p>A unique URL is generated if you select Generate URL. This is available for anyone to use if they have this URL. The data is refreshed daily. There are also limitations on the number of calls per day that can be made to this API, documented &lt;a class="link" href="https://docs.microsoft.com/en-gb/dynamics365/ai/customer-service-insights/exportdata" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-47.png"
loading="lazy"
>&lt;/p>
&lt;p>It would be easy to generate your own reports using Power BI or similar tool or have a daily poll to trigger notifications of high case levels etc to supervisors with this endpoint.&lt;/p>
&lt;p>To add to Power BI, select Get Data, Web, paste in the generated URL and you have access, nice and simple!&lt;/p>
&lt;p>This export of data is the first step, the screen shows that there will be a Power Automate\Power Apps\Logic apps connector, though you could probably use the existing one if you can limit the interaction.&lt;/p>
&lt;p>Featured Image by &lt;a class="link" href="https://unsplash.com/@icons8?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Icons8 Team&lt;/a> on &lt;a class="link" href="https://unsplash.com/s/photos/customer-service?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Unsplash&lt;/a>&lt;/p></description></item><item><title>Using Power Automate to generate Data</title><link>https://linked365.blog/2020/06/02/using-power-automate-to-generate-data/</link><pubDate>Tue, 02 Jun 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/06/02/using-power-automate-to-generate-data/</guid><description>&lt;img src="https://linked365.blog/images/2020/06-alexander-sinn-KgLtFCgfC28-unsplash.jpg" alt="Featured image of post Using Power Automate to generate Data" />&lt;p>Previously, I have used &lt;a class="link" href="https://linked365.blog/2020/05/21/mockaroo-and-flow-perfect-demo-data/" target="_blank" rel="noopener"
>Mockaroo and Flow&lt;/a> to generate data, but the data I required for demoing the Customer Services Insights functionality has to be linked from existing data to be valid.&lt;/p>
&lt;p>In this post, I will guide you through the methods I have used to randomise and create demonstration data that fits the requirements for Customer Service Insights, just using Power Automate and an Excel file.&lt;/p>
&lt;h2 id="tldr">TL;DR&lt;/h2>
&lt;p>Customer Service Insights only really works with data. This is great if you have some, but most demonstrations or trials have 10s of cases rather than 1000s. Here I walk through generating data using Flow, Rand() and Excel, mainly. Also, how to correct data if you didn&amp;rsquo;t quite get it the right first time 😊.&lt;/p>
&lt;h2 id="creating-cases">Creating Cases&lt;/h2>
&lt;p>Cases in D365 are linked to Contacts and Accounts and they need a title. As a bare minimum, this will create a case. But, for Customer Service Insights to work effectively, you need a few more parts.&lt;/p>
&lt;p>Origin is where the case came from, typically Twitter, Facebook, Phone, Email, Web etc. This allows for the segmentation of your customer base by source. Products link the case back to the faulty product or service that the case was about. A Priority is also needed to define the workload case for your staff or denote a superior service. Also, we need to know the satisfaction or the originator of the case with the resolution. This can be taken from a Forms Pro survey, for example.&lt;/p>
&lt;p>All these fields I have taken from the various parts of the Customer Service Insights reports and wanted to generate data with this populated to allow for an impressive and realistic visualisation in CSI.&lt;/p>
&lt;p>But I wanted to randomise the data, it is quite easy in Flow to create records, but to randomise them you need to choose from a selection, you could query the data in your system for each of these, but I found it easier to use a central store of the lookup data.&lt;/p>
&lt;h2 id="excel-for-random-data">Excel for Random Data&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-237.png"
loading="lazy"
>&lt;/p>
&lt;p>In Excel, I created an OneDrive file and added a table. In this table, I added several columns with information to build up a case.&lt;/p>
&lt;p>&lt;strong>Topic Start&lt;/strong> - Combine 3 fields to make the title of the case, which allows for randomising the title but keeping some keywords to allow for Topic categorisation by CSI.&lt;/p>
&lt;p>&lt;strong>IdCol&lt;/strong> - this is the key for the table. Each valid row has a unique number so I can retrieve the row in Flow later.&lt;/p>
&lt;p>&lt;strong>Topic Main&lt;/strong> - This is the middle part of the Title field. I am actually using a list of drug names I found on generatedata.com. By using a list, I hope to be able to drive the Topic categorisation.&lt;/p>
&lt;p>&lt;strong>Topic End&lt;/strong> - The final part of the topic, just some random words I thought sounded like ends of case titles.&lt;/p>
&lt;p>&lt;strong>Contact&lt;/strong> - This is the GUID for all the active contacts in the system. I exported the list to excel, unhide the columns on the left and grabbed that list.&lt;/p>
&lt;p>&lt;strong>Channel&lt;/strong> - These are the numeric values for the optionset used for Channel. I drilled into the options set from the field on the case.&lt;/p>
&lt;p>&lt;strong>Priority&lt;/strong> - Again a numeric values for the Priority optionset.&lt;/p>
&lt;p>&lt;strong>Product&lt;/strong> - This is a list of the active Product Ids in the environment.&lt;/p>
&lt;h2 id="create-cases-flow">Create Cases Flow&lt;/h2>
&lt;p>The overall flow is quite lengthy and has several conditions. Let&amp;rsquo;s step through it from the top. The flow is available in my CustServInsights solution &lt;a class="link" href="https://github.com/CooksterC/Community/tree/master/CustServInsights" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>First of all, trigger the flow from a button. The input parameter denotes how many cases you would like to make. Ensure you keep this as 1 for testing. Also, initialise the case counter for use in the next loop.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, create a Do Until loop. This will keep looping until our case counter matches or exceeds the required number of cases.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-1.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="retrieve-the-random-data">Retrieve the random data&lt;/h3>
&lt;p>Next, get the relevant lines from that Excel file. For each of the fields, choose a random number from 1 and the maximum number for each data set and get the corresponding row in the Excel file. This is for Priority where I have 5 rows in the Excel sheet (I duplicate Normal which has a value 2 to weight the priorities in favour of Normal), hence the Rand function is&lt;/p>
&lt;p>Rand(1_&lt;the minimum it can be>&lt;em>, 6&lt;/em>&lt;the next integer after the maximum it can be>_)&lt;/p>
&lt;p>Rand (1,6) for Priority.&lt;/p>
&lt;p>The Key Column is the IdCol of the file, populated with integers&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>This action is repeated for each of the random columns in the Excel file.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-3.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="create-a-case">Create a case&lt;/h3>
&lt;p>Next, use these values to create a Case. Use the Create a new record action and populate with the appropriate values. Title uses a combination of each of the topic parts. Customer (Contacts) uses the confusing for citizen developers syntax to populate the contact on the case. This only applies if you are using the Current Environment version of the custom connector. There is an idea to revert this back to the previous syntax &lt;a class="link" href="https://powerusers.microsoft.com/t5/Power-Automate-Ideas/Allow-Setting-null-value-to-the-lookup-field-in-Common-Data/idi-p/427649" target="_blank" rel="noopener"
>here&lt;/a>. Please vote! I also added a description, just so I can retrieve these new cases later if I need to.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>Origin uses the number for the optionset returned by the Excel and converts to an integer. The product field uses the same syntax as Contact.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>Priority is converted to an integer as well. Record created on is used to alter the created date of the record. It is a pseudo change, as the record keeps both what you want to show and the actual date as separate fields in the CDS. Unfortunately, there is a bug in both CDS connectors and the D365 connector that strips out the time part of the field. I raised the bug &lt;a class="link" href="https://powerusers.microsoft.com/t5/I-Found-A-Bug/CDS-connectors-can-not-update-overriddencreatedon-field/m-p/578164" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>The compose used as a parameter is below. Use the rand function again to subtract up to 45 days from the current date and subtract up to 6 hours from the result. Finally, format the result to a date-time acceptable by the connector&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-8.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="complete-the-slas">Complete the SLAs&lt;/h3>
&lt;p>Once the record is created, randomise the closure as well as whether it met any SLAs in place for first-contact and closure. Firstly, generate another random number which will be used to define which path our case will take. Next, choose if this case is still open. Any value greater or equal to 8, so 8, 9 and 10 or 30% of the cases, should be still open.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>On the positive side, the case is still open, another condition to decide if the case was responded to in time. This effectively means 10% of the cases will have failed their First response SLA and are still open. 20% will be still open but the first response was passed. The positive side of this condition is empty, the negative side, update the SLAs to show the first response SLA is met.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-10.png?fit=1024%2C642&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The first action in the negative side is a Update Record, using the Id of the created record. Update the first response field to Yes and the SLA succeeded to Yes. This is normally populated via workflow in the application.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>The next step is to retrieve all the SLA instances associated with the record. These are created when a case is created (if you have a default SLA configured) and denote when the SLA for that case will be breached. To make these appear as if the case passed its first response SLA, update the first response instance for this case. Firstly, find the record. This is a list records action, against the SLA KPI Instances entity, with a filter to retrieve only those that are for the case created. The order by condition means that the first response instance is returned first, as it&amp;rsquo;s failure time is naturally before the closure SLA failure time. Using the top count of 1 restricts the return to only one record. This should hopefully mean we retrieve 1 record only and that is the first response SLA.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>Loop through (there will only ever be one) the results and call an Update Record for each, marking the status as succeeded and populate the succeeded on date. Using the warning time will ensure it is prior to the failure time.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-15.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="closing-the-case">Closing the Case&lt;/h3>
&lt;p>On the negative side of the first condition statement, case is going to be closed, but first randomise whether this case met it&amp;rsquo;s case SLA. If the random number is 1 (10 % of cases) the case will be closed, but both the first response and case closure SLAs were not met.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>In the Yes part, use the same technique to the get the case SLA instances and update all of them to Non compliant.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>On the No side, make them all Succeeded and populate the date with the warning date, same as previous. The final part is to close the case. Whilst you now have the ability to perform an unbound action, I could not get it to work. Instead, I used a custom connector.&lt;/p>
&lt;h3 id="custom-connector-to-close-incident">Custom Connector to close Incident&lt;/h3>
&lt;p>I have numerous posts about configuring custom connectors, start with this article on &lt;a class="link" href="https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/" target="_blank" rel="noopener"
>LUIS&lt;/a> to create one. The action is CloseIncident and defined like this.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>The body of the request is below.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;IncidentResolution&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;subject&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="s2">&amp;#34;test postman&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;incidentid@odata.bind&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/incidents(7b978321-e7a0-ea11-a812-000d3a7fc8be)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;overriddencreatedon&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2020-05-22T13:28:43Z&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Status&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">-1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This is a post action against the CloseIncident action, the request is defined below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Drilling into the body parameter, you can see each of the parameters that are required.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>Using this in Flow is straight forward, add a new custom connector and populate the parameters. Be careful over the case Id, as it needs the odata binding populated.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-21.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="finishing-the-loop">Finishing the loop&lt;/h3>
&lt;p>The final part we do is increment the counter variable to ensure only the number of cases we specified are created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>In terms of creating cases, that is it. I created nearly a thousand cases this way in 30 minutes (took a few hours to build out the code obviously) but this is reuseable and even 1000 records in 3 hours is not achievable by hand.&lt;/p>
&lt;h2 id="updating-cases-flow">Updating cases Flow&lt;/h2>
&lt;p>There is always a time when you forget something. In this scenario, Customer Services uses the CSAT score and whether the case is escalated, and my original flow didn&amp;rsquo;t include that information. In hindsight, add these values to the Create case flow. To correct, I created another flow.&lt;/p>
&lt;p>The trigger is the same, manual flow button. The first step is to retreive all the cases that I created. Remember I added to the description &amp;ldquo;This is a test case generated on UtcNow()&amp;rdquo;? This allows me to retrieve all the cases with a description that starts the same.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>Then I loop through the retrieved cases. First of all, create 2 random numbers for use later. Then check if case is closed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>If a case is closed, all you can do is update the status and a few other fields, not all of them. If you try to update the Satisfaction on a closed case, you will get an error. So, for closed cases, open it first, by updating the record status and status reason.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>Then, update the record for a second time, this time adding the Satisfaction and Is Escalated flag. Satisfaction uses a formula to state if the random number, 1-6 is 5 or 6, use 5 as the rating, otherwise use the value of the random number. This allows for a weighting of the satisfaction emphasising a higher rating.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-28.png"
loading="lazy"
>&lt;/p>
&lt;p>Is escalated is true or false. In this scenario, I use a random again, so if the number is 5 or 6 using a range of 1-6, the case was escalated. This means only a small proportion is escalated.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/06-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>Now the case has the data required, close the case again with the custom connector used earlier.&lt;/p>
&lt;p>For the open case, side, just update the record, no need to open first.&lt;/p>
&lt;p>Header Photo by &lt;a class="link" href="https://unsplash.com/@swimstaralex?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Alexander Sinn&lt;/a> on &lt;a class="link" href="https://unsplash.com/s/photos/data?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Unsplash&lt;/a>&lt;/p></description></item><item><title>Sales Insights: Sales accelerator</title><link>https://linked365.blog/2020/05/28/sales-insights-sales-accelerator/</link><pubDate>Thu, 28 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/28/sales-insights-sales-accelerator/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-223.png" alt="Featured image of post Sales Insights: Sales accelerator" />&lt;p>This is the final of a 6 part series on Sales Insights, where I attempt to walk through of the Sales AI functionality that is part of the suite. The other articles are listed here.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/05/sales-insights-basic-set-up/" target="_blank" rel="noopener"
>Basic (Free) Setup&lt;/a> - The &amp;ldquo;free&amp;rdquo; AI capabilities that can be added to any Sales Instance&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/11/sales-insights-assistant-full-capabilities/" target="_blank" rel="noopener"
>Assistant Studio - Full capabilities&lt;/a> - The full suite of options for Insight Cards&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/14/sales-insights-productivity-intelligence/" target="_blank" rel="noopener"
>Productivity Intelligence&lt;/a> - Activity and Contact suggestions as well as Notes Analysis&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/?p=1336" target="_blank" rel="noopener"
>Connection Insights&lt;/a> - Relationship Analytics and Talking points&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/?p=1377" target="_blank" rel="noopener"
>Predictive Models&lt;/a> - Lead and Opportunity scoring along with premium forecasting.&lt;/p>
&lt;p>This post will look at the Sales accelerator, which is still in preview.&lt;/p>
&lt;h2 id="sales-accelerator">Sales Accelerator&lt;/h2>
&lt;p>Playbooks have been around for quite a while - the ability to have a pre-defined set of tasks when something happens. Sequences, which are fundamental for the Sales Accelerator, are a series of prompts to do things which are your best way of completing or reacting to an event. Applying this across your opportunities and leads, it can define what the next action should be today and for which deal.&lt;/p>
&lt;h2 id="configuration">Configuration&lt;/h2>
&lt;p>First, the terms need to be agreed to within the Sales Insights section.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-218.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, the content and layout needs to be defined, which adds components to the Sales Insights forms.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-219.png?fit=1024%2C387&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Ensure you configure the Engagement settings as well as security, I left these as the default.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-220.png"
loading="lazy"
>&lt;/p>
&lt;p>Let Publish and see what has changed. Veronica, my tame Sales user, now has a My Work section in the menu. This shows the Sales Accelerator option. Clicking on this displays a list of things that should be done and the record as shown here.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-221.png?fit=1024%2C800&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Without adding any sequences, the My work is pretty blank, just showing incomplete tasks.&lt;/p>
&lt;h2 id="sequences">Sequences&lt;/h2>
&lt;p>As we have discussed, sequences are a series of recommended tasks of your best practice to complete a sales process successfully. As an administrator, add a new sequence from the Sales Insights settings.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-222.png"
loading="lazy"
>&lt;/p>
&lt;p>Choose a name and also which of the entitles you want this sequence to start on.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-223.png"
loading="lazy"
>&lt;/p>
&lt;p>You are then prompted to create your first activity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-224.png"
loading="lazy"
>&lt;/p>
&lt;p>I chose Email. There are a variety of options depending on what you choose, email having the ability to use a template.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-226.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, add steps as your requirements dictate. Another important one is a wait time. This will mean the next activity will not be displayed until that time has passed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-227.png"
loading="lazy"
>&lt;/p>
&lt;p>Build up your sequence with other steps and delays.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-228.png"
loading="lazy"
>&lt;/p>
&lt;p>Save the sequence then activate it. Activation allows a user to apply the sequence to a record but prevents you from editing it while it is active. You need to deactivate first. Any sequences currently running will be disconnected from the sequence when is deactivated. This is nonsense, in my opinion. If you have a published sequence that you need to tweak, all users would have to re-apply the sequence and start from scratch.&lt;/p>
&lt;p>In a Lead or Opportunity view now, if you select one or more records you get a new option to connect a sequence.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-229.png"
loading="lazy"
>&lt;/p>
&lt;p>This will display a list of the active sequences. Select one and choose Connect.&lt;/p>
&lt;p>![]((images/2020/05-image-230.png?fit=1024%2C395&amp;amp;ssl=1)&lt;/p>
&lt;p>In the My Work section now, you will see an additional list, like below listing 3 lead actions to be done today. This view also shows the other steps I created.&lt;/p>
&lt;p>![]((images/2020/05-image-231.png?fit=1024%2C477&amp;amp;ssl=1)&lt;/p>
&lt;p>The steps can then be completed or action from that central pane. In this case, we can send an email or just mark it as complete. The next action, with the associated record is displayed in the main view.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-SI-Acc-1.gif"
loading="lazy"
>&lt;/p>
&lt;p>In the Up Next pane, the action depends on the type of step. Email will create a new email and populate with the template is selected. Task will use a quick create form. Phone call will attempt to use your configured dialer. I find this a problem as most sales environments won&amp;rsquo;t have an integration, and will frequently rely on a mobile to do the actual call. I would still want to log the fact that this call occurred.&lt;/p>
&lt;p>On the left panel, there are options to sort the list by score and at this point, it brings in all the capabilities of Sales Insights together.&lt;/p>
&lt;h2 id="final-thoughts">Final Thoughts&lt;/h2>
&lt;p>Sequences are a great tool to aid your workforce if your sequence of events is simple. I would like to see branching within the sequence with steps being defined by data on the record. Imagine if the sequence branched determined by the expected revenue or days to decision date? I added this idea &lt;a class="link" href="https://experience.dynamics.com/ideas/idea/?ideaid=343d96cd-fa9f-ea11-8b71-0003ff68992e" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>You can achieve both in Flow, but you need to create the records as you do if you use Playbooks. Sequences allow you to suggest record creation rather than enforce. Also, there is no customisation in sequences, except for Email Templates. Custom activities are not supported, for example. Would love some of the tasks to be automated, like an email reminder if no email has been returned from the customer. And it should interact with the email engagement part to&lt;/p>
&lt;p>The deactivation process also needs to be altered. Deactivating will de-link the sequence form the record. I would suggest deactivating leaves sequences connected to records to run but prevents new connections. You should be able to clone a sequence so that your new one can be used once you have tweaked it. I added the idea &lt;a class="link" href="https://experience.dynamics.com/ideas/idea/?ideaid=1709a075-00a0-ea11-8b71-0003ff68992e" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>Whilst I think it is a good step forward, the functionality available in tools like &lt;a class="link" href="https://www.salesspark.com/" target="_blank" rel="noopener"
>SalesSpark&lt;/a> is above and beyond what is available in Sales Accelerator now. I do think that Microsoft will get there though and hopefully will bring more automation and tools to the standard Sales functionality.&lt;/p></description></item><item><title>Sales Insights: Predictive Models</title><link>https://linked365.blog/2020/05/27/sales-insights-predictive-models/</link><pubDate>Wed, 27 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/27/sales-insights-predictive-models/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-149.png" alt="Featured image of post Sales Insights: Predictive Models" />&lt;p>This is the fifth in the series on Sales Insights, were I attempt to walkthrough the Sales AI functionality that is part of the suite. The other articles are listed here.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/05/sales-insights-basic-set-up/" target="_blank" rel="noopener"
>Basic (Free) Setup&lt;/a> - The &amp;ldquo;free&amp;rdquo; AI capabilities that can be added to any Sales Instance&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/11/sales-insights-assistant-full-capabilities/" target="_blank" rel="noopener"
>Assistant Studio - Full capabilities&lt;/a> - The full suite of options for Insight Cards&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/14/sales-insights-productivity-intelligence/" target="_blank" rel="noopener"
>Productivity Intelligence&lt;/a> - Activity and Contact suggestions as well as Notes Analysis&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/?p=1336" target="_blank" rel="noopener"
>Connection Insights&lt;/a> - Relationship Analytics and Talking points&lt;/p>
&lt;p>This post will walkthrough the Predictive models functionality, which includes Lead and Opportunity scoring as well as Premium forecasting.&lt;/p>
&lt;h2 id="lead-scoring">Lead Scoring&lt;/h2>
&lt;p>Predictive Lead scoring is a machine learning model which puts a score against each open lead. This allows your sales users to prioritise their interactions with leads, nurturing the right ones at the right tie to improve qualification results and reduce the time take to qualify a lead.&lt;/p>
&lt;p>The model used is specific to your organisation and needs to be configured by the administrator prior to publication and usage by the salesforce.&lt;/p>
&lt;p>Like Relationship analytics with similar opportunities I discussed previously, it needs some data. 30 qualified and unqualified leads. I utilised &lt;a class="link" href="https://mockaroo.com/" target="_blank" rel="noopener"
>Mockaroo&lt;/a> to create a thousand leads then used Flow to qualify and unqualify randomly. I detailed my work in the previous post, &lt;a class="link" href="https://linked365.blog/2020/05/21/mockaroo-and-flow-perfect-demo-data/" target="_blank" rel="noopener"
>here.&lt;/a> Once this is done, the predictive lead scoring is enabled.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-144.png?fit=1024%2C748&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Pressing Get Started now shows this screen.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-146.png?fit=1024%2C659&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>I was expecting the ability to create my own model, but it seems it uses the default first. Once ready, it shows this screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-149.png"
loading="lazy"
>&lt;/p>
&lt;p>Not really good accuracy so far&amp;hellip;. Selecting Publish brings you to the configuration site.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-150.png?fit=1024%2C478&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Now, let&amp;rsquo;s add some fields that have been populated in the Lead to personalise the model. Select Edit Fields. The next screen allows you to define the list of fields that you think have an impact on the qualification rate of a lead. Here, the fields that were populated when I created Leads are used. Your mileage on which fields is part of the training of your model.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-199.png"
loading="lazy"
>&lt;/p>
&lt;p>Once this is done, Click Retrain model for this new field selection to be used. After a period, the model is ready, and you can publish this model. Once published, the toggle for retraining automatically is available. This will, as it suggests, retrain the model regularly based on the fields selected. It will only publish the new version of the model it is better at predicting that the previous model&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-200.png"
loading="lazy"
>&lt;/p>
&lt;p>On the Lead form, there is a new section available, namely Predictive Lead Scoring.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-201.png"
loading="lazy"
>&lt;/p>
&lt;p>This is telling the sales user that this lead is likely to be disqualified, and the reasons why. There is also a view that is made available, My Open Leads Scored which gives a visual indicator of the score for each. Great information for a Sales user to quickly identify the Leads worth progressing.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-202.png?fit=1024%2C226&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h2 id="opportunity-scoring">Opportunity Scoring&lt;/h2>
&lt;p>Similar steps can be completed for the Opportunity Scoring, with a Predictive Opportunity Scoring section added to the Opportunity form.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-203.png"
loading="lazy"
>&lt;/p>
&lt;p>Top right of this section is a Chat icon, allowing a user to give feedback and provide a different score to the one given.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-204.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="premium-forecasting">Premium Forecasting&lt;/h2>
&lt;p>Premium Forecasting is based on the standard forecasting but adds a prediction on the value of each opportunity dependent on historical information as well as data in the opportunity.&lt;/p>
&lt;p>To establish forecasting, first, as an administrator, establish a forecast by choosing the Forecast configuration in the Sales App Settings section.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-206.png"
loading="lazy"
>&lt;/p>
&lt;p>Add a Org chart Forecast. This presents you with a form to fill out.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-207.png?fit=1024%2C849&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Required fields are a name and the top of the hierarchy. Here, I have configured the management hierarchy as shown to reflect the data in my system.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-208.png"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on the progress bar at the top (great control!), leave the user security section as default and hit Next.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-210.png"
loading="lazy"
>&lt;/p>
&lt;p>Include the Prediction field in the Layout and columns section. Here, you can add a column set - I found difficulty here, as the configuration of the values was not done automatically, I had to attach a column set and then use the option to change option set selection to choose the one I actually wanted, which would then show the Auto-configure columns option.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-212.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Next again, then activate the forecast.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-214.png"
loading="lazy"
>&lt;/p>
&lt;p>After a while, a success message is displayed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-215.png"
loading="lazy"
>&lt;/p>
&lt;p>Once this is done, sales users will be able to select the Forecasts section for themselves. As you can see from the version for Veronica, the Opportunities in the forecast include the hierarchy. The bottom panel can also be used to quickly forecast data, such as the category, revenue and close dates.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-217.png?fit=1024%2C559&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The Prediction value in the top row is meant to show the revenue, including the prediction percentage, but I have found it hard to replicate the data I need to establish a value.&lt;/p></description></item><item><title>Launch (Self) - Check App permissions in Power Apps</title><link>https://linked365.blog/2020/05/22/launch-self-check-app-permissions-in-power-apps/</link><pubDate>Fri, 22 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/22/launch-self-check-app-permissions-in-power-apps/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-192.png" alt="Featured image of post Launch (Self) - Check App permissions in Power Apps" />&lt;p>On the Twitterverse yesterday, it was announced that you now have the ability to Launch an application to replace itself.&lt;/p>
&lt;p>&lt;a class="link" href="https://powerapps.microsoft.com/en-us/blog/formulas-launch-to-self-and-self-operator/" target="_blank" rel="noopener"
>https://powerapps.microsoft.com/en-us/blog/formulas-launch-to-self-and-self-operator/&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://twitter.com/iAm_ManCat" target="_blank" rel="noopener"
>@Sancho Harker&lt;/a>, &lt;a class="link" href="https://twitter.com/TheCRMNinja" target="_blank" rel="noopener"
>@EY Kalman&lt;/a>, &lt;a class="link" href="https://twitter.com/ClarissaGillin2" target="_blank" rel="noopener"
>@Clarissa Gillingham&lt;/a> and I had a discussion about the uses of this new feature, and the thing I mentioned was that you should be able to do an app which is a central repository, an app selector. The problem I saw was that you needed to know if a user had access to an app. If they have access, show the app button, if not, don&amp;rsquo;t display it.&lt;/p>
&lt;p>As a user, having a button that gives an error is infuriating.&lt;/p>
&lt;p>I knew there were admin connectors for Power Apps in Power Automate, and you could use the action Get App Role Assignments as Admin from the Power Apps for Admin connector to get a list of people who had access to an app, but would this work? Surely you needed administrative access to use this connector? So, I had to do a proof of concept to make it work.&lt;/p>
&lt;h2 id="the-flow">The Flow&lt;/h2>
&lt;p>Firstly, this is an HTTP Request. The reason being the connectors needed are Admin only, Environment Maker is needed to use the administrator connectors, so this Flow needs to run as an admin user.&lt;/p>
&lt;p>This whole piece could be simpler if I could call this from a Power App directly, but this restriction means we need a two-hop method, two flow runs, though the first step should be covered by the Canvas app licence and the second, this flow, needs to be an administrator with a Per user Plan.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-174.png"
loading="lazy"
>&lt;/p>
&lt;p>The JSON body is simple, just an AppName and Email of the user, both strings.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;object&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;properties&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;AppName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Email&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;string&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Next, get your app permissions. This is in a couple of steps, so this Flow can move between environments. First, get a reference to the current environment. Next, get all the Apps in that environment. Finally, filter this list to only the one sent in in the HTTP parameters.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-177.png"
loading="lazy"
>&lt;/p>
&lt;p>There is a property of the returned app which is the Display Name. This is what is used to filter and match on, comping from the HTTP request.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-176.png"
loading="lazy"
>&lt;/p>
&lt;p>Now we can use the Get App Role Assignments as Admin connector to retrieve a list of users who have been given permission to our application.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-178.png"
loading="lazy"
>&lt;/p>
&lt;p>The PowerApp Name I am interested in is for the first one returned, so use an expression like above to prevent a Apply to Each loop.&lt;/p>
&lt;p>As this action could fail, it is the first time a connector is asking for something, configure a run after. Positive is for carrying on, failure we respond to http request.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-179.png"
loading="lazy"
>&lt;/p>
&lt;p>On the success side, filter the list of role assignments, checking for a Tenant type. This looks for a situation where you have shared the application with &amp;ldquo;Everyone&amp;rdquo;.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-180.png"
loading="lazy"
>&lt;/p>
&lt;p>Check to see if the returned array has any items in it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-181.png"
loading="lazy"
>&lt;/p>
&lt;p>If there is, respond positively.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-182.png"
loading="lazy"
>&lt;/p>
&lt;p>If no tenant access, check for specific user access by first filtering to only all the user principal types.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-183.png"
loading="lazy"
>&lt;/p>
&lt;p>Then check for the users email that was passed in.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-184.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, check that this array has values in it and respond accordingly.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-186.png?fit=1024%2C514&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>That is all for the main flow. Now to call this from PowerApps.&lt;/p>
&lt;h2 id="calling-main-flow">Calling Main Flow&lt;/h2>
&lt;p>To call the flow, you have to get Power Apps to call a http request, not directly possible, but if you put a wrapper around your flow like below, it can be done.&lt;/p>
&lt;p>Firstly, the trigger is PowerApps. Next call the primary flow above. The body sent contains 2 fields you ask for from the Power App. Unfortunately, you can not, yet, rename these variables.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-187.png"
loading="lazy"
>&lt;/p>
&lt;p>Parse the response from this so it makes it easier to return the response and respond to Power Apps.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-189.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="app-launcher">App Launcher&lt;/h2>
&lt;p>The App Launcher solution looks like this now.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-191.png"
loading="lazy"
>&lt;/p>
&lt;p>The App Launcher is configured with 3 buttons.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-192.png"
loading="lazy"
>&lt;/p>
&lt;p>Each button is configured to launch one of the other apps. This is the App Id. The default is to launch self, so no need for another parameter. This is all documented well in the &lt;a class="link" href="https://docs.microsoft.com/en-us/powerapps/maker/canvas-apps/functions/function-param" target="_blank" rel="noopener"
>Microsoft Launch documentation&lt;/a>.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-193.png?fit=1024%2C50&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The visibility of each button is controlled by variables, here for our secret app button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-194.png"
loading="lazy"
>&lt;/p>
&lt;p>On launch of the application, use the Flow above to populate the visibility variables for each button.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-195.png?fit=1024%2C71&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h2 id="sharing-the-apps">Sharing the Apps&lt;/h2>
&lt;p>Now it is all up and running, lets just check the access. For App Launcher, App 1 and App 2 I have shared with the whole tenant, as shown here.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-197.png"
loading="lazy"
>&lt;/p>
&lt;p>The secret app is not shared with everyone though.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-198.png"
loading="lazy"
>&lt;/p>
&lt;p>Launching the App Launcher as my admin role, you can see the buttons become visible as the code is run.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/Launch1.gif?fit=1024%2C725&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>For Veronica, who doesn&amp;rsquo;t have access to the secret app, her experience is the same, but she never sees the third button.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/Launch2-1.gif?fit=1024%2C725&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This solution is not perfect, it is missing any groups you are a member of, which is a big part of sharing apps, but just lets you know it is possible.&lt;/p></description></item><item><title>Mockaroo and Flow: Perfect Demo data</title><link>https://linked365.blog/2020/05/21/mockaroo-and-flow-perfect-demo-data/</link><pubDate>Thu, 21 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/21/mockaroo-and-flow-perfect-demo-data/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-luca-abad-lopez-qC6XbnBm-jo-unsplash-1.jpg" alt="Featured image of post Mockaroo and Flow: Perfect Demo data" />&lt;p>As a consultant, architect or just a blogger, you have to do a lot of demos. Recently, with my look at Sales Insights, the amount of data I needed was increasing. I had used Flow in the past to automate data entry, and it worked well, so I thought I would create some data for my environment using Flow, but first sourcing the data in Mockaroo.&lt;/p>
&lt;h2 id="mockaroo">Mockaroo&lt;/h2>
&lt;p>&lt;a class="link" href="https://mockaroo.com/" target="_blank" rel="noopener"
>Mockaroo&lt;/a> is a free data generator service which allows you to establish the fields you want and create a dummy import file for Dynamics. Great for my needs.&lt;/p>
&lt;p>For Sales Insights Lead prediction, I need Leads. So, First and last name, email, account name, topic, job title and email. Mockaroo has various types which you can use to flesh out the data. Fake company names, random first and last name etc. It does a great job of ensuring the chosen name / last name also links to the email address. Some things I needed were not present, such as the topic. It doesn&amp;rsquo;t really matter for my demo what data was in there, just needed something random, which the type grocery products gives me.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-147.png?fit=1024%2C823&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Choose the number of rows you need, select the format as CSV and Download. Open in Excel to view your random data goodness.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-151.png"
loading="lazy"
>&lt;/p>
&lt;p>Importing data into Dynamics has never been easier. Select Import from CSV from the Import from Excel menu on a view for the entity you want to import against (assuming you have enabled Import Data in security) and choose your file. Mockaroo uses double quotes for its quotation mark and comma as a separator. Select Review Mapping.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-152.png?fit=499%2C1024&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Here, map the CSV fields to the Dynamics fields, particular attention to the Primary fields which you need to populate. Hit Finish Import and this will queue your import job. Once successful, you will have a new set of &amp;ldquo;random&amp;rdquo; data for your use.&lt;/p>
&lt;h2 id="augmenting-your-data-in-flow">Augmenting your data in Flow&lt;/h2>
&lt;p>For Predictive Leads, you need 30 qualified and unqualified leads. To go through the steps to qualify each of the 1000 leads that were just added would be a time-consuming exercise. Also, there are some fields that the Predictive Leads default model would like, such as Industry type, budget, annual revenue and number of employees. These fields need updating with a random value prior to (dis)qualification.&lt;/p>
&lt;p>Industry type is an option set. The Common Data Service connector at the moment doesn&amp;rsquo;t give the user the ability to retrieve the values so you have to resort to a Custom Connector.&lt;/p>
&lt;p>I have been through &lt;a class="link" href="https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/" target="_blank" rel="noopener"
>customer connectors&lt;/a> before, for my &lt;a class="link" href="https://linked365.blog/2019/10/16/d365-org-db-settings-canvas-app/" target="_blank" rel="noopener"
>Org Settings app&lt;/a> amongst others. A custom connector allows connection to the wider Power Platform API, where you can do all manner of things, but most importantly for us retrieve a list of options for a field.&lt;/p>
&lt;h3 id="connector-action-definition">Connector Action Definition&lt;/h3>
&lt;p>I am not going to go through the basics of the connector creation, see my previous posts for that. What is specific to this project is the action to retrieve the option set. The URL for retrieving a list of option set values is below.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">https&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="c1">//{url}/api/data/v9.1/EntityDefinitions(&amp;#39;{entity}&amp;#39;)/Attributes(&amp;#39;{field}&amp;#39;)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet?$select=Options&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>{url} is just the standard Power Platform log in url. {Entity} and {field} select which entity and field you want to return the values for. For example, to return the gender code options on Contact, you would use this url.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">https&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="c1">//MYDEMOENVIRONMENT.crm11.dynamics.com/api/data/v9.1/EntityDefinitions(&amp;#39;contact&amp;#39;)/Attributes(&amp;#39;gendercode&amp;#39;)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet?$select=Options&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Transposing to the requirement for a custom connector, allowing for path parameters.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">https://MYDEMOENVIRONMENT.crm11.dynamics.com/api/data/v9.1/EntityDefinitions(&amp;#39;{entity}&amp;#39;)/Attributes(&amp;#39;{field}&amp;#39;)/Microsoft.Dynamics.CRM.PicklistAttributeMetadata/OptionSet?$select=Options
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The {} are placeholders for path parameters. Use this link in the Import Sample and choose Get as the verb should result in the below action configuration.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-156.png"
loading="lazy"
>&lt;/p>
&lt;p>By editing the Query variable, you can make it default to Options, make it required and make it internal so it hides the value from your Flow call.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-158.png"
loading="lazy"
>&lt;/p>
&lt;p>This should be enough for you to start with your Flow.&lt;/p>
&lt;h3 id="update-leads-flow">Update Leads Flow&lt;/h3>
&lt;p>This flow is manually triggered. First thing is to get the options set values, which is a call to the custom connector. I want the Industry Types, so use the entity lead and the field industrycode.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-159.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, get all the leads you want to update. In my scenario, all the leads created after yesterday which is still active. This is anything I imported.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-160.png"
loading="lazy"
>&lt;/p>
&lt;p>Loop through the Leads and decide on whether it is going to be qualified or not. I do this by using the rand() function, which gives me a random integer between the first and second parameters. So, rand(1,4) would give me either 1, 2 or 3. As I want to favour qualified leads, only 1 counts as a lost deal. This will provide me with roughly 2/3 qualified leads.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-161.png?fit=1024%2C290&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h4 id="disqualification-of-a-lead">Disqualification of a Lead&lt;/h4>
&lt;p>This is straight forward update record, but with a few interesting parts.&lt;/p>
&lt;p>Firstly, using rand() again populated budget, employee and annual revenue. Use different min and max values to populate the values accordingly.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-163.png"
loading="lazy"
>&lt;/p>
&lt;p>The only other interesting part is entering the Industry Type.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-164.png"
loading="lazy"
>&lt;/p>
&lt;p>The expression is below and broken down to the key parts.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">outputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">OptionSetValues&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">Options&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">]?[&lt;/span>&lt;span class="n">rand&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="m">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">outputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">OptionSetValues&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">/&lt;/span>&lt;span class="n">Options&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">]))]?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Value&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Firstly get all the options return by my custom connector call.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">outputs(&amp;#39;OptionSetValues&amp;#39;)?[&amp;#39;body/Options&amp;#39;]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Next, select one of the options by choosing a random number between 0 (o indexed array) and the number of options returned. If I have 10 options, the list will be returned with items in slots 0 - 9. So this effectively chooses which one I am going to use by random.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">[rand(0, length(outputs(&amp;#39;OptionSetValues&amp;#39;)?[&amp;#39;body/Options&amp;#39;]))]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Finally, the Option is actually an object, the value I actually need to populated in the record is Value&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-fallback" data-lang="fallback">&lt;span class="line">&lt;span class="cl">?[&amp;#39;Value&amp;#39;]
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>I know, not exactly low code. There are other ways to do this, with Selects, etc., but this gives a one-line expression.&lt;/p>
&lt;p>Finally in this lead update, set the status and status reason.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-165.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="qualifying-a-lead">Qualifying a Lead&lt;/h4>
&lt;p>Qualification of a lead is a little trickier. Start with a lead update, which is the same as the one for disqualification except you don&amp;rsquo;t set the status/status reason.&lt;/p>
&lt;p>Next, call the Perform an unbound action action. This is only available if you are within a solution and using the current environment connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-168.png"
loading="lazy"
>&lt;/p>
&lt;p>Select an entity, Lead, an Action, QualiifyLead and Item Id, the record that has just been updated. I have selected Yes for all the create options, so it will create a Contact, Account and Opportunity as it processes.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-170.png"
loading="lazy"
>&lt;/p>
&lt;p>At the bottom of the action, also update the status of the lead to 3, which is Qualified.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-169.png"
loading="lazy"
>&lt;/p>
&lt;p>The problem with this action is that it causes an error, the return from this action is an object where it is expecting an object. I am sure someone more skilled in the way of Flow will be able to tell me the real way of fixing this, but for me, I just add a Compose action that does nothing and ensures this action gets called whether the Qualification fails or not.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-171.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-172.png"
loading="lazy"
>&lt;/p>
&lt;p>The full flow is below. I manage to qualify or not 1000 leads in 27 minutes, admittedly it took a couple of hours to build the flow, but still, 2 1/2 hours for 1000 lead qualifications is pretty good!&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-166.png?fit=1024%2C732&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Hopefully this has showed you some of the tools available to you via Flow to manipulate data.&lt;/p>
&lt;p>Title Photo by &lt;a class="link" href="https://unsplash.com/@lucaca24?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Luca Abad Lopez&lt;/a> on &lt;a class="link" href="https://unsplash.com/s/photos/kangaroo-disguise?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" target="_blank" rel="noopener"
>Unsplash&lt;/a>&lt;/p></description></item><item><title>Sales Insights: Connection Insights</title><link>https://linked365.blog/2020/05/18/sales-insights-connection-insights/</link><pubDate>Mon, 18 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/18/sales-insights-connection-insights/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-140.png" alt="Featured image of post Sales Insights: Connection Insights" />&lt;p>This is the fourth in a series walking through the Sales Insights add-on application. The series list is below for your reference.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/05/sales-insights-basic-set-up/" target="_blank" rel="noopener"
>Basic (Free) Setup&lt;/a> - The &amp;ldquo;free&amp;rdquo; AI capabilities that can be added to any Sales Instance&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/11/sales-insights-assistant-full-capabilities/" target="_blank" rel="noopener"
>Assistant Studio - Full capabilities&lt;/a> - The full suite of options for Insight Cards&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/2020/05/14/sales-insights-productivity-intelligence/" target="_blank" rel="noopener"
>Productivity Intelligence&lt;/a> - Activity and Contact suggestions as well as Notes Analysis&lt;/p>
&lt;p>This post will be walking through Connection Insights, which includes Relationship Analytics and Talking Points.&lt;/p>
&lt;h2 id="relationship-analytics">Relationship Analytics&lt;/h2>
&lt;p>Relationship Analytics uses the data stored in D365 and Exchange, whether accounts, contacts, activities and emails. It then computes numerous KPIs for this data to establish how best to interact with an individual, leading to improved closure rates and customer satisfaction. There is also an analysis of the health of relationships to improve customer retention.&lt;/p>
&lt;p>The first step is to enable Relationship analytics and health by clicking the box within the Sales Insights settings app.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-124.png?fit=1024%2C584&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Hitting Save (the 2 Data Sources options were not enabled for me) you get a message stating it is being activated.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-125.png"
loading="lazy"
>&lt;/p>
&lt;p>After a short period, a success message is ready to use. At this point I have not changed any settings, including not enabling the Exchange Online configuration, as I would like to see what it is like without Email data.&lt;/p>
&lt;p>For the sales user, there is a new View available against opportunities, namely My Open Opportunities by Relationship. On first use, this is not very impressive.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-126.png?fit=1024%2C320&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Relationship health is done by looking at the frequency and type of interaction with the customer regarding the opportunity. By adding in some data (this is a demo system so data is not available) the view becomes a lot more usable.&lt;/p>
&lt;p>In this instance, data is added to the opportunity. You will also notice that a new section to the Opportunity form is has appeared. This section is giving me a visual representation of the health and indication when the next and last interactions were.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-128.png?fit=1024%2C505&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The KPIs are not populated straight away, it states it could be a couple of hours behind, so be patient. You will see the Relationship Health State (KPI) populated with the Health Computation in Progress which indicates it has enough data to provide a value.&lt;/p>
&lt;p>Once calculated, the control on the form is updated&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-130.png"
loading="lazy"
>&lt;/p>
&lt;p>Further, the view is giving you a visual indication across your opportunities&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-131.png?fit=1024%2C326&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Unfortunately, the data I entered wasn&amp;rsquo;t enough to make the relationship anything except poor! As you add more activity, this changes. I think on a 12 hour cycle, but can not confirm.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-132.png?fit=1024%2C165&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Also, now it is a little more insightful and realistic, let&amp;rsquo;s look at the chart that comes with the solution. Click on Show Chart and select Relationship Pipeline.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/SI-Rel-Ana-1.gif?fit=1024%2C719&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This chart shows all the deals that are due to close and plots them along with their relationship health. The bigger the circle, the larger the revenue. You can also hover over a point to see those key metrics. Pretty!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-133.png"
loading="lazy"
>&lt;/p>
&lt;p>Digging further into some of the tools, along with the control on the Opportunity record, there is a new tab, Relationship Analytics.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-135.png?fit=1024%2C455&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This is a great, one stop shop to look at the activity on the opportunity and how it is improving over time. Top left is the same content you seen on the first tab. Next is the count of Interactions that have occurred on this opportunity, split between us, your employees, and them, your customers.&lt;/p>
&lt;p>The top right shows the time spent on the Opportunity, a count of the hours spent in appointments or tasks, again split between us and them. Us is calculated by multiplying the length of the activity by the number of employees were part of the activity. Them does not do this calculation and is just a summation of the length of the activities where they were involved.&lt;/p>
&lt;p>Email Engagement relies on the Email Engagement functionality discussed in a previous &lt;a class="link" href="https://linked365.blog/2020/05/05/sales-insights-basic-set-up/" target="_blank" rel="noopener"
>post&lt;/a>. It shows all emails that were sent to and from the customer and how many were opened etc. Response rate measures the ratio of emails we sent to the customer which they responded to and vice-versa. This also comes from the Response time, which is the next chart.&lt;/p>
&lt;p>Most contacted displays the contacts that have been included on meetings, calls or emails regarding this opportunity. This is duplicated for who has sent the most emails etc in Most Contacted By.&lt;/p>
&lt;p>Finally, the Relationship Activities lists when activity has taken placed, the create date for activities over the lifetime of the Opportunity.&lt;/p>
&lt;p>This tab is pretty useful and will come into its own when you have the data to support it. We all know the more you speak to a client the more likely an opportunity will be successful. The likelihood of a deal being lost where the customer continues to respond frequently and quickly is pretty slim.&lt;/p>
&lt;h2 id="fine-tuning-the-results">Fine-tuning the results&lt;/h2>
&lt;p>Microsoft has provided you with a way of &amp;ldquo;tweaking&amp;rdquo; the results of the KPIs by rating the relative influence of each activity type. This will depend on your business and how it operates. For a B2C business, I would suggest that email or phone calls would be normal, and a meeting would normally be rare and infer a good relationship with the customer. B2B these would be different, with meetings more common.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-136.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="relationship-analytics-with-similar-opportunities-preview">Relationship Analytics with similar opportunities (preview)&lt;/h2>
&lt;p>There is a preview addition to the Sales Insights tools, namely relationship analytics with similar opportunities. There is a warning when you enable this feature that you need to have at least 30 each of won and lost opportunities to allow the new KPIs to be available.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-137.png?fit=1024%2C212&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>In that spirit, I created a Flow to generate the data. The flow asks for a number, then creates that number of opportunities for each active account with that number of activities, a random mix of emails, meetings, tasks &amp;amp; calls against each opportunity. It then closes the opportunity, either won or lost, with a roughly 60% spilt for won.&lt;/p>
&lt;p>You can find the flow as well as the other tweaks I made to my environment in GitHub &lt;a class="link" href="https://github.com/CooksterC/Community/tree/master/SalesInsightsTweaks" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>By enabling the preview, you have to agree to the terms.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-139.png"
loading="lazy"
>&lt;/p>
&lt;p>On the Opportunity screen now, the Relationship Analytics tab is replaced with Relationship Analytics (Preview) and is significantly improved, comparing your opportunity with the historic data.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-140.png?fit=1024%2C870&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h2 id="talking-points">Talking Points&lt;/h2>
&lt;p>Small talk is a method of embedding you with a customer or lead. If they think you are friendly and discuss more than just the product or deal, then it has been proven to increase the likelihood of winning a contract. Remembering all your client&amp;rsquo;s insignificant details, and not confusing customers is hard work. Great salespeople make notes on each client and keep them updated. Dynamics eases this pain by scanning your email and highlighting to you details about the customer which you can use to improve your relationship with them.&lt;/p>
&lt;p>These talking points are using the individuals&amp;rsquo; email, which is private to them, so any points that displayed are specific to the individual sales user.&lt;/p>
&lt;p>Back in the Sales Insights settings, an administrator can enable talking points and also which categories to use.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-142.png"
loading="lazy"
>&lt;/p>
&lt;p>There is one more thing you need to do to enable this, and it isn&amp;rsquo;t documented. Thankfully Priyesh Wagh steered me straight in his blog &lt;a class="link" href="https://d365demystified.com/2018/12/09/talking-points-in-d365-ai-for-sales/" target="_blank" rel="noopener"
>article&lt;/a> for D365 DeMystified. Thanks, &lt;a class="link" href="https://twitter.com/priyesh_wngman7" target="_blank" rel="noopener"
>Priyesh&lt;/a>!&lt;/p>
&lt;p>The relationship analytics solution adds a control to the contact form, namely TalkingPoints_section. This needs making visible by default, the form published an then you will see in the contact form a new section. This is populated with parts of an email I sent in.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-143.png"
loading="lazy"
>&lt;/p>
&lt;p>Each of the icons in the bottom represents the categories that have been found in the email that you have with the contact. If you click on an icon, the relevant snippet is shown. Further you can choose to view this in carousel view, the default, or list view by clicking on the icon top right.&lt;/p>
&lt;p>Lastly, by selecting the drop down arrow, the full email is displayed, where the user can click on the hyperlink to go to that email.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-SI-Rel-Ana-2.gif"
loading="lazy"
>&lt;/p></description></item><item><title>Sales Insights: Productivity Intelligence</title><link>https://linked365.blog/2020/05/14/sales-insights-productivity-intelligence/</link><pubDate>Thu, 14 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/14/sales-insights-productivity-intelligence/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-91.png" alt="Featured image of post Sales Insights: Productivity Intelligence" />&lt;p>This is the third instalment of my review/walkthrough of the Dynamics 365 Sales Insights application. &lt;a class="link" href="https://linked365.blog/2020/05/05/sales-insights-basic-set-up/" target="_blank" rel="noopener"
>Part 1&lt;/a> detailed the free features, with &lt;a class="link" href="https://linked365.blog/?p=1242" target="_blank" rel="noopener"
>Part 2&lt;/a> detail the first of the premium features, Assistant Studio, including custom Insight cards and how to prioritise them.&lt;/p>
&lt;p>This time, the blog is about Productivity Intelligence. This encompasses Auto capture (automatically bringing in content from Outlook and act on it, to reduce time entering data), email engagement (tracking email interaction from your customers) and Notes analysis (suggesting actions on the notes you make).&lt;/p>
&lt;h2 id="auto-capture">Auto capture&lt;/h2>
&lt;p>I have already discussed the basic version of this, so will just be going through the additions the Premium version brings.&lt;/p>
&lt;p>Auto capture is not enabled by default when you enable the other Sales Insights features, toggle the switch&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-91.png"
loading="lazy"
>&lt;/p>
&lt;p>You have to agree to the terms and conditions as this is still a preview feature&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-92.png"
loading="lazy"
>&lt;/p>
&lt;p>Here you now get to choose a security role or allow all users to enrol. This is on top of the license requirement. I checked all the content to be captured for my trial.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-93.png"
loading="lazy"
>&lt;/p>
&lt;p>As All security roles have been selected, the warning that basic features will be displayed is shown.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-94.png"
loading="lazy"
>&lt;/p>
&lt;p>Once complete, each user will have to give individual consent as well, which appears in the timeline or in the Assistant like below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-98.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-99.png"
loading="lazy"
>&lt;/p>
&lt;p>After you select Allow access, the central panel now has an Activity Suggestions link.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-100.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="activity-suggestions">Activity Suggestions&lt;/h3>
&lt;p>If an email comes into the users inbox now, a notification is displayed if the email address is associated with the account or contact.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-101.png"
loading="lazy"
>&lt;/p>
&lt;p>At the bottom is a Show all link, which displays a simple popup before delivering the user to the Activity Suggestions page.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-102.png"
loading="lazy"
>&lt;/p>
&lt;p>This is also available via the menu on the left&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-104.png?fit=1024%2C292&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Back in the timeline frame, a couple of options are available to the user, highlighted below. The first dismisses the suggestion, removing it from the list of possible suggestions.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-105.png"
loading="lazy"
>&lt;/p>
&lt;p>The next allows you to edit the activity, namely set the regarding to a different record&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-106.png"
loading="lazy"
>&lt;/p>
&lt;p>Hitting Save on the Edit screen shows this screen before the activity becomes part of the timeline.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-107.png?fit=1024%2C595&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The third option is just Save, which provides a prompt before it is created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-108.png"
loading="lazy"
>&lt;/p>
&lt;p>A small prompt is also shown when saving activities in this manner&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-109.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="contact-suggestions">Contact Suggestions&lt;/h3>
&lt;p>With the advanced features, you also get Contact Suggestions. This reduces the effort that syncing contacts etc. can be for your workforce. If an email is received from an email that is not within D365, a contact suggestion is created. An insight suggestion appears on the dashboard, which takes you to the full list on the left.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-112.png"
loading="lazy"
>&lt;/p>
&lt;p>On the menu, there is also a Contact Suggestions menu allowing the user to go to their full list.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-119.png?fit=1024%2C286&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>These contacts are ones that are not present in my instance and as such are prime to be brought in. Selecting a contact or the hyperlinked full name takes you to a quick create form, prepopulated with the information it has captured.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-120.png"
loading="lazy"
>&lt;/p>
&lt;p>Save and Close will create a contact in the system. Hitting cancel returns you to the list, but the contact suggestion is removed. I have asked the question on the forums, as I don&amp;rsquo;t think this is correct behaviour, whether intentional or not. Will update if I get a response.&lt;/p>
&lt;p>&lt;strong>UPDATE&lt;/strong>: Had confirmation that this is a bug and it &lt;a class="link" href="https://community.dynamics.com/365/aisales/f/dynamics-365-sales-insights/389123/contact-suggestions---cancel-in-quick-create-removes-suggestion/1044856#1044856" target="_blank" rel="noopener"
>will be fixed&lt;/a> by the end of the month! See, if you raise problems to Microsoft, they get resolved!&lt;/p>
&lt;p>On the list, you also have options to either Save as contact, which will create using the default population or Edit and Save which will show the quick create form. Delete will remove this contact from the suggestions. If you select more than one contact suggestion, only Save as contact and Delete are available.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-122.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="notes-analysis">Notes Analysis&lt;/h3>
&lt;p>The final part of Productivity Intelligence is Notes Analysis. This uses sentiment analysis to capture information held in the notes against contacts, accounts or opportunities. From this information, suggestions are made with data retrieved from the notes.&lt;/p>
&lt;p>Notes Analysis is enabled within the Sales Insights application once again. Toggle the switch.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-111.png"
loading="lazy"
>&lt;/p>
&lt;p>So now, in the activity pane against accounts, contacts, case, opportunity &amp;amp; lead you will be offered suggestions to create other records from the content in the notes. This is by providing a hyperlink in the note itself.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-113.png"
loading="lazy"
>&lt;/p>
&lt;p>Notice how the notes are read in direct notes and emails. Clicking on the link provides the user with a suggestion.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-115.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see from this suggestion, not only has it determined that I should have a meeting planned for Tuesday, but automated the date entry from my &amp;ldquo;next tuesday&amp;rdquo;.&lt;/p>
&lt;p>If I hit Edit and Create, a Quick Create form is displayed, prepopulated with the detail.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-116.png"
loading="lazy"
>&lt;/p>
&lt;p>The only issue I have here is that the note, when I return to the Timeline, still appears like I have not done the previous step and created the activity. Some suggestions allow a quicker create process, if you don&amp;rsquo;t need to change any of the detail&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-117.png"
loading="lazy"
>&lt;/p>
&lt;p>Edit and Create displays the prepopulated Quick Create form. Create just accepts the defaults and creates the record.&lt;/p>
&lt;p>Note Analysis is a great tool to the arsenal of the busy sales person. All of these tools are trying to reduce the time spent doing administrative tasks and push the sales person to be more active with their customers.&lt;/p></description></item><item><title>Sales Insights: Assistant (full capabilities)</title><link>https://linked365.blog/2020/05/11/sales-insights-assistant-full-capabilities/</link><pubDate>Mon, 11 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/11/sales-insights-assistant-full-capabilities/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image-48.png" alt="Featured image of post Sales Insights: Assistant (full capabilities)" />&lt;p>In my previous &lt;a class="link" href="https://linked365.blog/?p=1183" target="_blank" rel="noopener"
>post&lt;/a>, I walked through the configuration of the standard, &amp;ldquo;free&amp;rdquo; features of the Sales Insights offering for D365 Sales. This time, I am going to start on the premium features covered by the £37.70 per month license fee.&lt;/p>
&lt;p>If you look at the Sales Insights administration screen, the list of the capabilities is quite hefty. For this post, I will concentrate on the Assistant, Sales Insights cards and prioritising them.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-48.png"
loading="lazy"
>&lt;/p>
&lt;p>To get going, hit the Try Sales Insights button. This launches the screen below. Read and agree to the terms and hit continue.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-51.png?fit=1024%2C275&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Once done, you are presented with the install screen.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-52.png?fit=1024%2C497&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Once installation is complete, a message appears and the Go to Configuration is now available. This button takes the user to the Sales Insights Settings portion of the application.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-53.png?fit=1024%2C88&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>As you can see there is a lot more settings available to the administrator now. Lets start with the Insight Cards available in the Assistant Studio.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-54.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="assistant-studio">Assistant Studio&lt;/h2>
&lt;p>The advanced Assistant Studio is a separate display than the &amp;ldquo;free&amp;rdquo; version I mentioned on previous post.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-55.png?fit=1024%2C740&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>The first thing you will notice is the ability to make your own. This utilises Power Automate (and from there, you could rule the world) to define a schedule or trigger to run and produce a card for display.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-56.png?fit=1024%2C364&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Each Insight card has a security role selection now.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-77.png"
loading="lazy"
>&lt;/p>
&lt;p>Also, on the left is an ability to tweak the ranking of the cards, which ones appear higher in the view. This is tweaking the inbuilt sorting in addition to being able to make the card a priority. It is pretty limited, only 4 ranks available, but I would think that this is more than enough for most scenarios.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/image-79.png?fit=1024%2C478&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h3 id="creating-a-custom-insight-card">Creating a Custom Insight Card&lt;/h3>
&lt;p>Though the most common scenario would be using Power Automate to create a custom Insight, it is possible to go further by using cards created as XML and import them into your environment as a solution. The card is triggered by using the Web API. This will require a blog post on its own to get to the details, but for now, here is the link the Microsoft &lt;a class="link" href="https://docs.microsoft.com/en-gb/dynamics365/ai/sales/extend-relationship-assistant-card" target="_blank" rel="noopener"
>tutorial&lt;/a> on the subject. As you are calling the Web API, when and if these cards get created is open to a whole manner of scenarios - alerting from a finance system or bespoke service offering, or even telemetry from your own app or licensing solution is possible.&lt;/p>
&lt;p>Thankfully, creating cards via Power Automate is a lot simpler. I will walk through a scenario that is applicable to a Sales team. Everyone has competitors. Competitors all have blog rolls where they publish information on their products and views. It would be good to highlight these new posts to your Sales team, so they are aware of the latest developments prior to discussions with their customers. You can have a trigger for when an RSS feed changes, but this would mean you would have a flow for each blog. Adding a competitor blog would be time-consuming and in-effective.&lt;/p>
&lt;p>My design would be to on a daily schedule, loop through each of the competitors stored in the D365 environment with a blog, read any articles that have been posted since the day before and create an Insight card for each.&lt;/p>
&lt;p>I created a new field on the Competitor entity to enter the blog address.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-59.png"
loading="lazy"
>&lt;/p>
&lt;p>I have put it on the Competitor form and filled it with my blog for testing.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-60.png"
loading="lazy"
>&lt;/p>
&lt;p>My trigger is a schedule, defined to run every day at 7am.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-58.png"
loading="lazy"
>&lt;/p>
&lt;p>Then, get all the competitors that have a blog listed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-66.png"
loading="lazy"
>&lt;/p>
&lt;p>Each Insight Card that you create needs to have a user that you will show the insight for - something that flummoxed me for a long while. I would have thought that some cards would be applicable to the whole organisation, or a group of users. You can assign a security group for a card, which I will show later, so would assume it would create an active card for each member of the security group at the least. (I created an idea &lt;a class="link" href="https://experience.dynamics.com/ideas/idea/?ideaid=4835db60-fc8e-ea11-99e5-0003ff689573" target="_blank" rel="noopener"
>here&lt;/a>).&lt;/p>
&lt;p>To combat this, retrieve the Team based on a name (to allow for moving between environments)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-68.png"
loading="lazy"
>&lt;/p>
&lt;p>Put this into a variable for use in the next query without a loop action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-69.png"
loading="lazy"
>&lt;/p>
&lt;p>Then, query the team memberships table. The user id is the field needed so this is easier than drilling down to the user table.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-70.png"
loading="lazy"
>&lt;/p>
&lt;p>Convert this to an array so the flow can quickly use the values when creating the Insight card.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-71.png"
loading="lazy"
>&lt;/p>
&lt;p>For each of the blogs, get the posts that have been created since yesterday. If there is any, loop through the articles then for each user create an Insight card.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-74.png"
loading="lazy"
>&lt;/p>
&lt;p>With this information, we can post our card, firstly find the Sales Insights connector, and choose Create card for assistant V2 (preview)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-62.png"
loading="lazy"
>&lt;/p>
&lt;p>When you add this for the first time, you are prompted to log in and consent for the connector. Lots of permissions needed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-64.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, ready for creating the card. Here, properties from the blog roll and the Competitor are used.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-73.png"
loading="lazy"
>&lt;/p>
&lt;p>There are other properties that could be applicable to your Sales Insight, such as Card behaviour after click (whether to dismiss\snooze\do nothing to the card when the action is clicked), which entity and record to display the card on (remember this is only for core sales entities so far, namely Account, Contact, Lead and Opportunity) and display dates for the Insight.&lt;/p>
&lt;p>The Button type is an interesting selection. I have chosen open URL, but there is also Custom Action (CRM Process), Launch playbook, Open Record and Open URL. I used Open URL for my demo, will describe the others later in the post.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-80.png"
loading="lazy"
>&lt;/p>
&lt;p>The Show for is populated with the following. This gets the current user Id from the teams membership array.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Loop_users&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">userId&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The URL is populated with a link to the article, but as this is an array in itself, take the first one using the code below&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="n">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Loop_new_articles&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">links&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Once this code is run, you should create your first custom insight card, which appears on the dashboard like below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-75.png"
loading="lazy"
>&lt;/p>
&lt;p>Drilling down into the note gives you more detail and allows the action to be taken.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-76.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="button-types">Button Types&lt;/h3>
&lt;p>As described earlier, there are 5 actions available in the button types.&lt;/p>
&lt;h4 id="custom-action-crm-process">Custom Action (CRM Process)&lt;/h4>
&lt;p>Custom Action is a relatively new one. It relies on a pre-created action in the Flow that defines the action. This functionality allows the administrator to configure triggering of a workflow or plugin, as long as it is against an entity.&lt;/p>
&lt;p>For example, here the action is defined to use the Opportunity custom action CloseAllOpportunityQuotes, define which record it needs to run against and also the quote Status.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-87.png"
loading="lazy"
>&lt;/p>
&lt;p>The parameters are defined by the action within the D365 customisation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-89.png"
loading="lazy"
>&lt;/p>
&lt;p>This new action is configured in the Sales Insight card creation step.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-88.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="launch-playbook">Launch Playbook&lt;/h4>
&lt;p>Playbooks are a relatively new feature within the Sales app, which allows a sales manager or administrator to configure a pre-defined set of activities, or a play, to define the perfect way an interaction with a customer should work. You can define them on one or more of the core sales entities.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-82.png?fit=1024%2C489&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>On a Sales Insight card, establish which Playbook template you want to use, define which entity to apply it to and which record.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-83.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="open-record">Open Record&lt;/h4>
&lt;p>This is a simple one, launch a record when the user hits the button. Define the entity and the record Id.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-84.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="open-url">Open URL&lt;/h4>
&lt;p>Another simple one, I used it in the walkthrough above. You need to define the URL to open, here I link back to the first article link in the RSS feed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-85.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="rest">REST&lt;/h4>
&lt;p>This button type allows interaction with an API endpoint. Define the endpoint, which method, though I am not sure what use a GET would be. Also, define the Headers and body. This allows the user to push content or start activity in external systems, logging a case with ServiceNow or creating an activity in your own bespoke system for example. You could also use this to trigger a Flow and create an interaction via that route.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-86.png"
loading="lazy"
>&lt;/p></description></item><item><title>Sales Insights: Basic set up</title><link>https://linked365.blog/2020/05/05/sales-insights-basic-set-up/</link><pubDate>Tue, 05 May 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/05/05/sales-insights-basic-set-up/</guid><description>&lt;img src="https://linked365.blog/images/2020/05-image.jpeg" alt="Featured image of post Sales Insights: Basic set up" />&lt;p>I have been working for quite a while on &lt;a class="link" href="https://dynamics.microsoft.com/en-gb/ai/customer-insights/" target="_blank" rel="noopener"
>Customer Insights&lt;/a>, running workshops and generally getting to know it, but I realised that there is a multitude of products in the Insights suite, Customer Insights, Customer Service Insights, Product Insights, Marketing Insights and Sales Insights. These tools each have their own niche, and I don&amp;rsquo;t know them at all well. So I thought I would educate myself and hopefully someone else by walking through configuring each one and writing down my experiences.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image.jpeg"
loading="lazy"
alt="Microsoft Dynamics 365 Sales Insights - YouTube"
>&lt;/p>
&lt;h2 id="the-business-case">The Business Case&lt;/h2>
&lt;p>Dynamics 365 Sales Insights to use its full name is designed to help your sales managers improve their team&amp;rsquo;s performance. It does this by continuously analysing the interactions a salesperson has with a customer, whether in D365 Sales or Exchange. Each business relationship is evaluated to understand the activities that are completed and how previous interactions have affected sales.&lt;/p>
&lt;p>Do you know how often a salesperson contacts a potential lead? Do they always use canned responses, or is there a form of personality on the interaction? Have you provided your sales team with actionable insights about their opportunities?&lt;/p>
&lt;p>Dynamics 365 Sales Insights has a selection of Free and Advanced features which improve the view of the customer, enabling rich customer experiences in the interactions with your sales team. It uses AI modelling to constantly monitor these interactions and provide insights to your salespeople at the appropriate time, increase lead closure and customer satisfaction.&lt;/p>
&lt;h2 id="free-vs-advanced">Free vs Advanced&lt;/h2>
&lt;p>As already described, there are several free tools to start your journey, which are part of the standard Dynamics 365 Sales offering, namely Assistant (was Relationship Assistant), Auto Capture and email engagement. This first part of the series will walk through configuring the free features.&lt;/p>
&lt;p>Advanced features is a £37.70 per month per user add-on, which is a hefty cost, but with it, you get the full suite of products - Assitant with Studio, Relationship Analytics, Predictive lead and opportunity scoring, Notes analysis, Talking points, Who knows whom, Sales accelerator, Assistant for teams and Conversation Intelligence. This is a lot of functionality. Over the next few posts, I will try and educate myself and step through the experience.&lt;/p>
&lt;h2 id="configuring-sales-insights-free-features">Configuring Sales Insights Free features&lt;/h2>
&lt;p>I started with a brand new trial, again, the best way to do this is to follow along with &lt;a class="link" href="https://twitter.com/TATTOOEDCRMGUY" target="_blank" rel="noopener"
>Chris Huntingford&lt;/a> &lt;a class="link" href="https://www.youtube.com/watch?v=lfGtjcxeKj4" target="_blank" rel="noopener"
>here&lt;/a>. I chose all apps, as usual, then launched the standard Sales Hub. Down the bottom right, is a new area Sales Insights Settings.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-SI-1.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="assistant-configuration">Assistant Configuration&lt;/h2>
&lt;p>The first free feature is Assistant. Clicking on the Manage link takes us to the Assistant Studio to manage the cards that are available to the end-user.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image.png?fit=1024%2C472&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>You are pretty limited to what you can do on this screen, as it is the Free version. All you can do is enable/disable specific cards &amp;amp; make them a high priority. Each card description is vague, but there is a reference from Microsoft &lt;a class="link" href="https://docs.microsoft.com/en-gb/dynamics365/ai/sales/action-cards-reference" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>For instance, I have enabled Recent Meeting and Recent Meeting (Exchange). I have then added a meeting both within D365 and within Outlook for Veronica Quek. When she opens her sales dashboard, she gets this view.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-2.png?fit=1024%2C374&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>This is different than the view if you have not got the 2020 Wave 1 functionality enabled.&lt;/p>
&lt;p>For the Reminder, as it is just passed, I get an option to add some notes or open the appointment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Also, clicking on the Assistant button top right gives a drop-down for the activities I have set up.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-SI-2.gif"
loading="lazy"
>&lt;/p>
&lt;p>You will notice that the user has the option to tell the AI whether the alert is useful or not, delay or cancel a notification. The valuable data is available to the administrator (and Microsoft) appearing alongside the detail of the card in the admin section.&lt;/p>
&lt;p>Some cards have options for the administrator to set, such as the Close date coming soon card. This allows an admin to specify how many days before a close date will the owner is notified via a card on the assistant.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>This pops up in the assistant like below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>All these action cards are great to bring outstanding tasks or stuff to the attention of your salespeople. Some of them will be reliant on having a full license.&lt;/p>
&lt;h2 id="auto-capture-free">Auto capture (free)&lt;/h2>
&lt;p>The next free component of Sales Insights is Auto Capture. To enable this, you have to agree to the Terms of service, which will enable Auto capture.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on Manage opens the Auto Capture configuration.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-11.png?fit=1024%2C296&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>You can see that the Premium is now tantalising close, but let&amp;rsquo;s limit our selves to the free version. This requires Exchange Online sync set up and mailboxes configured. Plenty of articles out there stepping you through that. The insights from this don&amp;rsquo;t seem to come through straight away, I set up on a Friday and did not see any insights, by the Monday, it was all visible. Maybe that is just a glitch in the system, can not see any reference to this.&lt;/p>
&lt;p>I sent 2 emails to my demo account, from an email address already belonging to a contact in D365.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>These are emails I would expect a salesperson to action, the contact is explicitly asking for something related to a possible sale. In Sales Insights dashboard, there is a new notification.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>If I click on the first part, it opens a preview of the email where you can open the email direct in Outlook online.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>On the contact record you see the insights again and also the email that is untracked is highlighted. In the Timeline, the highlighted button allows you to track the email straight away without returning to Outlook.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-15.png?fit=1024%2C346&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>What cards appear depend on the insight cards you enable on the Assistant studio, discussed earlier. Anything that has a mention on your inbox is reliant on the auto-capture functionality being configured.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-16.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="email-engagement-free">Email Engagement (Free)&lt;/h2>
&lt;p>The final &amp;ldquo;free&amp;rdquo; Sales Insight is Email Engagement. Check the Microsoft page on it &lt;a class="link" href="https://docs.microsoft.com/en-gb/dynamics365/ai/sales/email-engagement" target="_blank" rel="noopener"
>here&lt;/a> for full details. This tool allows you to be notified when the recipient opens an email, tr&lt;/p>
&lt;p>Firstly, we need to grant permission by selecting the grant permission link in the Sales Insight Admin.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>This brings up the usual Permissions Requested approval box.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>Once accepted, you should be presented with this page.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, back in the Sales Insights configuration page, the Email Engagement (free) has changed to a Set up link.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on Set up presents you with a page where you enable the functionality.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>If you want to track attachment opening etc. you also need to configure OneDrive integration for your environment. In effect, any attachments are stored in OneDrive, and a link to that is sent to the user rather than the actual file. This allows the logging of attachment interactions. Navigate to &lt;a class="link" href="https://admin.powerplatform.com/" target="_blank" rel="noopener"
>admin.powerplatform.com&lt;/a>, open your environment and Settings. Click on Integration / Document Management Settings, which will open this page.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-25.png?fit=1024%2C314&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>To enable OneDrive, you need SharePoint enabled, so click on Enable Server-Based SharePoint Integration. Walkthrough the SharePoint Integration dialog, choosing a site to host your D365 files. Then click Enable OneDrive for Business back in the Document Management Settings page.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>When I did this, I came across the issue that I needed a default SharePoint Site, but to set the default you need to change a setting which is not on the form. Workaround &lt;a class="link" href="https://community.dynamics.com/crm/f/microsoft-dynamics-crm-forum/247524/how-to-set-sharepoint-site-as-default-yes-in-dynamics-365/1029478" target="_blank" rel="noopener"
>here&lt;/a>. Once that is done, you get a new part of the Document Management Settings.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-27.png?fit=1024%2C406&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>There is also a bit they don&amp;rsquo;t tell you about in the config, namely to enable Email as a document storage entity. If you go into SharePoint Document Locations under the Document Management Settings, you will be presented with this screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>Make sure Email is ticked (along with the others), enter a path to the SharePoint and select Next. I decided to link it back to the Account so selected that as a based on entity then hit Next again. After a little churning, this is the result.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-33.png"
loading="lazy"
>&lt;/p>
&lt;p>When you add an email now, you get a new tab (with the Enhanced Email Wave 1 enabled).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>In the old way, you get a section available on the right&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>There are a few additional features enabled with this, firstly Recipient Activity&lt;/p>
&lt;h3 id="recipient-activity">Recipient Activity&lt;/h3>
&lt;p>To record email activity, a small 1-pixel gif is placed in the email as you send it. This will, when the email is read, notify you that the email has been read. You can toggle this on or off per email using the Do Not Follow functionality in the Email Engagement section. There is also an override per Contact in the contact preferences section.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-47.png"
loading="lazy"
>&lt;/p>
&lt;p>This is a snapshot of the HTML email that I sent, you can see the embedded gif which is a link to the Microsoft tracking site.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-28.png?fit=1024%2C168&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>In D365, a notification appears as a new Insight card against the contact and in the dashboard view. It also appears in the timeline for the contact that was sent the mail. The stats and alerts are not fool-proof, each email seems to be opened multiple times, which is not my interactions. I assume that this is due to various services such as spam filters etc. checking the links, but it does give you confidence that there has been an interaction of some sort.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-29.png?fit=1024%2C364&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h3 id="attachment-activity">Attachment Activity&lt;/h3>
&lt;p>In addition to opening the email, you can also track them opening any attachments you send too. Firstly, you need to save the email before you can add attachments. Then add an attachment. You should get a new Follow button once you have added the attachment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>Selecting the Follow button tags the attachment for following and it appear in the grid of attachments like below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, when the recipient receives the attachment, it is a link to the OneDrive file like below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-36.png"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on the link drives the recipient to a OneDrive page where they can download the file. Please note, that these files are not secured, you don&amp;rsquo;t need to log on to get at these files, only the link. It would be pretty random that you could determine the link, but it is just a warning. Normal sharing would be preferred for contracts etc. but it is great for marketing/sales documents.&lt;/p>
&lt;p>&lt;img src="https://i2.wp.com/linked365.blog/wp-content/uploads/2020/05/image-38.png?fit=1024%2C485&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>In D365, once the file is opened, you see a Sales Insights notification and if you open the email in D365, activity gets logged like below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-39.png"
loading="lazy"
>&lt;/p>
&lt;p>The attachments are stored on the users OneDrive, which you can see below for Veronica&amp;rsquo;s OneDrive.&lt;/p>
&lt;p>&lt;img src="https://i0.wp.com/linked365.blog/wp-content/uploads/2020/05/SI-3.gif?fit=1024%2C628&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h3 id="link-activity">Link Activity&lt;/h3>
&lt;p>Another feature in Email Engagement is link tracking. Any link you put into your email gets replaced with a link back to the D365 server. Each time the user clicks on the link, it is logged in D365, before the recipient is redirected to the original URL.&lt;/p>
&lt;p>For instance, if I link to my blog in an email&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-40.png"
loading="lazy"
>&lt;/p>
&lt;p>The recipient receives the email like below, but if you hover over the link it shows the full link that the user gets.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-41.png"
loading="lazy"
>&lt;/p>
&lt;p>If I click on the link, the user gets directed to my awesome blog. More importantly, the link tracking appears in D365.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-42.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="delayed-delivery">Delayed Delivery&lt;/h3>
&lt;p>When you send an email, with Email Engagement on, you can delay it. Click on Delay Send option presents you with this screen&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-43.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit send this time does nothing, with D365 in the background sending the email out when the time arrives. A nice little feature to pre-plan engagements.&lt;/p>
&lt;h3 id="follow-up-reminder">Follow-up Reminder&lt;/h3>
&lt;p>Another nice little quality of life feature is the ability to add a follow-up reminder. This can be done at any time after the email has been sent.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-44.png"
loading="lazy"
>&lt;/p>
&lt;p>You can choose the condition and the time frame as well as a comment. This appears as an Assistant card once the date has reached.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/05-image-45.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="email-templates">Email Templates&lt;/h3>
&lt;p>Another feature enhanced with Email Engagement is templates. You can select templates by selecting Insert Template in the Email form. As you build up tracking on these emails and they are interacted with, statistics are built upon the suitability of each template - which ones ended up with an email that was opened for example.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/05/image-46.png?fit=1024%2C404&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;h2 id="next-time">Next time&lt;/h2>
&lt;p>As you can see this set of tools, including in the subscription cost of a Sales license is pretty cool. In my next post I will delve deeper into the premium features.&lt;/p></description></item><item><title>MB-400: Power Apps + Dynamics 365 Developer Associate Exam</title><link>https://linked365.blog/2020/04/18/mb-400-power-apps--dynamics-365-developer-associate-exam/</link><pubDate>Sat, 18 Apr 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/04/18/mb-400-power-apps--dynamics-365-developer-associate-exam/</guid><description>&lt;img src="https://linked365.blog/images/2020/04-04-CERT-Associate-Dynamics365-Power-Apps-Developer-e1587136202888.png" alt="Featured image of post MB-400: Power Apps + Dynamics 365 Developer Associate Exam" />&lt;p>This week, I am on holiday, meant to be in Egypt watching the kids swim in the Red Sea, drinking as much beer as I can &amp;amp; getting pink. As this didn&amp;rsquo;t happen, I decided to fit in an exam instead. Why not get another qualification instead?&lt;/p>
&lt;p>MB-400, the new developer exam, was the one I was dreading, more so than &lt;a class="link" href="https://linked365.blog/2020/04/04/mb-600-microsoft-power-apps-dynamics-365-solution-architect-beta/" target="_blank" rel="noopener"
>MB-600&lt;/a> I did a couple of weeks back, as my hands-on development has really ground to a halt in the last couple of years, as I move towards the design / architecting side of Power Apps. I know the capabilities, but the syntax was something I had to revise, a lot.&lt;/p>
&lt;p>My mind maps for this one are listed with the others &lt;a class="link" href="https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>This exam, I owe a lot to &lt;a class="link" href="https://twitter.com/joejgriffin" target="_blank" rel="noopener"
>Joe Griffin&lt;/a>, the CRM Chap, his blog is here &lt;a class="link" href="https://crmchap.co.uk/" target="_blank" rel="noopener"
>https://crmchap.co.uk/&lt;/a>. He is writing a whole series of articles on this and it has just been announced, along with the legend &lt;a class="link" href="https://twitter.com/juliandynamics" target="_blank" rel="noopener"
>Julian Sharp&lt;/a> that he is creating a &lt;a class="link" href="https://t.co/JLIIa6m09Z" target="_blank" rel="noopener"
>series of webinars&lt;/a> to help people with the exam. Joe&amp;rsquo;s articles were a thorough revision set for me and opened some long-forgotten parts of the abundance which is the D365 dev landscape.&lt;/p>
&lt;p>Also, &lt;a class="link" href="https://twitter.com/DynamicsNinja" target="_blank" rel="noopener"
>Ivan Ficko&lt;/a>, his blog &lt;a class="link" href="https://dynamicsninja.blog/" target="_blank" rel="noopener"
>https://dynamicsninja.blog/&lt;/a> was a great help when I was down a the dirty end, working out how to set up &lt;a class="link" href="https://dynamicsninja.blog/2019/05/22/d365-webhooks-part-1/" target="_blank" rel="noopener"
>Webhooks&lt;/a>.&lt;/p>
&lt;p>Finally, the learning paths on Microsoft are pretty good, especially for Power Apps. The Exam has several listed &lt;a class="link" href="https://docs.microsoft.com/en-us/learn/certifications/exams/mb-400" target="_blank" rel="noopener"
>here&lt;/a> but I would advise working through all the Power Apps ones you can find, and practice.&lt;/p>
&lt;p>This is one of the exams that you need experience, get out your trial environment, visual studio code &amp;amp; create a Javascript, PCF control and all the other parts.&lt;/p>
&lt;h2 id="exam-content">Exam Content&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-EXAM-Associate-MB-400.png"
loading="lazy"
>&lt;/p>
&lt;p>There was a few surprises in the exam, most notably, the inclusion of F &amp;amp; O questions. You need to have a basic understanding of their capabilities.&lt;/p>
&lt;p>PowerApps formulas were also in there and stumped me. Casting values was something I had not come across, as more of an old school Customer Engagement guy.&lt;/p>
&lt;p>Ribbon Workbench also had a couple of questions and stretched my knowledge somewhat. There were the now usual groups of questions related to the scenario as well, all digging into aspects across the whole dev ecosystem.&lt;/p>
&lt;p>Security, solutions, model driven, canvas, client scripting, PCF, Flow, BPFs all had at least one question as well.&lt;/p>
&lt;p>Overall, it was tough. Tested my knowledge anyway, as a lay developer.&lt;/p></description></item><item><title>Changing working habits - WFH isn't easy</title><link>https://linked365.blog/2020/04/09/changing-working-habits-wfh-isnt-easy/</link><pubDate>Thu, 09 Apr 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/04/09/changing-working-habits-wfh-isnt-easy/</guid><description>&lt;img src="https://linked365.blog/images/2020/04-04-home-office-4994104_1920-e1586111871325.jpg" alt="Featured image of post Changing working habits - WFH isn't easy" />&lt;p>As a departure from my usual posts, I wanted to share my thoughts on coping during the biggest change to our professional life: COVID-19. Social distancing rules have meant that a lot more of us are having less social contact with our colleagues, family and friends. This leads to stress and anxiety, exhibited in numerous ways, and if not tackled, depression.&lt;/p>
&lt;p>Further, our professional interactions are very different. Those workshops to thrash out issues are no longer. Getting the time with key stakeholders who are fire-fighting the effects on the business of COVID-19 rules is hard. We have to learn to work in different ways, particularly as I think this will be a marathon. Ensuring you are approaching these trying times with the correct mental attitude is key to your success.&lt;/p>
&lt;p>I admit, in a previous life, I had clinically diagnosed depression. My life was routine: Commute, Work, Commute, Dinner, TV. This led to thoughts in my mind around how I was perceived at work and at home. Nothing I did was acceptable, nothing anyone else did was good enough. I struggled to think about anyone apart from myself. My family were hit hardest, with mood swings, erratic behaviour and shouting. For that, I apologise to my family, friends and colleagues.&lt;/p>
&lt;p>I want to just highlight a few points that are helping me rationalise my health these days and understand how we can help others with our interactions. In my view, the way to evaluate a community or group is to look at how they treat and support the weakest in their group. At this time, we should take this to mean how we support everyone in these unusual times.&lt;/p>
&lt;h2 id="your-routine-has-changed---keep-the-separation">Your routine has changed - Keep the separation&lt;/h2>
&lt;p>When we all used to commute to work, we had an hour in our own thoughts. We had a separation from work and home. This was time for our brains to consider the day and switch between the 2 main characters in our life: Work and Home.&lt;/p>
&lt;p>As this changes to walking to your kitchen table, that time disappears. Your two personas can merge, but more importantly, your brain doesn&amp;rsquo;t have time to digest.&lt;/p>
&lt;p>Give yourself time to differentiate between home and work. Take 20 minutes, read a book, go for a walk or listen to Spotify album at the end of your day to separate the two.&lt;/p>
&lt;h2 id="socialise-at-work">Socialise at work&lt;/h2>
&lt;p>When I am in the office, I get interrupted at least twice an hour, people asking questions or overhearing conversations. Mostly work-related and is the reason why project teams work best when they are in the same location. Not only do you have more understanding of what is happening in your project that is not part of your focus area, but you also get to know your colleagues, understand they are having a bad day or that they have a hangover (you know who you are). This time breaks the day, disrupts your flow and sometimes clarifies the picture.&lt;/p>
&lt;p>Try starting each call with a chat, rather than getting straight to business. There are always latecomers to a call, so use this time to gossip, talk about the latest Netflix docudrama or check if someone has enough toilet roll.&lt;/p>
&lt;p>Also, force it. We have had great success in taking the last hour of the workday twice a week and forcing a chat. No agenda, no pressure to join, but a check-in point for everyone. This needs to have management buy-in, but not led by management. We try and not talk shop, but it is inevitable. Those banter moments you had in the office should surface here too - comedy is the best way to elevate the mood.&lt;/p>
&lt;h2 id="socialise-at-home">Socialise at home&lt;/h2>
&lt;p>My involvement in the community over the last year has meant that I was going out more, interacting more and chatting more than ever before. This shouldn&amp;rsquo;t stop just because we are not allowed to go to a pub or meet for a user group.&lt;/p>
&lt;p>&lt;a class="link" href="https://twitter.com/TATTOOEDCRMGUY" target="_blank" rel="noopener"
>Chris Huntingford&lt;/a> has made this an art form by creating the &lt;a class="link" href="https://twitter.com/BespokeBadger" target="_blank" rel="noopener"
>Bespoke Badger&lt;/a>, a regular pub night which he hosts where anarchy ensues. This can be a little wild and usually includes alcohol. As you can see, the great and the good of our community are in full force.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/04/70730e5b-677f-4a67-b783-40e93d889949.jpg?fit=1024%2C765&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>I realise this isnt for everyone, so there are other things happening, including &lt;a class="link" href="https://daveburrell.co.uk/virtual-lunch/" target="_blank" rel="noopener"
>lunch time&lt;/a> hosted by &lt;a class="link" href="https://twitter.com/DaveBurrell" target="_blank" rel="noopener"
>Dave Burrell&lt;/a>.&lt;/p>
&lt;p>The point is, arrange some interaction with your friends. Poker nights, book (wine) club, curry night, they all can still happen. Zoom is free, up to 40 minutes, but redialing in straight away works just fine. Don&amp;rsquo;t forget your family and not just the ones you talk to daily but remember Great Aunt Maude. Calling her will make her day! Do realise that you may take 30 of the 40 minutes getting Aunt Maude up and running though.&lt;/p>
&lt;h2 id="dont-expect-the-same-pace">Don&amp;rsquo;t expect the same pace&lt;/h2>
&lt;p>I am lucky, I have two teenage boys. On a typical day, they don&amp;rsquo;t require my attention for long, if at all. To be honest, as long as the fridge is full and the WiFi works, they are good for weeks.&lt;/p>
&lt;p>Other members of my team will have young children, juggling keeping them entertained with holding down their role. Be lenient with them, expect interruptions, expect those meetings to be cancelled last minute.&lt;/p>
&lt;iframe src="https://giphy.com/embed/ZdU3bTTc1WWStZM5lm" width="480" height="340" frameborder="0" class="giphy-embed" allowfullscreen>&lt;/iframe>
&lt;p>&lt;a class="link" href="https://giphy.com/gifs/moodman-working-from-home-wfh-ZdU3bTTc1WWStZM5lm" target="_blank" rel="noopener"
>via GIPHY&lt;/a>&lt;/p>
&lt;p>Also, a lot of businesses, if not all, are under such different pressures since the start of social distancing: keeping helpdesks open with little staff, creating products suitable for a different way to do business, working with their other partners to ensure their service is still available. Gone are the days when you can thrash out a solution by bringing in stakeholders across the country for a 1/2 day workshop.&lt;/p>
&lt;p>Time with your business owners will be sacrosanct. Ensure your meetings are essential and have a list of decisions to be made. We have to adapt as consultants and help our customers through these difficult times. This will generally be doing a lot more thinking for them, creating options rather than expecting them to come up with a solution.&lt;/p>
&lt;h2 id="exercise">Exercise&lt;/h2>
&lt;p>I know, I am not the perfect role-model for fitness, but getting out in the world is a great way of clearing your head. That call you are on, do you need to see a screen? Could you walk while you listen in? Concentration is key on a call, listening and walking is easy.&lt;/p>
&lt;p>What about that decorating you have been putting off? You may struggle to get wallpaper but preparing for a day when you can is a great way of getting away from work. Getting out in the garden, preparing for the future summer with friends and family really gives hope for a time when we can laugh at this situation.&lt;/p></description></item><item><title>3 Minute Features: Episode 10: Keys</title><link>https://linked365.blog/2020/04/07/3-minute-features-episode-10-keys/</link><pubDate>Tue, 07 Apr 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/04/07/3-minute-features-episode-10-keys/</guid><description>&lt;img src="https://linked365.blog/images/2020/04-04-image.png" alt="Featured image of post 3 Minute Features: Episode 10: Keys" />&lt;p>When I started this &lt;a class="link" href="https://linked365.blog/2020/01/09/3-minute-features-episode-1-entities/" target="_blank" rel="noopener"
>series&lt;/a>, my intention was to create a series of videos to guide a user in the fundamentals of the Power Platform, starting with Entities and working my way through each of the parts.&lt;/p>
&lt;p>The trouble with video is that it takes a long while to edit and prepare. Each video was taking 4-6 hours to produce. This, I am well aware, is most likely down to my lack of skill, but it was definitely not a great use of my time. The time I dedicated to this was cutting into the time I spent with my family and other side projects.&lt;/p>
&lt;p>So, to keep the series going, I am going to switch to writing the articles, but still keeping to the remit of 3 minutes. The average person reads 200-250 words a minute, so my limit is 750 words. Not for the intro, but for the article itself. I hope the articles are informative and enough to get you going on the topic. Let me know any feedback.&lt;/p>
&lt;h2 id="episode-10-keys">Episode 10: Keys&lt;/h2>
&lt;p>Keys are used to denote unique fields or sets of fields for an entity. Each entity will have one primary key, the GUID of the record and a developer can&lt;br>
add up to 5 secondary keys.&lt;/p>
&lt;p>Typical usage is to denote a key from another system - if you are integrating and the source has a unique identifier, it makes sense to create this as a key in your entity.&lt;/p>
&lt;p>Keys are unique. If someone tries to create a record, through the interface or via the API with the same unique value in a key as an existing record, it&lt;br>
will fail and the user will be notified. This is the only way you can fully ensure duplicate data is not created. De-duplication rules check for matches,&lt;br>
but the user can easily bypass this.&lt;/p>
&lt;p>There are only a few fields that can be part of keys&lt;/p>
&lt;ul>
&lt;li>Decimal Number&lt;/li>
&lt;li>Whole Number&lt;/li>
&lt;li>Strings&lt;/li>
&lt;li>Date\Times&lt;/li>
&lt;li>Lookup&lt;/li>
&lt;li>Picklist&lt;/li>
&lt;/ul>
&lt;p>Also, when the key is populated, any fields with certain characters in the data it (&amp;lt;,&amp;gt;,*,%,&amp;amp;,:,/,\) you will struggle with upserts and patches. This is fine if you are doing uniqueness checking only, but not if you are using this for an integration. Keys are limited to 16 fields each as well as 900 bytes per key (the fields concatenated together, not the data).&lt;/p>
&lt;h2 id="creating-keys">Creating Keys&lt;/h2>
&lt;p>So let&amp;rsquo;s create a key for our new entity. In the Keys tab, select Add Key,&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-keys-1.100-1.gif"
loading="lazy"
>&lt;/p>
&lt;p>You are presented with a selection of the fields that you can add to your key, you must choose one. Also, give it a name. Hit Save entity. The key will be added to the database in the back end. In the maker experience, you can not tell the progress of this step, but you must check this progress, as without the process completing, your key is redundant.&lt;/p>
&lt;p>Hit the Classic Interface button, drill down to keys and you can see the status of the job, drilling down again to see the detail.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-keys-2.gif"
loading="lazy"
>&lt;/p>
&lt;p>Depending on how much data you have, depends on how long this process takes. As you move up the systems, from Dev to Test and Production, be aware of this. The time it takes to import a solution and publish it will be affected. Millions of records will take time.&lt;/p>
&lt;p>My key doesn&amp;rsquo;t work, the system process failed. This is because the field I used, Name, has duplicates in it. This means that the key is not in position to be used &amp;amp; duplicate detection will not work.&lt;/p>
&lt;h2 id="duplicate-detection">Duplicate Detection&lt;/h2>
&lt;p>In the interface, if I try to create a thing with the same name as already exists, I will get an error and be stopped from progressing. This names the key and prompts the user where to look. Ensure the name of the key drives the user to the right field to change.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-keys-3.gif"
loading="lazy"
>&lt;/p>
&lt;p>Combining fields to form a key is great here. You could prevent leads being created which have the same first and last name as well as postcode or company name for example.&lt;/p>
&lt;p>So simple, useful &amp;amp; essential to build up your requirements.&lt;/p></description></item><item><title>MB-600 : Microsoft Power Apps + Dynamics 365 Solution Architect (beta)</title><link>https://linked365.blog/2020/04/04/mb-600-microsoft-power-apps--dynamics-365-solution-architect-beta/</link><pubDate>Sat, 04 Apr 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/04/04/mb-600-microsoft-power-apps--dynamics-365-solution-architect-beta/</guid><description>&lt;img src="https://linked365.blog/images/2020/04-04-ezgif-6-fc5292b96c95-e1585908984789.png" alt="Featured image of post MB-600 : Microsoft Power Apps + Dynamics 365 Solution Architect (beta)" />&lt;p>Last week I sat the MB-600 exam, which for any aspiring Solution Architect in our world is the pinnacle qualification. Still in beta, so not sure how I got on, but thought I would share my thoughts while I still remember.&lt;/p>
&lt;p>As part of my learning, I create mindmaps, it helps me focus my understanding and is quicker for me to review later for last-minute cramming sessions.&lt;/p>
&lt;p>With the rest of the maps I have created, you can see them &lt;a class="link" href="https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>These mind maps were based on the skills outline that is available &lt;a class="link" href="https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RE440oW" target="_blank" rel="noopener"
>here&lt;/a>. Skills outlines with the other exams are a great resource for understanding what is in the exam, this is not the case for MB-600. The outline effectively gives you an understanding of the soft skills required.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-ezgif-6-2d4536ba34de.png"
loading="lazy"
>&lt;/p>
&lt;p>The questions on the exam also covered most applications across the PowerPlatform. As a Solution Architect, you should have a generic view across all the platform and this is taken for granted in this exam. Even outside of the application is tested. Below is my memory of the areas that were covered, not going to be complete, but gives you an idea of the scope.&lt;/p>
&lt;ul>
&lt;li>Power Platform
&lt;ul>
&lt;li>Security&lt;/li>
&lt;li>Field level security&lt;/li>
&lt;li>Business Units&lt;/li>
&lt;li>Controls&lt;/li>
&lt;li>Development
&lt;ul>
&lt;li>How could you complete a simple dev exercise to complete a custom task&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Solutions and patches - This had a couple of questions, so worth understanding&lt;/li>
&lt;li>Data Import tools&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Power Apps
&lt;ul>
&lt;li>User cases&lt;/li>
&lt;li>Usage&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>D365 Customer Service
&lt;ul>
&lt;li>Scenarios on its usage&lt;/li>
&lt;li>What is included OOTB&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>D365 Sales
&lt;ul>
&lt;li>Scenarios for usage&lt;/li>
&lt;li>OOTB functionality&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>Other
&lt;ul>
&lt;li>Marketing&lt;/li>
&lt;li>Gamification (This surprised me the most)&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul></description></item><item><title>Quick Approvals - Send with Options</title><link>https://linked365.blog/2020/04/02/quick-approvals-send-with-options/</link><pubDate>Thu, 02 Apr 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/04/02/quick-approvals-send-with-options/</guid><description>&lt;img src="https://linked365.blog/images/2020/04-04-image-38.png" alt="Featured image of post Quick Approvals - Send with Options" />&lt;p>As I digitally transform the club I am involved with, &lt;a class="link" href="http://stardiving.org" target="_blank" rel="noopener"
>stardiving.org&lt;/a> I come across ways in Power Automate that are pretty useful. I have previously talked about &lt;a class="link" href="https://linked365.blog/adaptive-cards-improved-approvals-part-1/" target="_blank" rel="noopener"
>Adaptive Cards&lt;/a> for approvals and this works great, but only for internal use. Same with Approvals, they are perfect for what I wanted to achieve, but limited to internal users.&lt;/p>
&lt;p>Send Email with options is a great way of getting approval or an answer to a specific question for any user, external or internal. I use this action, along with a Form &amp;amp; some parallel branching to move our little club another step towards total digitisation&lt;/p>
&lt;h2 id="the-scenario">The Scenario&lt;/h2>
&lt;p>My club, for a new member, requires entry of their personal details, medical information and contact details, and the way we store this and allow for access necessitates that we use online, secure storage. With my background, it is clear we should use SharePoint lists to store this data (yes, I know SharePoint is not a data repository, but it works great when you do not have a lot of data and limited monetary resources).&lt;/p>
&lt;p>Forms is also a great tool to publish these questions out to our members or their parent or guardian. It gives a great look and feel, is pretty easy to set up and, again, is free in the licensing Microsoft generously gives the club due to its charitable status. The problem with Forms is that you can not collate signatures. You can&amp;rsquo;t do this via Forms Pro either, there are several really good business reasons for this, especially as Adobe or Docusign make a whole business out of this.&lt;/p>
&lt;p>For my scenario, we had to get agreement to various parts of the entry, particularly around the consent to store their data and use it run the club. This would be easy in a paper form, just ask for a signature, but to bring this electronically, I needed to create a way of ensuring that they have agreed and capture that agreement.&lt;/p>
&lt;p>Power Automate has a great approvals engine, but you can not send an approval outside of your organisation (you can if the user is a guest, but I don&amp;rsquo;t want to add all our parents as guests). So this is out.&lt;/p>
&lt;p>&lt;a class="link" href="https://linked365.blog/adaptive-cards-improved-approvals-part-1/" target="_blank" rel="noopener"
>Adaptive Cards&lt;/a> are also great, but this is restricted to internal users as well, and you are reliant on the receiver of the card having the appropriately supported viewer, which is only Microsoft applications currently.&lt;/p>
&lt;p>Power Automate also has a &amp;ldquo;Send email with Options&amp;rdquo; which allows a much simpler approval process, but you can send it to anyone. Perfect for my scenario, free and any email address!&lt;/p>
&lt;h2 id="the-solution">The solution&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-38.png"
loading="lazy"
>&lt;/p>
&lt;ul>
&lt;li>Forms data entry&lt;/li>
&lt;li>Copy information to SharePoint list&lt;/li>
&lt;li>Ask for approval via email
&lt;ul>
&lt;li>Approve email given&lt;/li>
&lt;li>Have a record that they acknowledged.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>If approval is not given, notify an administrator&lt;/li>
&lt;/ul>
&lt;h2 id="form">Form&lt;/h2>
&lt;p>&lt;a class="link" href="https://meganvwalker.com/" target="_blank" rel="noopener"
>Megan Walker&lt;/a> is the Forms queen, not going to try and compete with the knowledge she has imparted since Forms came out.&lt;/p>
&lt;p>My form is pretty simple, asks a host of questions on behalf of the diver and the parent. There are a couple of sections, branched depending on whether the user is entering this form as a member or their parent/guardian.&lt;/p>
&lt;p>I ask in the form for them to confirm a couple of key points, by asking for the name of the diver to confirm their agreement. This is obviously not foolproof, but gives enough confirmation, backed up with the email approval that comes as part of the Flow.&lt;/p>
&lt;h2 id="create-sharepoint-item">Create SharePoint Item&lt;/h2>
&lt;p>My trigger is &amp;ldquo;When a New response is submitted&amp;rdquo;. As I have no CDS, this is the only one available to me. I then get the response details, which helps later when you want to copy the details across to SharePoint list.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>Next step is to create the SharePoint list&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>Because we will have different user groups, there are separate questions in the survey which populate the same data fields in the list. This is done with a simple if ( equals (field,&amp;rsquo;&amp;rsquo;), value1, value2) function. The random field names are those linking to the questions, which look prettier when you insert them.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-csharp" data-lang="csharp">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="k">equals&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Get_response_details&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">r11eaea5575824aa8b515f76fd43d1332&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>&lt;span class="err">&amp;#39;&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Get_response_details&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">r6d52d6567ea1425aaf91c6d678c125e8&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">],&lt;/span>&lt;span class="n">body&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Get_response_details&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)?[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">r11eaea5575824aa8b515f76fd43d1332&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="emailing-for-approval">Emailing for approval&lt;/h2>
&lt;p>After the list item is created, I put in a parallel branch. The left branch sends out the email for approval, the right branch waits for a week. If the week is reached, send an email to our administrator to chase the person, as the user who entered the information has not done the confirmation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>On the left parallel branch, I create the email with options&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-32.png"
loading="lazy"
>&lt;/p>
&lt;p>This formatted email converts into the email below, shown in GMail. You can see the formatting that was applied, and the 2 buttons I defined in the action.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/03/image-33.png?fit=1024%2C424&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>Clicking on the Approve or Deny button shows the user this screen, thanking them for their response&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-34.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="waiting-for-approval">Waiting for Approval&lt;/h2>
&lt;p>Back in the Flow, we wait for a response.&lt;/p>
&lt;p>&lt;img src="https://i1.wp.com/linked365.blog/wp-content/uploads/2020/03/image-35.png?fit=1024%2C267&amp;amp;ssl=1"
loading="lazy"
>&lt;/p>
&lt;p>If it is not Approve, then send an email to our administrator, to check what part they don&amp;rsquo;t agree with.&lt;/p>
&lt;p>If it is Approve, update the item to confirm that the member is registered successfully&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-36.png"
loading="lazy"
>&lt;/p>
&lt;p>Either way, cancel the flow. As the other parallel branch is waiting for a week and then responding to our administrator, cut this short by cancelling the flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/04-04-image-37.png"
loading="lazy"
>&lt;/p></description></item><item><title>Incident App (Part 2)</title><link>https://linked365.blog/2020/03/18/incident-app-part-2/</link><pubDate>Wed, 18 Mar 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/03/18/incident-app-part-2/</guid><description>&lt;img src="https://linked365.blog/images/2020/02-image-15.png" alt="Featured image of post Incident App (Part 2)" />&lt;p>In the first part of this series, &lt;a class="link" href="https://linked365.blog/2020/02/23/incident-app-part-1/" target="_blank" rel="noopener"
>here&lt;/a> I established an application I wrote to improve incident management at the club I am proud to chair.&lt;/p>
&lt;h2 id="requirements">Requirements&lt;/h2>
&lt;ul>
&lt;li>Centralised, secure list of incidents - (&lt;a class="link" href="https://linked365.blog/2020/02/23/incident-app-part-1/" target="_blank" rel="noopener"
>Part 1&lt;/a>)&lt;/li>
&lt;li>Ability to add divers to list for trials or competitions (&lt;a class="link" href="https://linked365.blog/2020/02/23/incident-app-part-1/" target="_blank" rel="noopener"
>Part 1&lt;/a>)&lt;/li>
&lt;li>Data entry must be easy and not time-consuming (&lt;a class="link" href="https://linked365.blog/2020/02/23/incident-app-part-1/" target="_blank" rel="noopener"
>Part 1&lt;/a>)&lt;/li>
&lt;li>Weekly notification of all incidents to the welfare officer&lt;/li>
&lt;li>Email to parent or guardian of the diver when an incident is raised&lt;/li>
&lt;li>Escalation to welfare officer and others in the organisation for serious incidents&lt;/li>
&lt;li>Not cost anything&lt;/li>
&lt;/ul>
&lt;p>In this part I will walk you through the flows I used to notify parents and the welfare officer. There is also a requirement to escalate, notify immediately for serious incidents.&lt;/p>
&lt;h2 id="weekly-notification">Weekly Notification&lt;/h2>
&lt;p>To allow our welfare officer to monitor all incidents and any patterns, it was requested that they receive a weekly overview of all incidents raised that week.&lt;/p>
&lt;p>To do this, I created a flow using the recurrence trigger.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-10.png?w=619"
loading="lazy"
>&lt;/p>
&lt;p>Using these options, the flow will trigger at 3 am every Sunday morning.&lt;/p>
&lt;p>I then establish a variable for the email body and go off and retrieve all the items that have been created since last week. The filter query is used here to filter on all incidents that were created after 7 days ago, a simple addDays function used to get to the date 7 days ago&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-12.png?w=553"
loading="lazy"
>&lt;/p>
&lt;p>Next, just check to see if there are any incidents this week by checking the length of the returned list.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-13.png?w=552"
loading="lazy"
>&lt;/p>
&lt;p>If this is greater than 0, then incidents have been created, go on to create an email, if not, just do nothing.&lt;/p>
&lt;p>The next part is where I had to be a little bit clever, as the standard thing you would do did not give me enough flexibility. You could pass this list into a Create HTML function, but this put the data in a column format, where I wanted to display as a list going down the page, more of a normal email format.&lt;/p>
&lt;p>Instead, I built up an email, formatting the content as I went. Starting with an apply to each, taking the Get Items from SharePoint command. The first action I used repeatedly in the creation of the email, which is stripping the html content from html aware fields in the columns of the SharePoint. Leaving these in resulted in a lot of mangled emails.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-14.png?w=576"
loading="lazy"
>&lt;/p>
&lt;p>I then append to the Email Body string I created earlier a formatted HTML content.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-15.png?w=545"
loading="lazy"
>&lt;/p>
&lt;p>The incident date is a simple formatDateTime function useage&lt;/p>
&lt;p>formatDateTime(items(&amp;lsquo;Apply_to_each&amp;rsquo;)?[&amp;lsquo;IncidentDate&amp;rsquo;],&amp;lsquo;dd/MM/yyyy&amp;rsquo;)&lt;/p>
&lt;p>The next step is because Contacted field is a multi-choice option set. Again, I loop through the contents of the Contacted? field and append to the email body variable.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-16.png?w=571"
loading="lazy"
>&lt;/p>
&lt;p>The final parts of the loop finish of the content for each incident&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-17.png?w=554"
loading="lazy"
>&lt;/p>
&lt;p>Finally, send out the email. Subject details how many incidents in the week with a count from the SharePoint items returned.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-18.png?w=566"
loading="lazy"
>&lt;/p>
&lt;h2 id="email-the-parent--guardian">Email the Parent / Guardian&lt;/h2>
&lt;p>The next requirement was to notify the diver&amp;rsquo;s parent or guardian. For years, we had relied on slips of paper, which again is a GPDR nightmare. Using email was a sure fire way to ensure we have done our duty. This only applied for minor incidents, parents will certainly be involved a lot quicker for anything serious.&lt;/p>
&lt;p>Firstly, trigger when a new item is created in the SharePoint list&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-19.png?w=549"
loading="lazy"
>&lt;/p>
&lt;p>Next, get the diver that is indicated in the list, diver id being the linking record between the incident list &amp;amp; members&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-20.png?w=559"
loading="lazy"
>&lt;/p>
&lt;p>As this SharePoint get items call may return more than one item, we have to place in a Apply to Each&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-21.png?w=317"
loading="lazy"
>&lt;/p>
&lt;p>Check to see if the diver has an email address (if new divers come on board, this might not be the case until we have their full details).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-22.png?w=768"
loading="lazy"
>&lt;/p>
&lt;p>If no email, stop the action, otherwise send an email to the email to notify the parent.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-23.png?w=547"
loading="lazy"
>&lt;/p>
&lt;h2 id="escalate-an-incident">Escalate an Incident&lt;/h2>
&lt;p>Most incidents, thankfully, require little follow up or after care. But, there are occasions that require our parent association to be notified along with insurance companies. We also have an internal follow up process for such incidents by our welfare officer.&lt;/p>
&lt;p>Rather than create a new flow, after the flow above, I continue. Does the Contacted multiple select option set contain Ambulance or Police, both mean an immediate escalation. This is done by looping through the options selected and updating a variable if one of them matches either of the 2 conditions.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-26.png?w=778"
loading="lazy"
>&lt;/p>
&lt;p>Further, there is a severe boolean on the form, so if that is triggered, also update the variable to true.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-27.png?w=666"
loading="lazy"
>&lt;/p>
&lt;p>Finally, if Severe has been set, send an email&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-28.png?w=696"
loading="lazy"
>&lt;/p></description></item><item><title>Alexa, Field Service and Me (Part 5) - Using Azure Service Bus</title><link>https://linked365.blog/2020/03/13/alexa-field-service-and-me-part-5-using-azure-service-bus/</link><pubDate>Fri, 13 Mar 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/03/13/alexa-field-service-and-me-part-5-using-azure-service-bus/</guid><description>&lt;img src="https://linked365.blog/images/2020/03-image-5.png" alt="Featured image of post Alexa, Field Service and Me (Part 5) - Using Azure Service Bus" />&lt;p>In my previous &lt;a class="link" href="https://linked365.blog/2020/03/09/alexa-field-service-and-me-part-4-using-azure-funtions/" target="_blank" rel="noopener"
>post&lt;/a> I walked through swapping out Power Automate with Azure Functions for responding to Alexa in our &lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" target="_blank" rel="noopener"
>Field Service&lt;/a> scenario.&lt;/p>
&lt;p>This post is about finalising the code by using Service Bus function to create the Work Order.&lt;/p>
&lt;p>In the Power Automate version I used a child flow call to allow the response to happen quickly, without waiting for the numerous calls to establish data then creating the record. This is standard, good practice to improve the response time.&lt;/p>
&lt;h2 id="create-the-queue">Create the Queue&lt;/h2>
&lt;p>Firstly, over to portal.azure.com &amp;amp; create a service bus. The service bus is the messaging underpinning for our queue.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-azurefunction-3.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Next create a queue within the service bus. Queues are a list of things that your code needs to process. Functions can then be subscribed to the queue to be triggered when something enters the queue&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-azurefunction-4.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;h2 id="adding-to-the-queue">Adding to the Queue&lt;/h2>
&lt;p>Back in our first function, you only require a few lines to add an item to the queue. The first line gets an environment variable like previously, from the local json file or the application settings within the Azure function.&lt;/p>
&lt;p>The object I create here is to simply pass all the details I need to the queue.&lt;/p>
&lt;p>var queueClient = (IQueueClient)new QueueClient(Environment.GetEnvironmentVariable(&amp;ldquo;ServiceBusConString&amp;rdquo;), Environment.GetEnvironmentVariable(&amp;ldquo;queueName&amp;rdquo;), ReceiveMode.PeekLock, null);
var fsObject = new
{
email = emailAddress,
contactId = (Guid)jContactResponse[&amp;ldquo;value&amp;rdquo;][0][&amp;ldquo;contactid&amp;rdquo;],
intent,
date,
device
};
Task messageReturn = SendMessagesAsync(JsonConvert.SerializeObject(fsObject).ToString());&lt;/p>
&lt;p>I then call the function SendMessagesAsync, converting the object to a string as I do it. The SendMessageASync is below&lt;/p>
&lt;p>private static async Task SendMessagesAsync(string messageToSend)
{
try
{
Message message = new Message(Encoding.UTF8.GetBytes(messageToSend));
Console.WriteLine(&amp;ldquo;Sending message: &amp;quot; + messageToSend);
await queueClient.SendAsync(message);
message = null;
}
catch (Exception ex)
{
Console.WriteLine(string.Format(&amp;quot;{0} :: Exception: {1}&amp;rdquo;, DateTime.Now, ex.Message));
}
}&lt;/p>
&lt;p>Call the method uses an Asynchronous call which I don&amp;rsquo;t wait for the return. I just assume it works and get on with responding to the user.&lt;/p>
&lt;h2 id="reading-the-queue">Reading the Queue&lt;/h2>
&lt;p>To read the object from the queue, you need to register the function as a subscriber to the queue.&lt;/p>
&lt;p>To do this, the function trigger needs to have a certain format&lt;/p>
&lt;p>[FunctionName(&amp;ldquo;AddToFS&amp;rdquo;)]
public static async void AddToFS([ServiceBusTrigger(&amp;ldquo;ccalexa&amp;rdquo;, Connection = &amp;ldquo;ServiceBusConString&amp;rdquo;)] string myQueueItem, ILogger log, ExecutionContext context)
{&lt;/p>
&lt;p>The parameters to the function connect to a queue called ccalexa &amp;amp; a service bus indicated in the application variable &amp;ldquo;ServiceBusConString&amp;rdquo;. This signature shows that Microsoft is thinking about moving between environments from the start.&lt;/p>
&lt;p>The next part of the function defines the parameters for the call to D365. This leads to parsing the object that is being found on the queue.&lt;/p>
&lt;p>JObject woObject = JObject.Parse(myQueueItem);&lt;/p>
&lt;p>Guid contactId = (Guid)woObject[&amp;ldquo;contactId&amp;rdquo;];
var email = woObject[&amp;ldquo;email&amp;rdquo;];
var intent = woObject[&amp;ldquo;intent&amp;rdquo;];
string date = (string)woObject[&amp;ldquo;date&amp;rdquo;];
string device = woObject[&amp;ldquo;device&amp;rdquo;].ToString();&lt;/p>
&lt;p>Once we have the detail of the item sent in, we can go to D365 and retrieve some records we need to create the Work Order, firstly to the Contact, to retrieve the account associated with it.&lt;/p>
&lt;p>var contactResult = await d365Connect.GetAsync(&amp;ldquo;api/data/v9.1/contacts(&amp;rdquo; + contactId + &amp;ldquo;)?$select=_parentcustomerid_value&amp;rdquo;);
if (!contactResult.IsSuccessStatusCode)
{
return;
}&lt;/p>
&lt;p>If the return is not success, something went wrong. Forgive me for not doing some proper error trapping here. Next, we work to get the Default Pricelist, from the account &amp;amp; work order type from the intent passed in&lt;/p>
&lt;p>JObject contactObject = JObject.Parse(contactResult.Content.ReadAsStringAsync().Result);
var accountId = contactObject[&amp;quot;_parentcustomerid_value&amp;quot;];
HttpResponseMessage accountResponse = await d365Connect.GetAsync(&amp;ldquo;api/data/v9.1/accounts(&amp;rdquo; + accountId.ToString() + &amp;ldquo;)?$select=_defaultpricelevelid_value&amp;rdquo;);&lt;/p>
&lt;p>JObject jaccountResponse = JObject.Parse(accountResponse.Content.ReadAsStringAsync().Result);&lt;/p>
&lt;p>Guid priceListId = (Guid)jaccountResponse[&amp;quot;_defaultpricelevelid_value&amp;quot;];&lt;/p>
&lt;p>HttpResponseMessage woTypeResponse = await d365Connect.GetAsync(&amp;ldquo;api/data/v9.1/msdyn_workordertypes()?$select=msdyn_workordertypeid&amp;amp;$filter=cc_alexaintent eq &amp;lsquo;&amp;rdquo; + intent + &amp;ldquo;&amp;rsquo;&amp;rdquo;);&lt;/p>
&lt;p>JObject jwotResponse = JObject.Parse(woTypeResponse.Content.ReadAsStringAsync().Result);
Guid woTypeId = (Guid)jwotResponse[&amp;ldquo;value&amp;rdquo;][0][&amp;ldquo;msdyn_workordertypeid&amp;rdquo;];&lt;/p>
&lt;p>Next, we build up the object to add as a new work order. Line 2 shows binding to a pricelist record. This method is used for type &amp;amp; account too. I also generate a random number for the name to keep consistent with the Flow version.&lt;/p>
&lt;p>JObject workOrder = new JObject();
workOrder.Add(&amp;ldquo;msdyn_pricelist@odata.bind&amp;rdquo;, (&amp;quot;/pricelevels(&amp;quot; + priceListId + &amp;ldquo;)&amp;rdquo;));&lt;/p>
&lt;p>workOrder.Add(&amp;ldquo;msdyn_name&amp;rdquo;, (&amp;ldquo;AZ&amp;rdquo; + new Random().Next(4000, 500000)));
workOrder.Add(&amp;ldquo;msdyn_serviceaccount@odata.bind&amp;rdquo;, (&amp;quot;/accounts(&amp;quot; + accountId + &amp;ldquo;)&amp;rdquo;));
workOrder.Add(&amp;ldquo;msdyn_systemstatus&amp;rdquo;, 690970000);&lt;/p>
&lt;p>workOrder.Add(&amp;ldquo;msdyn_workordertype@odata.bind&amp;rdquo;, (&amp;quot;/msdyn_workordertypes(&amp;quot; + woTypeId + &amp;ldquo;)&amp;rdquo;));
workOrder.Add(&amp;ldquo;msdyn_taxable&amp;rdquo;, false);&lt;/p>
&lt;p>if (date != string.Empty) workOrder.Add(&amp;ldquo;msdyn_timefrompromised&amp;rdquo;, date);
if (device != string.Empty) workOrder.Add(&amp;ldquo;msdyn_instructions&amp;rdquo;, device);&lt;/p>
&lt;p>log.LogInformation(workOrder.ToString());&lt;/p>
&lt;p>HttpRequestMessage createWO = new HttpRequestMessage(HttpMethod.Post, d365Connect.BaseAddress.ToString() + &amp;ldquo;api/data/v9.1/msdyn_workorders&amp;rdquo;);&lt;/p>
&lt;p>createWO.Content = new StringContent(workOrder.ToString(), Encoding.UTF8, &amp;ldquo;application/json&amp;rdquo;);&lt;/p>
&lt;p>HttpResponseMessage createWOResp = d365Connect.SendAsync(createWO, HttpCompletionOption.ResponseContentRead).Result;&lt;/p>
&lt;p>Finally a post method to the msdyn_workorders entity pushes this as a new work order into the system.&lt;/p>
&lt;h2 id="connecting-alexa-to-our-function">Connecting Alexa to our Function&lt;/h2>
&lt;p>This is the simplest bit. In the original set of &lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" target="_blank" rel="noopener"
>posts&lt;/a>, I talked about endpoints. The endpoint needs swapping to the function call.&lt;/p>
&lt;p>The URL is retrieved the same way as I did in my demo, from the Azure Function properties in the Azure portal.&lt;/p>
&lt;p>Update the Service Endpoint &amp;amp; you are good to go.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-8.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;h2 id="the-results">The results&lt;/h2>
&lt;p>When I started this challenge, I wanted to compare and contrast the response time between Flow and Functions. I would assume Functions would be quicker, but what would the difference be?&lt;/p>
&lt;p>Caveats here - Both the flow and the function are my code. I am sure that there are better ways of doing both. Both follow each other functionally so it is a fair comparison.&lt;/p>
&lt;p>To test, I swapped the end point and then did 5 runs to &amp;ldquo;warm up the code&amp;rdquo;. I found , particularly Azure function, took a while to come up to speed. This can be explained by cold starting of functions which will be the case in our scenario. Even flows run faster the second time through.&lt;/p>
&lt;p>I then ran the test cycle 10 times then used the monitoring within Alexa to monitor response time. Both sections I checked I was getting work orders being created correctly.&lt;/p>
&lt;p>The first blip in the chart is the Flow configuration. This has a P90 (90 percent of the requests where responded within this time) of over 4 seconds. It drops to a more respectable 1 second as the Flow is warmed up.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-9.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>The second blip is when the configuration swaps to Azure Function. You can see this has a peek around 2 seconds for the first call. then dropping to 300ms for each subsequent call. This is a vast improvement for the responsiveness of your app.&lt;/p>
&lt;p>Don&amp;rsquo;t get me wrong, I am not telling you to revert everything to a Function, it is using the right tool for the job.&lt;/p>
&lt;p>Power Automate got me this far, it is great for scenarios where you don&amp;rsquo;t need an immediate response, it is great to prove that developing Alexa into your toolset is beneficial, but if you want to get serious about the user experience, in this instance, a Function serves you better.&lt;/p></description></item><item><title>Alexa, Field Service and Me (Part 4) - Using Azure Functions</title><link>https://linked365.blog/2020/03/09/alexa-field-service-and-me-part-4-using-azure-functions/</link><pubDate>Mon, 09 Mar 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/03/09/alexa-field-service-and-me-part-4-using-azure-functions/</guid><description>&lt;img src="https://linked365.blog/images/2020/03-image-5.png" alt="Featured image of post Alexa, Field Service and Me (Part 4) - Using Azure Functions" />&lt;p>I was lucky enough to be given a speaking slot at &lt;a class="link" href="https://www.summiteurope.com/" target="_blank" rel="noopener"
>Summit Europe&lt;/a> in Barcelona on this Alex subject. Unfortunately this event is now postponed until June, but I set myself the challenge to replace the Flow in this solution with a more capable (quicker) response time.&lt;/p>
&lt;p>Power Automate is great, don&amp;rsquo;t get me wrong. I love that a low code alternative to connecting applications is available. I love that you can automate anything in your business with a point and click interface. But, there are times when the (ex) prodev in me thinks that this approach could lead to applications that don&amp;rsquo;t respond to you as quickly as they should.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-7.png?w=566"
loading="lazy"
>&lt;/p>
&lt;p>In my Alexa solution (&lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" target="_blank" rel="noopener"
>here&lt;/a>) I use a Alexa to trigger a Flow that checks the user&amp;rsquo;s email, responds to the user then calls a second flow to create a Work Order in Field Service. This response takes roughly 3 seconds, which is on the edge of acceptable. My goal would be to bring this down to at most a second, using a Function.&lt;/p>
&lt;h2 id="functions">Functions&lt;/h2>
&lt;p>&lt;a class="link" href="https://azure.microsoft.com/en-gb/services/functions/" target="_blank" rel="noopener"
>Azure Functions&lt;/a> are event driver serverless bits of code that can complete complex actions or orchestrations. They are built on Azure, using a consumption operation normally (you pay for the compute resources when they are triggered) so sit around costing you nothing until called. Bit like Flow in this regard.&lt;/p>
&lt;p>They can be written in .NET, Java, JavaScript or Python and can scale with your usage. I have experience in a previous live in .NET, so plumped for this.&lt;/p>
&lt;p>Please be warned that I am not a prodev anymore. It took me a while to get a Function connected to D365. My days of coding everyday &amp;amp; really understanding the intricacies here are long gone (sadly). If I have done something wrong, then I am sorry. It was just my way of proofing a point. I am sure that the performance can be improved further quite easily.&lt;/p>
&lt;h2 id="create-a-function">Create a Function&lt;/h2>
&lt;p>First you need an Azure subscription. You can get a trial with credit to complete a PoC for free. I am not going through those steps.&lt;/p>
&lt;p>Secondly, choose your code environment. I have used Visual Studio 2019, as I struggled with configuring on my PC with Visual Studio Code(It was me) and when I moved to Visual Studio 2019, everything worked. I would recommend starting with Visual Studio Code, as it is free and it is definitely the way forward.&lt;/p>
&lt;p>So in visual Studio, we create an Azure Function. Here I start a new project, select the Azure Function template, give the project a name, accept the standard options and I get my code snippet for a function ready to run&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-azurefunction-1-1.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Just to check everything is working, lets publish to Azure &amp;amp; try it out!&lt;/p>
&lt;p>Here, I select Publish on the project and create all new versions (the original bits are for my complete one) for Resource Group, Hosting plan &amp;amp; Azure storage.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-azurefunction-2.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>It takes a while the first time as it is provisioning bits in Azure as well as compiling code, but when it is done, you can try it out in Postman.&lt;/p>
&lt;p>To get the URL, hope over to portal.azure.com and search for your function. I use the top bar &amp;amp; search for Alexa.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image.png?w=974"
loading="lazy"
>&lt;/p>
&lt;p>On the left hand side menu, drop down the Functions Menu to show the function we created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-1.png?w=719"
loading="lazy"
>&lt;/p>
&lt;p>Top right is a link to the URL that we need to post to. This includes the website address plus a function key. This secures the API a little. This is a PoC, so this is enough for me, but in production, be wary about opening functions to the public&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-3.png?w=607"
loading="lazy"
>&lt;/p>
&lt;p>If you hit copy &amp;amp; paste this into a Postman session, or just a webpage, you will get the default response back.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-4.png?w=616"
loading="lazy"
>&lt;/p>
&lt;p>If you add a query parameter like it is expecting, namely name, you will get a different response&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-image-5.png?w=614"
loading="lazy"
>&lt;/p>
&lt;p>So, this is a simple function, deployed to Azure, with a post &amp;amp; return. That easy!&lt;/p>
&lt;h2 id="alexa-function---getting-the-current-user">Alexa Function - Getting the current user&lt;/h2>
&lt;p>As I said in the outset, my code is not perfect by any means. I expect (encourage) criticism, to expand my understanding of the subject. I don&amp;rsquo;t intend to go through my code line by line, just the key aspects.&lt;/p>
&lt;p>The code is available &lt;a class="link" href="https://github.com/CooksterC/Community/tree/master/AlexaFunction" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;p>The function call has an attribute which is used to define the call to the function. This tickles to your Azure Function.&lt;/p>
&lt;p>[FunctionName(&amp;ldquo;Alexa&amp;rdquo;)]
public static async Task&lt;IActionResult> RunAlexa(
[HttpTrigger(AuthorizationLevel.Function, new string[] { &amp;ldquo;get&amp;rdquo;,
&amp;ldquo;post&amp;rdquo; }, Route = null)] HttpRequest req,
ILogger log,
ExecutionContext context)
{&lt;/p>
&lt;p>The next part retrieve the JSON body of the trigger from Alexa and converts the body into an object from which we can ascertain parts of the request body.&lt;/p>
&lt;p>string content = new StreamReader(req.Body).ReadToEnd();
dynamic alexaContent = JsonConvert.DeserializeObject(content);&lt;/p>
&lt;p>The main part we want is to get the Alex access token. This allows, as I described in the second part of the &lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" target="_blank" rel="noopener"
>Alexa blog&lt;/a>, the retrieval of information about the user that is interacting with Alexa.&lt;/p>
&lt;pre>&lt;code> if (alexaContent.context.System.apiAccessToken == null)
{
log.LogError(&amp;quot;No Access Token sent&amp;quot;);
return null;
}
&lt;/code>&lt;/pre>
&lt;p>This section calls Alexa api, using the apiToken that was sent and asks for the email of the user. If we get an error, as in we have not got approval, respond straight way, the same as we did for Alexa in Flow.&lt;/p>
&lt;p>using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(&amp;ldquo;&lt;a class="link" href="https://api.eu.amazonalexa.com/v2/accounts/~current/settings/Profile.email%22%29;" target="_blank" rel="noopener"
>https://api.eu.amazonalexa.com/v2/accounts/~current/settings/Profile.email");&lt;/a>
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(&amp;ldquo;Bearer&amp;rdquo;, apiAccessToken);
try
{
emailAddress = await client.GetStringAsync(&amp;rdquo;&amp;quot;);
log.LogInformation(emailAddress);
}
catch (Exception ex)
{
log.LogInformation(ex.ToString());
var errorObject = new
{
version = &amp;ldquo;1.0&amp;rdquo;,
response = new
{
card = new
{
type = &amp;ldquo;AskForPermissionsConsent&amp;rdquo;,
permissions = new string[1]
{
&amp;ldquo;alexa::profile:email:read&amp;rdquo;
}
}
}
};
return new JsonResult(errorObject);
}
}&lt;/p>
&lt;h2 id="alexa-function---authorisation-against-d365">Alexa Function - Authorisation against D365&lt;/h2>
&lt;p>The next section retrieves a list of variables stored in a local settings file, local.settings.json or in the application settings when this becomes a proper function. This allows you not to store client secrets etc within the code and also allows you to alter where the function is pointed to for dev \ test environments.&lt;/p>
&lt;p>string baseUrl = Environment.GetEnvironmentVariable(&amp;ldquo;baseUrl&amp;rdquo;);
string clientId = Environment.GetEnvironmentVariable(&amp;ldquo;clientId&amp;rdquo;);
string secret = Environment.GetEnvironmentVariable(&amp;ldquo;secret&amp;rdquo;);
string authority = Environment.GetEnvironmentVariable(&amp;ldquo;Authority&amp;rdquo;);&lt;/p>
&lt;p>string getToken = await GetToken(baseUrl, clientId, secret, authority, log);&lt;/p>
&lt;p>The GetToken function is below. I used the code from docs.microsoft.com &lt;a class="link" href="https://docs.microsoft.com/en-gb/powerapps/developer/common-data-service/authenticate-oauth#connect-as-an-app" target="_blank" rel="noopener"
>here&lt;/a>. This code steps you through creating an application user and giving it the appropriate rights, as well as how to configure the clientId &amp;amp; secret.&lt;/p>
&lt;p>private static async Task&lt;string> GetToken(
string baseUrl,
string clientId,
string secret,
string Authority,
ILogger log)
{
AuthenticationContext authContext = new AuthenticationContext(Authority);
ClientCredential credential = new ClientCredential(clientId, secret);
AuthenticationResult result = await authContext.AcquireTokenAsync(baseUrl, credential);
return result.AccessToken;
}&lt;/p>
&lt;p>Next is to check the email is in D365. Firstly, I configure the httpClient object, then call the api to retreive all the contacts that have a emailaddress1 equal to the email sent by the user. I only care about the first name &amp;amp; last name, so using the select will return only those fields.&lt;/p>
&lt;p>If there is a response, I carry on, if not, I need to respond to the user again.&lt;/p>
&lt;p>using (HttpClient d365Connect = new HttpClient())
{
d365Connect.BaseAddress = new Uri(baseUrl);
d365Connect.DefaultRequestHeaders.Add(&amp;ldquo;OData-MaxVersion&amp;rdquo;, &amp;ldquo;4.0&amp;rdquo;);
d365Connect.DefaultRequestHeaders.Add(&amp;ldquo;OData-Version&amp;rdquo;, &amp;ldquo;4.0&amp;rdquo;);
d365Connect.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(&amp;ldquo;application/json&amp;rdquo;));
d365Connect.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(&amp;ldquo;Bearer&amp;rdquo;, getToken);
HttpResponseMessage contactResponse = await d365Connect.GetAsync(&amp;ldquo;api/data/v9.1//contacts()?$select=firstname, lastname&amp;amp;$filter=emailaddress1 eq &amp;lsquo;&amp;rdquo; + emailAddress + &amp;ldquo;&amp;rsquo;&amp;rdquo;);
if (!contactResponse.IsSuccessStatusCode)
return null;
log.LogInformation(&amp;ldquo;Read Contact&amp;rdquo;);
JObject jContactResponse = JObject.Parse(contactResponse.Content.ReadAsStringAsync().Result);
if (!jContactResponse[&amp;ldquo;value&amp;rdquo;].HasValues)
{
log.LogInformation(&amp;ldquo;Cant find contact&amp;rdquo;);
var errorObject = new
{
version = &amp;ldquo;1.0&amp;rdquo;,
response = new
{
outputSpeech = new
{
text = &amp;ldquo;Hi, Big Energy Co here. Unfortunately,&amp;rdquo; + emailAddress + &amp;ldquo;is not registered with us for the Alexa App. Please contact 01234 567890 during office hours to configure your account&amp;rdquo;,
type = &amp;ldquo;PlainText&amp;rdquo;
},
card = new
{
type = &amp;ldquo;Standard&amp;rdquo;,
title = &amp;ldquo;Big Energy Co&amp;rdquo;,
text = &amp;ldquo;Unfortunately, &amp;quot; + emailAddress + &amp;ldquo;is not registered with us for the Alexa App. Please contact 01234 567890 during office hours to configure your account&amp;rdquo;
}
}
};
return new JsonResult(errorObject);
}&lt;/p>
&lt;p>In the flow, it is at this point, when I have enough information, I send over to a child flow. In this scenario I am sending over to a service bus. I will detail how that works in the next post, as configuring the bus etc will take time. You can always get ahead of the action by taking a look at the code.&lt;/p>
&lt;h2 id="alexa-function---respond-to-the-user">Alexa Function - Respond to the user&lt;/h2>
&lt;p>Finally, we need a proper response to the user. Similar to the flow, we have a switch on the intent. I use a string that I append to and build up. The Azure parts are only for me to check that the response is from Azure version rather than Power Automate.&lt;/p>
&lt;p>switch (intent)
{
case &amp;ldquo;service&amp;rdquo;:
returnBody = &amp;ldquo;Hi, we have recieved your request for an Azure Service &amp;ldquo;;
returnBody += device == &amp;quot;&amp;rdquo; ? &amp;quot;&amp;rdquo; : &amp;quot; for your &amp;quot; + device;
returnBody += date == string.Empty ? &amp;quot;&amp;rdquo; : &amp;ldquo;. We will endeavour to book a service on &amp;quot; + date;
break;
case &amp;ldquo;repair&amp;rdquo;:
returnBody = &amp;ldquo;Sorry to hear you have a Azure broken &amp;ldquo;;
returnBody += device == string.Empty ? &amp;ldquo;device&amp;rdquo; : device;
returnBody += date == string.Empty ? &amp;quot;&amp;rdquo; : &amp;ldquo;. We will endeavor to send an engineer on &amp;quot; + date;
break;
case &amp;ldquo;emergency&amp;rdquo;:
returnBody = &amp;ldquo;Oh No! An Azure Emergency!&amp;rdquo;;
break;
default:
returnBody = &amp;ldquo;OK, Big Energy Azure Function has got your request&amp;rdquo;;
break;
}&lt;/p>
&lt;p>By creating an object then converting to JSON, this can be used as the response.&lt;/p>
&lt;p>returnBody += &amp;ldquo;. One of our support specialist will contact you within the hour to confirm the scheduled time for our engineer&amp;rdquo;;
var returnObject = new
{
version = &amp;ldquo;1.0&amp;rdquo;,
response = new
{
outputSpeech = new
{
text = returnBody,
type = &amp;ldquo;PlainText&amp;rdquo;
},
card = new
{
type = &amp;ldquo;Standard&amp;rdquo;,
title = &amp;ldquo;Big Energy Co&amp;rdquo;,
text = returnBody
}
}
};
log.LogInformation(&amp;ldquo;Responding&amp;rdquo;);
return new JsonResult(returnObject);&lt;/p></description></item><item><title>Scottish Summit - A Review</title><link>https://linked365.blog/2020/03/07/scottish-summit-a-review/</link><pubDate>Sat, 07 Mar 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/03/07/scottish-summit-a-review/</guid><description>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-03-01-at-22.44.28-1.jpeg" alt="Featured image of post Scottish Summit - A Review" />&lt;p>The extra day a year only comes around every 4 years and it seemed appropriate that a lot of the Power Platform community came together to celebrate in Glasgow.&lt;/p>
&lt;p>Scottish Summit 2020 was sponsored by Avanade and myself and several colleagues went along to enjoy the event, cement Avanade in the community, share our knowledge and learn from others.&lt;/p>
&lt;p>With over 1000 people descending on the University of Strathclyde’s Technology and Innovation Centre, this event is one of the biggest, free, community organised events in Europe. Our hosts, Iain Connolly and Mark Christie have worked hard to promote the event and established it quickly as the place to be for D365 / Azure / Office users and partners to be.&lt;/p>
&lt;h2 id="first-day--common-data-service-hack">&lt;strong>First Day – Common Data Service Hack&lt;/strong>&lt;/h2>
&lt;p>My first day at the conference was participating in the CDS Hackathon. Chris Huntingford and Lucy Bourne from Microsoft introduced us to the requirements for the hack and 20 of us spent the day being creative in groups to resolve an environmental challenge. Our group decided to tackle our carbon footprint, highlighting how our day-to-day choices can have an impact on the environment.&lt;/p>
&lt;p>Combining a Forms Pro questionnaire, a Power App for the collation of data by council employees, a Modal driven app to maintain the questions and Power BI to visualise it, we produced a solution that would be ready for use within 3 hours! This shows the power of the Low code capabilities of the Power Platform and teamwork!&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-03-04-at-11.21.54.jpeg?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Thanks to &lt;a class="link" href="https://twitter.com/LeeMBaker" target="_blank" rel="noopener"
>@LeeMBaker&lt;/a> for the photo&lt;/p>
&lt;p>On Friday evening I managed to catch up with a lot of the Microsoft team attending the event, discussing the partner landscape, challenges they are seeing and how we can work with them to overcome these challenges.&lt;/p>
&lt;h2 id="scottish-summit-saturday">&lt;strong>Scottish Summit Saturday&lt;/strong>&lt;/h2>
&lt;p>On Saturday, after an early start, we set out our stall. Avanade was showcasing our capabilities to the attendees with D365, across Customer Engagement and Finance and Operations. Mixed Reality has become a big topic within the community, and we were lucky to be able to showcase a HoloLens 2. This was a big crowd-pleaser, with a lot of attendees experiencing this technology for the first time.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-03-01-at-22.44.28-1.jpeg?w=768"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-02-29-at-12.57.12-1.jpeg?w=1024"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-02-29-at-12.52.50.jpeg?w=768"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>Explaining how Mixed Reality can be used for training, 3rd line support or visualisations of products in your environments was an eyeopener to a lot of people and it was great to showcase Avanade&amp;rsquo;s capability and some customer successes.&lt;/p>
&lt;h2 id="keynote--this-is-more-than-just-technology">&lt;strong>Keynote – This is more than just technology…..&lt;/strong>&lt;/h2>
&lt;p>What a start! Jon Levesque, Senior Platform Evangelist for the Power Platform at Microsoft was piped into the main hall, with a kilt on to celebrate our location.&lt;/p>
&lt;p>&lt;img src="https://pbs.twimg.com/media/ER7p32BXUAAApQS?format=jpg&amp;amp;name=medium"
loading="lazy"
alt="Image"
>&lt;/p>
&lt;p>Photo courtesy of &lt;a class="link" href="https://twitter.com/marijnsomers" target="_blank" rel="noopener"
>@MarijnSomers&lt;/a> (corrected)&lt;/p>
&lt;p>He started with his personal journey, starting from being a member of the team that supported Steve Ballmer when he was giving talks across the world to his role now, where he is paid to fly around the world and evangelise on the Power Platform.&lt;/p>
&lt;p>Jon gave pertinent stories about how the Power Platform has changed people and businesses across the world, empowering people in their day jobs to think about creating solutions to benefit their role.&lt;/p>
&lt;p>His enthusiasm for the community and how it impacts the lives of everyone was infectious. Everyone left with a sense of belonging and enthusiasm to develop themselves and their businesses to the next level&lt;/p>
&lt;p>Throughout the day, there were various sessions that we attended to educate ourselves.&lt;/p>
&lt;h2 id="session-1---to-code-or-not-to-code---that-is-the-question">&lt;strong>Session 1 - To Code or not to Code - That is the Question&lt;/strong>&lt;/h2>
&lt;p>My first session was given by Scott Durow and Sara Lagerquist, both Microsoft Valued Professionals and at the top of their game. Their talk was about the perceived battlegrounds that have been drawn between LowCode and Pro-Dev practitioners.&lt;/p>
&lt;p>Sara argued that Low-code, via Power Apps, Power Automate and the other numerous members of the Power Platform are allowing for a more reactive and time frames for users to achieve the solutions they need in their businesses. She highlighted that coding can lead to technical debt, development bottlenecks and reduced user adoption.&lt;/p>
&lt;p>Scott countered these arguments by highlighting that bad solutions can come from low-code or pro dev equally, and each has its place in bring solutions to live. Gone are the days when grumpy developers can hold BAs and functional consultants hostage with their use of technical terms&lt;/p>
&lt;p>But the outcome of their presentation was showing that we need to remove the barriers. Technical and functional need to co-exist and work with each other to use the right technology for the problem. Low code has great use cases to empower individuals to expand their applications across data silos, but if you want a speedy integration would Power Automate fit the bill? Encouraging Functional and Technical consultants to have conversations early on in a project and recognising the diversity of their skill sets would lead to increased user adoption and improved solutions.&lt;/p>
&lt;h2 id="session-2---mixed-reality---extending-d365-on-the-next-frontier">&lt;strong>Session 2 - Mixed Reality - Extending D365 on the next frontier&lt;/strong>&lt;/h2>
&lt;p>Kyle Hill, one of Avanade’s MVP hosted a session on Mixed Reality. He used the session to show the capabilities of Microsoft’s HoloLens 2 and how it empowers everyone within a business. From architectural uses – walking through a floor plan to first-line service staff - providing visual clues to while they are resolving a problem on customer site.&lt;/p>
&lt;ul>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-02-29-at-12.52.49.jpeg?w=1024"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-02-29-at-12.24.48-1.jpeg?w=1024"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-whatsapp-image-2020-02-29-at-12.24.48.jpeg?w=1024"
loading="lazy"
>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;p>He also walked through how a low-code approach can be taken to augment the view of a user and the tools Microsoft provides to create this content.&lt;/p>
&lt;p>It was a great show of how this emerging technology will soon be as widespread as mobile phones, available to all at a price point to match. I love the fact that Avanade is at the front of this adoption and are bringing this technology to businesses of all scales to change their approach to solving problems and transforming their processes.&lt;/p>
&lt;h2 id="session-3---top-20-tips-for-surviving-networking-at-events">&lt;strong>Session 3 - Top 20 Tips for Surviving Networking at Events&lt;/strong>&lt;/h2>
&lt;p>Not every session is a technical one, Lucy Bourne, another Microsoft employee delivered a great session on how individuals can address their anxieties to better involve them in our community. In any community, when you begin, it is a room of strangers and lots of people are anxious about reaching out and getting involved.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/03-er9io5ux0aejlcl-scaled.jpg?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Photo courtesy of &lt;a class="link" href="https://twitter.com/D365Geek" target="_blank" rel="noopener"
>@D365Geek&lt;/a>&lt;/p>
&lt;p>Lucy gave a whistle-stop guide to her 20 tips to survive these moments, gain confidence in your interactions and get involved. She highlighted that everyone has the same fears, everyone thinks they are an imposter at times and every one is unique. If you be yourself, “celebrate your onlyness”, as she puts it, and be genuine, then you can address your fears and become part of the big family we have as a community.&lt;/p>
&lt;h2 id="session-4--powerapps--a-thunderbolt-of-functional-awesome">&lt;strong>Session 4 – PowerApps – A Thunderbolt of Functional Awesome&lt;/strong>&lt;/h2>
&lt;p>To round out my day, I went to see Chris Huntingford, a Microsoft Partner Technical Architect show his audience how quick and easy it is to create a production application using low-code techniques and the tools make available to us via the Power Platform.&lt;/p>
&lt;p>He explained the benefits and fundamentals of the Power Platform and how we should be engaging with it as users, empowering businesses to democratise their data. He further made it clear that there is only a limited pool of developers, but if we encourage our business users to make edge apps with the data that is available to them, companies can save time and money.&lt;/p>
&lt;p>Towards the end of the session, he built an application within minutes, truly showing the flexibility of the platform.&lt;/p>
&lt;h2 id="in-conclusion">&lt;strong>In conclusion&lt;/strong>&lt;/h2>
&lt;p>Scottish Summit was a great event, it highlighted the great community we have. With speakers coming from Australia, America and all over Europe, it is an event that has started to become a must for anyone involved in the Microsoft stack.&lt;/p></description></item><item><title>3 Minute Feature : Episode 9 : Dashboards</title><link>https://linked365.blog/2020/03/05/3-minute-feature-episode-9-dashboards/</link><pubDate>Thu, 05 Mar 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/03/05/3-minute-feature-episode-9-dashboards/</guid><description>&lt;p>A common staple of the Model driven app experience, my 9th video runs you through creating single and multi stream dashboards&lt;/p>
&lt;h2 id="episode-9--dashboards">Episode 9 : Dashboards&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/gmLIvkGkNQM"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>Dashboards have 2 variants, those that are connected to an entity and those that are not. An entity dashboard, called Single Stream previouly, are designed for support desk users or similarly focused indviduals.  The multii stream dashboards are for more typical dashboard requirements, displaying MI for your users.&lt;/p>
&lt;p>For an entity dashboard,  you need to start from an entity.&lt;/p>
&lt;p>Use Entity, Dashboard, add dashboard, select one of the overview types, I have gone for 3 column overview, varied width.&lt;/p>
&lt;p>You are presented with the dashboard edit screen. Give it a name and a view to use with the dashboard, remember this is for a single entity.&lt;/p>
&lt;p>In the 3 panels at the top you can add 3 charts of your choice, from those available against that entity, and only system charts.&lt;/p>
&lt;p>The stream is meant to be a focus area for a list of records to be displayed. Select a view, again for the same entity.&lt;/p>
&lt;p>Select Save and close. In the user interface, if you got to the entity in question and select Dashboards, the new dashboard should be visible. It stats with the visual filter not displayed. This is the 3 charts we put in.&lt;/p>
&lt;p>If you select any of the charts and drill down, the data in the other charts and the feed is filtered as well&lt;/p>
&lt;p>In the top right of the dashbaord you can also alter the timeframe resulting in the records being redisplayed.&lt;/p>
&lt;p>For the multi-stream dashboards, add a new dashboard direct from the solution. Here I chose a 3 column dashboard. The same editor appears. You can add components such as Charts, views web resources and even a timeline control. To make room for it, I will delete the 2 spots to the right, the add a timeline control. I can also then expand to fill the whole of the right of the frame.&lt;/p>
&lt;p>Again save and close, to return to the solution view and ensure you publish all customisations.&lt;/p>
&lt;p>In the user interface, our new dashboard is now available. The timeline fills out the far side and our other components are visible&lt;/p>
&lt;p> Like with Views, you can also create your own dashboards. Similarly, if you want to restrict the access to Dashboards, you need to do it with a personal dashboard and share it to restict the useage to a particular user group. All System dashboards are available to all users who have the application where the dashboard is configured.&lt;/p>
&lt;p>Here I create a copy of my dashboard and then I am able to share it. I go into the dashboard and remove the pane for an account listing. Hitting save shows you my new, personal version of the dashboard.&lt;/p>
&lt;p>When using Personal dashboards, ensure the users you share with also have access to any personal views or charts you add to your dashboard&lt;/p></description></item><item><title>3 Minute Feature : Episode 8 : Charts</title><link>https://linked365.blog/2020/02/27/3-minute-feature-episode-8-charts/</link><pubDate>Thu, 27 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/27/3-minute-feature-episode-8-charts/</guid><description>&lt;p>Charts in a model app are a great tool for customisers to visualise data&lt;/p>
&lt;h2 id="episode-8--charts">Episode 8 : Charts&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/9z1LLflHro8"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>Charts in D365 allow a visualisation of the data from a view. We discussed views earlier in the series so won&amp;rsquo;t go into that.&lt;/p>
&lt;p>Starting at the Entity in your solution, you navigate to charts, select Add Chart&lt;/p>
&lt;p>The new chart display comes up&lt;/p>
&lt;p>We will begin with a simple column chart.&lt;/p>
&lt;p>Select a Legend Entries, this is the column that will be counted or summed etc, giving you your Y axis&lt;/p>
&lt;p>Next, select the series entries. This gives you your x axis bands. If you choose a date field, you can define the date period.&lt;/p>
&lt;p>Now hit save and close.&lt;/p>
&lt;p>The chart appears in the solution&lt;/p>
&lt;p>Over in the user interface, if you select the entities and views, you will have an option to display a chart. This allows the current view to be displayed in the chart you select, getting you this visualisation&lt;/p>
&lt;p>Here, you can see the chart we defined has been brought through.&lt;/p>
&lt;p>If you select or one or the bars in the chart, the view gets filtered by the selected data and it also allows you to drill down the data, dividing the data into other categories.&lt;/p>
&lt;p>This chart is a system chart. System charts can be part of your solution, being able to move between environments, but you will not be able to &amp;ldquo;secure&amp;rdquo; them. Either everyone sees the chart of no one does.&lt;/p>
&lt;p>If you want to only share certain charts with certain groups of users, you should be using user charts. It also allows me to show you the other visualisations easier.&lt;/p>
&lt;p>On the chart, if I select New, I will be creating a new user view, only initially shared with my user. The same interface appears allowing you to define the chart.&lt;/p>
&lt;p>I have given this a separate name, hit save and close&lt;/p>
&lt;p>Back in the user interface, on hard refresh, the new chart appears. Also, on the chart, I have the ability to share. Here I can share with other users or teams of users.&lt;/p>
&lt;p>Using account, as there is more data, I will run through the options available to you. Firstly, I make a copy of the out of the box Account By Industry then select edit.&lt;/p>
&lt;p>This chart starts off as a bar chart, firstly switch to a column chart. Next we can add a field to the series to show a max number of employees in each sector.&lt;/p>
&lt;p>You can only have mor e than one series or legend entry, not both at one time. So next I remove the number of employees and add a second series for country region&lt;/p>
&lt;p>You can see now that the bars are split up by country then industry. Swappng the series over, allows you to imagine the data in a different way&lt;/p>
&lt;p>Lets looked at the other options, Stacked Bar or Column is great for you to show percentage data, but only works if the totals are roughly the same.&lt;/p>
&lt;p>Areas have a different visualisation, good for time line data to show increases.&lt;/p>
&lt;p>Line does nto have the overlap like area, again great to show variation in time.&lt;/p>
&lt;p>You will notice that I can not choose the other types. This is because I have more than one series or legend displayed. These visualisations rely on 2 dimensional data only.&lt;/p>
&lt;p>I remove the series for country to show these other options and select a simple Pie chart. This chart has a high number of records that are redundant, no industry, so it may be worth fitlering using a different view, or fixing the data.&lt;/p>
&lt;p>Funnel charts are really useful to show progress through a sales cycle, changing the size of the segment depending on the count of records.&lt;/p>
&lt;p>Tags display a list of the fields in the category &amp;amp; a count. Great for quickly visualising other data for filtering.&lt;/p>
&lt;p>And finally donuts are another visualisation&lt;/p>
&lt;p>This works well with small sets of types.&lt;/p>
&lt;p>To limit data, either use a different view or you can grab the top or bottom number of records from the view. Here I limit to the top 3 types displayed, hence our visualisation is a lot more appealing&lt;/p></description></item><item><title>Incident App (Part 1)</title><link>https://linked365.blog/2020/02/23/incident-app-part-1/</link><pubDate>Sun, 23 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/23/incident-app-part-1/</guid><description>&lt;img src="https://linked365.blog/images/2020/02-image-15.png" alt="Featured image of post Incident App (Part 1)" />&lt;p>Most of you won&amp;rsquo;t know this, but to keep me busy (as if work, blogging, presenting &amp;amp; community isn&amp;rsquo;t enough) I am the chair of my local platform diving club, Star Diving. Give them a look at &lt;a class="link" href="http://stardiving.org/" target="_blank" rel="noopener"
>http://stardiving.org/&lt;/a> if you or your son or daughter want to learn a great sport that pushes you to control your body &amp;amp; keep fit.&lt;/p>
&lt;p>My youngest son is part of the Skills squad (very proud parent) and he loves it. To support him and mainly because I was the last to step back, I became the chair of the club last April.&lt;/p>
&lt;p>Star is a registered charity, whose purpose is to promote diving across Surrey and beyond and have 200 members or all ages. As a registered charity, Microsoft generously gives Star 25 licenses for using Office 365, we host our email and use teams and other things.&lt;/p>
&lt;h2 id="the-requirement">The requirement&lt;/h2>
&lt;p>Diving is a dangerous sport to the untrained and accidents happen. Logging accidents and informing parents, in this day and age of GPDR has become a concern. Gone are the days that we can keep an accident book at the pool side and have a chat with a parent. Our duty of care needs to ensure any incidents are logged centrally to ensure repeat incidents.&lt;/p>
&lt;p>On discussing with our coaches and welfare officer a list of requirements where created. Wasn&amp;rsquo;t a formal list, just from conversations etc, but like any good BA, I created a list&lt;/p>
&lt;ul>
&lt;li>Centralised, secure list of incidents&lt;/li>
&lt;li>Ability to add divers to list for trials or competitions&lt;/li>
&lt;li>Data entry must be easy and not time-consuming&lt;/li>
&lt;li>Weekly notification of all incidents to the welfare officer&lt;/li>
&lt;li>Email to parent or guardian of the diver when an incident is raised&lt;/li>
&lt;li>Escalation to welfare officer and others in the organisation for serious incidents&lt;/li>
&lt;li>Not cost anything&lt;/li>
&lt;/ul>
&lt;p>Of all these requirements, the last one drove me in a direction which is not my normal. I am so used to firing up a CDS environment, creating an entity structure and starting the process from data.&lt;/p>
&lt;p>I decided to delve into the unknown (I know the principles, like any Solution Architect, but doing is different) and create a SharePoint list or two to store the data and build a Power App on top to handle data entry. Power Automate will be used to link the app together and provide the notifications.&lt;/p>
&lt;h2 id="introducing-pike">Introducing Pike&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-15.png?w=430"
loading="lazy"
>&lt;/p>
&lt;p>Pike&amp;rsquo;s front screen has a series of buttons that I will hopefully expand on as I add functionality. I have used the default black and yellow scheme, as Star&amp;rsquo;s colours are the same.&lt;/p>
&lt;h2 id="data-entry">Data Entry&lt;/h2>
&lt;p>If you click on Create New Incident, you are taken to the first data entry screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-16.png?w=432"
loading="lazy"
>&lt;/p>
&lt;p>This is my first learning point. I knew what the * next to the fields means, but my users didn&amp;rsquo;t. Don&amp;rsquo;t assume that just because you know how something works that others will.&lt;/p>
&lt;p>This is a simple form based on the SharePoint list. The fields are formatted for the screen, and I didn&amp;rsquo;t want a lot of scrolling, so split the data entry over 2 screens. The first screen uses a second list for all our divers and displays a drop-down of them.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-17.png?w=419"
loading="lazy"
>&lt;/p>
&lt;p>Further, if the diver is not on the list, for trials or competitions, you can add them using the + next to the diver&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-18.png?w=406"
loading="lazy"
>&lt;/p>
&lt;p>The Reporter field is a Person or Group field in SharePoint, which allows linking to a user on our environment. Location is a choice field, with diving specific terms.&lt;/p>
&lt;p>Once all the fields that require data are filled in, a big Next button appears at the bottom&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-19.png?w=426"
loading="lazy"
>&lt;/p>
&lt;p>This is done by a simple formula on the Visible property of the button, namely, only display if the form is valid&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-20.png?w=558"
loading="lazy"
>&lt;/p>
&lt;p>Selecting the button passed to a second New form, to finish entering the data.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-21.png?w=392"
loading="lazy"
>&lt;/p>
&lt;p>The Contacted? field is a multi-choice field and it kicks off a flow for serious incidents (if a hospital visit or ambulance is called, it is serious by default)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-22.png?w=404"
loading="lazy"
>&lt;/p>
&lt;p>Again, the visibility of the submit button is controlled by the validity of the form.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-23.png?w=431"
loading="lazy"
>&lt;/p>
&lt;p>The submit form doesn&amp;rsquo;t conduct a straight submit but combines the data on the two forms. Additionally, notify the user if there is a positive or negative outcome to the submission&lt;/p>
&lt;p>Patch(
Incidents,
Defaults(Incidents),
&amp;lsquo;frmIncidentNew-First&amp;rsquo;.Updates,
&amp;lsquo;frmIncidentNew-Second&amp;rsquo;.Updates, {&amp;lsquo;Welfare History&amp;rsquo;: &amp;ldquo;Created by &amp;quot; &amp;amp; User().FullName}
);
If(
IsEmpty(Errors(Incidents)),
Notify(
&amp;ldquo;Your incident has been recorded&amp;rdquo;,
NotificationType.Success
);
Navigate(
Home,
ScreenTransition.CoverRight
),
Notify(
&amp;ldquo;There was a problem submitting your incident. Please contact &lt;a class="link" href="mailto:incidents@stardiving.org" >incidents@stardiving.org&lt;/a> manually&amp;rdquo;,
NotificationType.Error
)
)&lt;/p>
&lt;p>This returns the user to the home screen, where they can view incidents they logged by clicking My Logged Incidents.&lt;/p>
&lt;h2 id="viewing-incidents">Viewing Incidents&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-25.png?w=437"
loading="lazy"
>&lt;/p>
&lt;p>As you can see, I got bored in testing &amp;amp; documented a lot of gruesome accidents, which thankfully doesn&amp;rsquo;t happen.&lt;/p>
&lt;p>Clicking on the arrow shows the detail.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-27.png?w=415"
loading="lazy"
>&lt;/p>
&lt;p>For a normal coach, a reporter, this is the end of the functionality. But for our welfare officer and administrator, there are a couple of additional features.&lt;/p>
&lt;h2 id="securing-special-features">Securing Special features&lt;/h2>
&lt;p>On startup of the application, I run a Flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-28.png?w=918"
loading="lazy"
>&lt;/p>
&lt;p>This flow is checking to see if the logged in user is the owner of the team that owns the Incidents list.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-29.png?w=638"
loading="lazy"
>&lt;/p>
&lt;p>Firstly, initialise some variables, then call the SharePoint API to check the current users rights in the given SharePoint site.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-30.png?w=631"
loading="lazy"
>&lt;/p>
&lt;p>The variable in the Uri is passed in from the Power App, which is the users email address.&lt;/p>
&lt;p>If this call returns a value, it means that the user is in the owner team, and this result is passed back to the Power App.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-31.png?w=573"
loading="lazy"
>&lt;/p>
&lt;p>The isAdmin boolean is set after the call as shown previously.&lt;/p>
&lt;p>This global variable is used on the List of Incidents screen to hide or show an icon at the top&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-32.png?w=425"
loading="lazy"
>&lt;/p>
&lt;p>The visibility of this is controlled by the isAdmin value.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-33.png?w=372"
loading="lazy"
>&lt;/p>
&lt;p>This button toggles whether the user sees all the incidents or just their own. This allows an admin to view all incidents.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-34.png?w=443"
loading="lazy"
>&lt;/p>
&lt;p>On the incident detail screen, there is a edit button as well, which allows an admin or welfare officer to add some commentary to the incident, such as when the parent is contacted or details about any investigations.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-35.png?w=427"
loading="lazy"
>&lt;/p>
&lt;h2 id="the-sharepoint-list">The SharePoint List&lt;/h2>
&lt;p>In SharePoint, you can see the recorded incident in the SharePoint list&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-36.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>This is a simple use of the list, and is secure. Next article, I will walk-through the other flows that are being triggered to notify the parents and welfare officers to complete the requirements.&lt;/p>
&lt;h2 id="conclusions">Conclusions&lt;/h2>
&lt;p>It is a simple app, but it really hits the mark for being cheap (free), secure, easy &amp;amp; portable. SharePoint may not be the database of choice for everyone, but you can not knock it for being cheap. Power Apps just adds that extra polish to the data storage mechanism that takes it from a plain list to an intuitive application.&lt;/p>
&lt;p>If there are any clubs out there that want to work with me on implementing this app at your organisation, particularly charities, give me a shout. I would be happy to help &amp;amp; share the application and spend time installing with you.&lt;/p></description></item><item><title>3 Minute Features : Episode 7 : Forms Pt2</title><link>https://linked365.blog/2020/02/20/3-minute-features-episode-7-forms-pt2/</link><pubDate>Thu, 20 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/20/3-minute-features-episode-7-forms-pt2/</guid><description>&lt;p>This is the second part of the Forms feature, highlighting some useful tips &amp;amp; where to start when Business rules is not enough.&lt;/p>
&lt;h2 id="episode-7-forms-pt2">Episode 7: Forms Pt2&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/DIqKBoJkbGs"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>With forms, if business rules don&amp;rsquo;t meet your requirements, you may have to resort to Javascript. These little code snippets allow you to do pretty much anything on a form that is not possible in business rules, but be warned, Javascript nowadays is frowned upon. It is code for a start, so you need a skilled professional to create and maintain it. Use it as a last resort.&lt;/p>
&lt;p>Each form has a library of files you can upload to it, each file containing one or more functions. Each function needs to be associated with an event, such as the load event of the form or a change event for a field.&lt;/p>
&lt;p>You can also establish form parameters, which can be used by your scripts. Say you want to ensure only if the user comes from another form, you can use this to pass history from the other form.&lt;/p>
&lt;p>Non-event dependencies are a list of fields that are required by scripts. Adding a field to the list locks it to the form.&lt;/p>
&lt;p>Back in the maker experience, there are few nice functions to make your life as a designer easier.&lt;/p>
&lt;p>In the bottom left is a selection which allows you to visualise how your form will look at certain aspect ratios. As this is the new world of unified interface, this form will be rendered on a phone or tablet as well as a desktop. Here, as the form size is changed, the header section is displayed as the first section. Phone is also the size used for the outlook client.&lt;/p>
&lt;p>Header can also be altered, fields added. As you add more than 4 fields, you get a prompt, letting you know that this new field won&amp;rsquo;t be directly visible on the form, but part of the flyout only. Opening the app, you can see this.&lt;/p>
&lt;p>The default option is high density, as we just saw, but you can also choose to untick this to go back to the previous way. This means the fields are editable in the header, but take up more space. Depends on what you want to achieve in your layout. As you can see, as I was in responsive mode, the header gets shifted to the first section of the first tab&lt;/p>
&lt;p>In the user experience, now that we are not in high density mode, the fields in the header are editable directly, with the 5th field being available and editable in the drop down&lt;/p>
&lt;p>There are 4 types of form you can create. We have mostly been working with Main forms, the default wide forms which we are used to.&lt;/p>
&lt;p>Quick view forms are those to show data from a parent entity.&lt;/p>
&lt;p>We can also have Card forms, which appear when the user is displaying a list as a series of cards. Generally, if there is not enough space to render a list properly, the UI will shift to display it as a card view.&lt;/p>
&lt;p>To show this, on the account form, I add a quick view form to the form, choose the related entity and the form to display.&lt;/p>
&lt;p>Also, we can add a new grid to show off the card view. This, as there is little space in the thin column, uses the card view form.&lt;/p>
&lt;p>Quick Create is a form which you first have to enable on the entity by editing the properties of the entity.&lt;/p>
&lt;p>Once enabled, you can create a quick create form, add some fields to it and save.&lt;/p>
&lt;p>When you select quick create on a grid now, it will display a form to the right of the main form, allowing you to quickly add information, and automatically link the new record to the main entity&lt;/p></description></item><item><title>2020 Release Wave 1: Improved Email</title><link>https://linked365.blog/2020/02/19/2020-release-wave-1-improved-email/</link><pubDate>Wed, 19 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/19/2020-release-wave-1-improved-email/</guid><description>&lt;img src="https://linked365.blog/images/2020/02-image-14.png" alt="Featured image of post 2020 Release Wave 1: Improved Email" />&lt;p>Part of the 2020 Wave 1 were some changes to the Email functionality, namely contextual email communication &amp;amp; Easier selection of email templates.&lt;/p>
&lt;p>I have already been through enabling the Wave 1 release &lt;a class="link" href="https://linked365.blog/2020/02/16/2020-release-wave-1-kanban-board/" target="_blank" rel="noopener"
>here&lt;/a>, so won&amp;rsquo;t do that again.&lt;/p>
&lt;h2 id="easier-selection-of-email-templates">Easier selection of Email templates&lt;/h2>
&lt;p>Previously, in an email, you can select the Template box, and it just gives you a selection of the templates.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-7.png?w=408"
loading="lazy"
>&lt;/p>
&lt;p>Once you select the template, this is rendered in the email body.&lt;/p>
&lt;p>Now, in 2020 Wave 1, we get a different popup&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-8.png?w=731"
loading="lazy"
>&lt;/p>
&lt;p>As you select a template, the right pane shows you a preview of the email, including the data that is part of the template being retrieved from the regarding record you created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-10.png?w=718"
loading="lazy"
>&lt;/p>
&lt;p>This is a simple change, but is a great user experience change, particularly where templates are heavily used. No longer will you have to do all those clicks to ensure you have the right template, simple but effective. Well done Microsoft.&lt;/p>
&lt;h2 id="contextual-email-communication">Contextual Email Communication&lt;/h2>
&lt;p>This is another brilliant, quick win. Allowing you to switch between email &amp;amp; the record is excellent enhancement. You need to enable it.&lt;/p>
&lt;p>Start by going to the area selector at the bottom of the site map &amp;amp; select App Settings&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-11.png?w=214"
loading="lazy"
>&lt;/p>
&lt;p>This will open the overview pane, and in the middle of that you can select Manage against Enhanced Email&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-12.png?w=776"
loading="lazy"
>&lt;/p>
&lt;p>Select Yes then Save then go back to an Opp form or anything with a timeline&lt;/p>
&lt;p>Select the little + against the activity timeline, select Email &amp;amp; viola, contextual email&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-13.png?w=217"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-14.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>This little screen is a sort of popup, detached from the opp behind it, but you can interact with the form behind&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-contextual-email.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>See how you can copy and paste information to make a sales or service users life easier.&lt;/p>
&lt;p>You can also navigate to other screens&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-contextual-email-2.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Well played Microsoft, well played.&lt;/p>
&lt;p>Email writing in D365 has always been behind that of Outlook, but this will bea big improvement to a lot of people.&lt;/p></description></item><item><title>2020 Release Wave 1 : Kanban board</title><link>https://linked365.blog/2020/02/16/2020-release-wave-1-kanban-board/</link><pubDate>Sun, 16 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/16/2020-release-wave-1-kanban-board/</guid><description>&lt;img src="https://linked365.blog/images/2020/02-image-6.png" alt="Featured image of post 2020 Release Wave 1 : Kanban board" />&lt;p>On 3rd February, early access to the Kanban board for Opportunities was made available, and as an avid user of Kanban like boards, I thought I would give it a spin. Kanban is a method of visualising and planning activities by their status. In the standard model app you can apply a process to any record, having a step by step guide to your business process.&lt;/p>
&lt;h3 id="update">UPDATE&lt;/h3>
&lt;p>I have been playing with this further, and it seems that there is a large caveat around the process that the Kanban uses, details at the end&lt;/p>
&lt;h2 id="enabling-the-wave-1-early-access">Enabling the Wave 1 Early Access&lt;/h2>
&lt;p>Goto &lt;a class="link" href="https://admin.powerplatform.microsoft.com/support" target="_blank" rel="noopener"
>https://admin.powerplatform.microsoft.com/&lt;/a>, Environments, choose your environment&lt;/p>
&lt;p>On the right hand side, there is now an option to Enable the 2020 Wave 1 Early Access. Here, you can see that I have enabled mine&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;h2 id="enable-kanban-on-opportunity">Enable Kanban on Opportunity&lt;/h2>
&lt;p>The Microsoft documentation &lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365/sales-enterprise/add-kanban-control" target="_blank" rel="noopener"
>here&lt;/a> walks you through the steps. For a new feature, having to resort to using the classic customisation interface is something that goes against the grain.&lt;/p>
&lt;p>Open make.powerapps.com, select Advanced Settings from the cog top right&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-1.png?w=396"
loading="lazy"
>&lt;/p>
&lt;p>This opens the classic interface where you need to go to Settings \ Customise \ Customise the system. You should add this to a solution obviously, but just for PoC.&lt;/p>
&lt;p>Scroll down the entities until you find Opportunity, and select it. The third tab lists the controls that are available to the Opportunity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-2.png?w=809"
loading="lazy"
>&lt;/p>
&lt;p>Select Add Control then scroll down to Kanban, select it then hit Add.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-3.png?w=767"
loading="lazy"
>&lt;/p>
&lt;p>You will then hit Save and Publish.&lt;/p>
&lt;h2 id="displaying-the-kanban-board">Displaying the Kanban board&lt;/h2>
&lt;p>Once this is done, open up the Sales app. Select a view of opportunities. In the top right, select the 3 dots then Show As and choose Kanban.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-5.png?w=381"
loading="lazy"
>&lt;/p>
&lt;p>Once this is done, your Sales process is displayed as columns with each opportunity listed&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2020/02-image-6.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Each column has a count of the number of records and a sum of the estimated revenue for all the records at the status.&lt;/p>
&lt;p>You can search the opportunities like any other view and also change it to display the opportunities by status.&lt;/p>
&lt;p>The 3 fields on each record can be edited on this screen, allowing for quick editing of the key fields. You can drill down into each record which pops the main form into view.&lt;/p>
&lt;p>Each opportunity can be dragged between columns. This triggers the display of the record for you to choose the next stage.&lt;/p>
&lt;h2 id="thoughts">Thoughts&lt;/h2>
&lt;p>It is a great feature that will be handy for teams to quickly see the state of opportunities.&lt;/p>
&lt;p>It is let down by not being able to customise the card display, well I couldn&amp;rsquo;t work it out. You are limited to the owner, estimated revenue and estimated close date. I can understand limiting you to 3 fields, but a customiser should be able to choose. I would assume a card form should be tied to this.&lt;/p>
&lt;p>Also, when you drag and drop, even if you have the required fields, the record is displayed. Not really that quick. I would think that if no fields are required for a particular stage change, it should just happen. A bit fiddly.&lt;/p>
&lt;p>Finally, the adherence to your process is excellent. I added a step to my sales process and it just re-displayed the Kanban board. No effort.&lt;/p>
&lt;p>I am sure this feature will be improved over time, and will be great for those companies that don&amp;rsquo;t customise away from the Microsoft sales process too much.&lt;/p>
&lt;h2 id="default-process-only">Default Process only&lt;/h2>
&lt;p>After working with a client on demoing this in their environment, it became obvious that there is a fundamental caveat with using the Kanban feature.&lt;/p>
&lt;p>If you don&amp;rsquo;t use the standard Opportunity Sales Process, don&amp;rsquo;t expect any use out of the new feature as it stands currently. Only the default process is used.&lt;/p>
&lt;p>I created an idea here &lt;a class="link" href="https://experience.dynamics.com/ideas/idea/?ideaid=2548d535-b154-ea11-b698-0003ff68c1c4" target="_blank" rel="noopener"
>https://experience.dynamics.com/ideas/idea/?ideaid=2548d535-b154-ea11-b698-0003ff68c1c4&lt;/a>&lt;/p></description></item><item><title>3 Minute Features : Episode 6 : Forms Pt1</title><link>https://linked365.blog/2020/02/13/3-minute-features-episode-6-forms-pt1/</link><pubDate>Thu, 13 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/13/3-minute-features-episode-6-forms-pt1/</guid><description>&lt;p>There is a lot you can do with forms in the Modal driven app, so this topic is split into two&lt;/p>
&lt;h2 id="episode-6-forms-pt-1">Episode 6: Forms Pt 1&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/LFajN4gVfno"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>In the solution, select our entity, then forms&lt;/p>
&lt;p>Select the main form. Once the form opens, you can see the fields I have already added.&lt;/p>
&lt;p>I am going to a new tab, then add sections. Sections allow you to add controls linked to the primary record. Each section can have upto 4 columns to display your fields.&lt;/p>
&lt;p>As you drag fields onto the segment, the form renders for you.&lt;/p>
&lt;p>Another form control is the subgrid. A subgrid allows you to display a grid of records, either assocaitated with the main record or defined by a view. If you want to display contacts associated with an account, this is where you would do it.&lt;/p>
&lt;p>Quick View allows you to display the quick form displayed for a parent entity. Approver is a user record and is a parent of our entity. This allows quick display of important data from the parent. The form you choose is defined as any other form, just a special type.&lt;/p>
&lt;p>Depending on the field you add to the form, you can change the control that is used. There are a few controls that Microsoft provide out of the box. Here I have added a numeric field to the form. Under components, you can change the default component to a selection, depending on your business needs.&lt;/p>
&lt;p>Each component will have properties for you to set and configure the interaction. There are a growing number of controls available to you, google pcf gallery.&lt;/p>
&lt;p>Don’t forget about your header and footer as well, drag fields into them. The header tends to be critical information that you can alter, owner status reason etc.&lt;/p>
&lt;p>The footer tends to be more audit information, the current status, who last edited or create the record for example, but this will depend on your requirements.&lt;/p>
&lt;p>Switching to the form we created, you can see the Arc Knob we selected, allows us to point or drag the data entry&lt;/p>
&lt;p>In the new tab we created, you can see the fields that have been rendered. You can also see the subgrid that was added, giving the user the ability to create a new contact or associate this record with an existing record. Hit save and you can confirm that the grid now displays the newly linked record.&lt;/p>
&lt;p> If you noticed on our main tab, there was a large control displaying notes and activities. This is a special section that is really useful and common in D365. To utilise it on your entity, we first have to enable your entity for activities. This is not currently available within the maker experience, so as a customiser, go back to the old method of editing apps and switch to the classic interface&lt;/p>
&lt;p>Select the  Activities check box, which enables your entity to have all the activity types associated with it. Save and close to update the entity.&lt;/p>
&lt;p>If you go to the form now, you will not notice any difference, as again this is a Classic interface only feature currently.&lt;/p>
&lt;p>Opening ithe form in classic mode allows the activity section to be tweaked. You can show Notes or activities or both and a host of additional options including whether to show the filter pane or not.&lt;/p>
&lt;p>Under the activities tab you can select which activity types are visible and which field to sort on. You can also define options to tweak what is displayed to the user and how the user interacts with the form.&lt;/p>
&lt;p>So publishing our form and displaying the content you can see that the user can quickly add a phone call or other activity tab to the entity. This displays in the timeline. Notes can be added straight in the grid. This is also where attachments can be uploaded .&lt;/p></description></item><item><title>3 Minute Features : Episode 5 : Views</title><link>https://linked365.blog/2020/02/06/3-minute-features-episode-5-views/</link><pubDate>Thu, 06 Feb 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/02/06/3-minute-features-episode-5-views/</guid><description>&lt;p>In the fifth installment of this series, I look at views. How to design them and where they are used.&lt;/p>
&lt;h2 id="episode-5-views">Episode 5: Views&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/K6wIdnxP_vs"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>Starting on the entity, go to Views&lt;/p>
&lt;p>This lists all the system views that are associated with our entity. These are generated when you create an entity. Some of them are normal, views that represent data to the user when they view lists. Some have special uses, which I will go through at the end&lt;/p>
&lt;p>Lets start with a new view&lt;/p>
&lt;p>Give your view a name, meaningful for what it will be doing, hit create&lt;/p>
&lt;p>As you can see, it now displays the defualt field of your entity, name. It is also showing you data from your live system, so you can tell if you need to adjust layout to fit your data&lt;/p>
&lt;p>Some fields, the ones that are added by the system, are hidden, so change the selection to All. Then, it is as simple as drag and drop to add a field to the view.&lt;/p>
&lt;p>You can use the drop down on each field to change the width, or drag the handles. You can also drag and drop to change the order. Delete the column by the drop down.&lt;/p>
&lt;p>On the right or on the field, you can define the sorting. This changes the sorting by first ascending then descending if you repeat the action. The sorting is only by fields visible in the view. You can add further sort criteria as well.&lt;/p>
&lt;p>Filtering of the view is fundamental. Select Edit Filters. I want to show only my approvals, then add row. This is a simple field chosen on the entity at the moment. Select the field, then the condition. There are some special ones when working with user records to define it as the current user&lt;/p>
&lt;p>Hit Ok. Notice that the displayed list is filtered straight away, helping you to quickly visualise what it will look like. Back in filters, we can do lots of more advanced filtering, such as filtering on a parent or child entity. We can also group conditions to allow for complicated expressions using Or and And parts.&lt;/p>
&lt;p>Once we are happy, hit save, then publish so we can check it out in our app&lt;/p>
&lt;p>When we got to My Things now, in the view drop down, there is a new selection&lt;/p>
&lt;p>I can chose this and get my filtered list. The end user can add additional filtering as needed or resize columns, but the fundamental filter is kept.&lt;/p>
&lt;p>Back to our maker experience, to add a field from a parent entity, by selecting related. Here I add the primary email of the approver to the view, which allows me to see parent information on the child record. Just that, no child information or many to many information is available.&lt;/p>
&lt;p>Just to show you the lookup view, I connected account to My thing via a relationship. On the account form, the list of fields displayed when selecting my thing is defined as the lookup view.&lt;/p>
&lt;p>Quick view and advanced find are the views used for those particularly capabilities in the app. Feel free, and you should, update these to your business needs.&lt;/p>
&lt;p>Users can also make their own views (subject to permission), by selecting Create View in any view. Their interface is not as pretty as the maker experience, but would assume this is coming.&lt;/p>
&lt;p>They can base the view on an existing view. Then ammend a filter. Hit save, give it a name and close.&lt;/p>
&lt;p>This new view is available under the drop down under My Views.&lt;/p>
&lt;p>If you go back to Create Views, under saved views, select the view you just created and you can hit Share, which allows you to share the view with a colleague or team of colleagues. You can also allow them to edit this view.&lt;/p></description></item><item><title>3 Minute Features : Episode 4 : Business Rules</title><link>https://linked365.blog/2020/01/30/3-minute-features-episode-4-business-rules/</link><pubDate>Thu, 30 Jan 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/01/30/3-minute-features-episode-4-business-rules/</guid><description>&lt;p>Wearing ties is a rule that is just bonkers, and not allowing working from home. Thankfully those in CDS are a little more understandable.&lt;/p>
&lt;p>Welcome to the 4th video in the 3 minute feature series, on Business Rules&lt;/p>
&lt;h2 id="episode-4--business-rules">Episode 4 : Business Rules&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/HNFvild4WUw"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>Starting from the Entity, select Business Rules, Add Business Rule&lt;/p>
&lt;p>At the top is some tools which we will use later&lt;/p>
&lt;p>The first part is a condition, what combination of fields will make the rule trigger. This can be a combination of fields, either both values or one or more of the values&lt;/p>
&lt;p>In my scenario, I am going to worry about the status reason for my thing, mimicking an approval process. So, firstly, is the status reason waiting approval?&lt;/p>
&lt;p>Then our first action. I want to make the Approver field business required, forcing the user to enter a value.&lt;/p>
&lt;p>Next, make the default value of the log field Waiting for approval. Setting values is very limited, you might want a timestamp here, but this is not possible in a rule.&lt;/p>
&lt;p>Next, the 2 approval fields need to be visible, allowing my user to enter the values&lt;/p>
&lt;p>Now I have achieved everything I wanted on this condition, lets move to th e next condition. If it is not &amp;ldquo;waiting approval&amp;rdquo;, check to see if it is approved&lt;/p>
&lt;p>Add a condition to the negative side of the first condition, select eh status reason &amp;amp; a different value&lt;/p>
&lt;p>This time, we want to still ensure the approver and the log are visible, but lock them both, stopping once it is approved anyone changing the value&lt;/p>
&lt;p>But what would happen if the status reason was switched back to waiting approval from approved? The first condition path does not unlock the fields, assumes they are already unlocked. This should be fixed. The business rule editor allows you to copy actions and conditions. Click on the action, select copy.&lt;/p>
&lt;p>The select paste. The rule editor then asks you where to paste it to. Select the + where you want it.&lt;/p>
&lt;p>We want an unlock rather than a lock, so swap over the action.&lt;/p>
&lt;p>Repeat for the log as well.&lt;/p>
&lt;p>We can use this techique to cover all the basis, or the default condition, where it isnt Awaiting approval or approved. Copy the Set Business Required, past on the negative condition. Rename it to show we care about maintenance. Same for the show approver and log actions, with the value set to hide.&lt;/p>
&lt;p>Once we are done, hit save. This runs a validate as well, proving that there are no missing parts to the actions or conditions. You can rename the rule by dropping down the top option.&lt;/p>
&lt;p>This rule is not active yet, we need to activate it, but first the scope has to be considered. Do you want this rule to apply to any time a record is added or updated anywhere in your system, such as imports etc or just when using a form, or just one specific form.&lt;/p>
&lt;p>Finaly, Activate. Once activated, the rule can not be edited, only deactivated.&lt;/p>
&lt;p>This is then ready to be tested.&lt;/p>
&lt;p>I create a new Thing. The default negative path is running now, hiding both the approver &amp;amp; log fields.&lt;/p>
&lt;p>As I change the status reason to Waiting approval, the first postive branch kicks in, showing the 2 fields and making the approver mandatory.&lt;/p>
&lt;p>If I move it to Approved, the approver is locked, but the field remain visible.&lt;/p>
&lt;p>There are a few more options for you in actions, around the suggestions and warnings, so lets edit the rule by deactivating first.&lt;/p>
&lt;p>Lets show an error message to enforce that the approver is required. Against the field and a custom tesxt.&lt;/p>
&lt;p>Also, we can recommend a value in this condition for multiple fields.&lt;/p>
&lt;p>Under details, you can add one ore more defaults for fields, I will just recommend a title for now&lt;/p>
&lt;p>Hit Save, then Activate again and lets see it in action&lt;/p>
&lt;p>Where the status reason is waiting approval now, we get an error on the approver field, alerting us we need to fill that in. Also, there is a little light bulb that appears against Name, if you click on it, there is a button for you to fill in the form with the fields that we set up&lt;/p>
&lt;p>Back to the business rule, there is a snapshot button. This creates a picture of your full business rule to share with others.&lt;/p></description></item><item><title>3 Minute Features : Episode 3: Relationships</title><link>https://linked365.blog/2020/01/23/3-minute-features-episode-3-relationships/</link><pubDate>Thu, 23 Jan 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/01/23/3-minute-features-episode-3-relationships/</guid><description>&lt;p>Relationships are difficult, will she go out with you? Are you good enough? Does he want to propose?&lt;/p>
&lt;p>Those in CDS are a &lt;em>little&lt;/em> less complicated, but only just.&lt;/p>
&lt;p>My next 3 minute feature tries to give you an understanding of relationships&lt;/p>
&lt;h2 id="episode-3-relationships">Episode 3: Relationships&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/oldn4f2lhH8"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>First, lets explain a relationship&lt;/p>
&lt;p>The simpliest relationship there is in the Common data service is account to contact An account can have 0, 1 or more contacts. You could infer properties of the contact to be the same as the account. This relationship in CDS is called a 1 to many relationship if you take the relationship from the prospective of the account.&lt;/p>
&lt;p>From the contact, this is a many to one relationship, as many contacts will be associated with the same account. The same relationship, looking at the contact, would be a many to one relationship&lt;/p>
&lt;p>If, and this is pretty standard, a contact may have a relationship to many accounts, you can create a many-to-many relationship. This way, a intermediary table holds two relationships between the two entities in question.&lt;/p>
&lt;p>Going back to my solution, select my entity I have been creating and then relationships.&lt;/p>
&lt;p>As you can see, there are already a lot of relationships. These are created for you as you created the entity and selected some options. Connected From and To for example is because we ticked the box to Enable connections on the entity.&lt;/p>
&lt;p>Select Add relationship, then start with a Many-to-one. On the right hand side, you firstly need to select the related entity. As we are creating a many-to-one, where MyThing entity is the child, CDS will create a new lookup field on the child entity and give it a name and label both of which you are welcome to change&lt;/p>
&lt;p>In the general section, this is the name of your relationship itself. The default is very long winded, so I would advise to shorten to something more useful.&lt;/p>
&lt;p>Advanced options are where the relationship behaviour is defined. This is a set of options to automatically control the relationship. Parental is the default, but to understand what this means, lets look at all the options available in Custom&lt;/p>
&lt;p>The first is Delete. If the parent entity is deleted, what do you want to happen to the child? Delete the child as well when the business logic does not need orphaned records (for opporunity and opportunity lines for example) . Remove link will just make the child link to the parent null. Restrict will prevent the parent from being deleted if there are active child records present.&lt;/p>
&lt;p>The second is Share. The options here either share the child record with the same as who has just had the parent record shared with them (would work with account and opportunities for example), share only active records with them, share only those records owned by the owner of the parent record. None ensure that the share doesn’t get cascaded.&lt;/p>
&lt;p>Reparent is next, this works exactly the same as share, either changing the owner on all, active or user owned or none of the child records.&lt;/p>
&lt;p>Assignment works the same as share, if the parent record is assigned, do you want to assign all / active / user owned or none of the child records. This could work with tasks associated with cases.&lt;/p>
&lt;p>Finally unshare, which is the opposite of share.&lt;/p>
&lt;p>There are 2 standard options available to you as well, namely Referential and Parental.&lt;/p>
&lt;p>Referential has Cascade None for each of the Assign, Share, Unshare and reparent but with Delete as remove link or restrict&lt;/p>
&lt;p>Parental has Cascade All for all options, including delete.&lt;/p>
&lt;p>A word of caution here, a child entity can have only 1 parental entity, where you can cascade sharing or assigning. If there are 2 relationships, you will have to decide which one is the one you would like to use to cascade logic.&lt;/p>
&lt;p>Relationship configured, I will hit Done. The new relationship is highlighted in bold.&lt;/p>
&lt;p>I will quickly create a many to many relationship. Here after selected the related entity, you get to enter a relationship name as normal (noting the physical table name) and the new entity name you would like to create to serve as your intermediary table. Not there are no behaviour options here.&lt;/p>
&lt;p>Finally through the one to many relationship. This behaves the same as the many to one, but you are creating the lookup field on the child entity, which is the entity you select. You have the option to select behaviour type here as well.&lt;/p>
&lt;p>Hit Save entity to commit your changes to your environment.&lt;/p>
&lt;p>Going back to the solution, you can see it has automatically included the three entities I chose as related entities to my solution, as we are configuring them as well.&lt;/p></description></item><item><title>3 Minute Features : Episode 2 : Fields</title><link>https://linked365.blog/2020/01/16/3-minute-features-episode-2-fields/</link><pubDate>Thu, 16 Jan 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/01/16/3-minute-features-episode-2-fields/</guid><description>&lt;p>This is the 2nd installment of my 3 minute feature videos, going into detail about the different field types, how they appear on the interface and some other useful stuff.&lt;/p>
&lt;h2 id="episode-2-fields">Episode 2: Fields&lt;/h2>
&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/6LRwIyVUo48"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
&lt;h2 id="transcript">Transcript&lt;/h2>
&lt;p>Starting with the new entity I created last time, select new then field.&lt;/p>
&lt;p>This pops up a form to the right, which has a display name and field name for you to enter the detail. The Name can not be changed once you hit save.&lt;/p>
&lt;p>Next is the type, as you ca n see there is a lot of them. To demonstrate each type, I added one of each to a modal form and display on the right how the default for each type behaves.&lt;/p>
&lt;p>There are certain properties for fields that are always present.&lt;/p>
&lt;p>Required ensures that there must be data in this field when saving&lt;/p>
&lt;p>Searchable means that this field is visible for all users who have entity access in views and advanced find. Usually this will be ticked&lt;/p>
&lt;p>Calculated or Rollup Fields allow you to summarise other fields to suit your business needs. This is only the tip of the iceberg and I will do a video on this soon&lt;/p>
&lt;p>Under Advanced options, give your field a description. The other options available depend on the field type you enter.&lt;/p>
&lt;p>Here, a simple text field has a maximum length. Be conservative over your field sizes as a best practice. Text has a max size of 4000 characters.&lt;/p>
&lt;p> On the form this is rendered with only 1 line.&lt;/p>
&lt;p>The Text Area has the same restrictions as Text The designer can decide how many lines to display.&lt;/p>
&lt;p>Email is still a text field in the backend database, but is rendered with a control allowing the user click and email from the page&lt;/p>
&lt;p>The same for URL, popping open the website.&lt;/p>
&lt;p>Ticker Field links directly to the MSN Money website to give a quick view of the stock&lt;/p>
&lt;p>Phone allows interaction with your telephony provider or Teams etc to direct dial the number&lt;/p>
&lt;p>Autonumber effectively gives each record a more user friendly or quotable reference to the record. This is great for case management type activities. You can establish what the prefix is and the number range. It gives you a preview of the format. On the form this &amp;ldquo;number&amp;rdquo; only appears when you save the record.&lt;/p>
&lt;p>The first number format is Whole Number. This does not allow decimal places to be entered and you can also establish a minimum and maximum value which helps with data entry. A warning to the user when the entry doesn’t match is given.&lt;/p>
&lt;p>Duration is a sppecial field which allows the user to select a duration from a drop down, the result is stored as a number in the database.&lt;/p>
&lt;p>Timezone presents the user with a list of international time codes and the database stores just a numeric representation of it.&lt;/p>
&lt;p>Language is similar, with only organisation enabled languages listed&lt;/p>
&lt;p>Date and time presents the user with 3 controls. A date picker and hour and minute drop downs. The Behavaiour option means that the data is stored as a Coordinated Universal Time and translates it to the user current time zone or you can say it is independent of the timezone, recorded and displayed as entered.&lt;/p>
&lt;p>IME Mode is applicable for all text fields, and it allows asian characters sets to be visible or rendered. Very advanced and if it effects you, you will probably already know how to configure it.&lt;/p>
&lt;p>The next type only renders a date picker, but still has the behaviour for time zones&lt;/p>
&lt;p>Currency is a numeric data type, but also creates a couple of extra fields when you hit save.. As the user enters the data, it is saved in the currency selected and also calculated and stored in the base currency of your system. This allows you to rollup opportunities etc in a common currency&lt;/p>
&lt;p>Customer is a special field that can either have a lookup to Contact or Account. The user can choose either. This field is useful for opportunities or other activities where sometimes you may link to one then the other.&lt;/p>
&lt;p>Decimal number allows you to define min &amp;amp; max again, but also how many decimal places These number types are limited to + or - one hundred thousand million, with upto 10 decimal places.&lt;/p>
&lt;p>File is next. File is only used, currently, in Canvas apps and flows, so not on my model driven form. It stores binary data and has a max file size of128Mb. Useful for capturing images, pdfs etc in a Power App.&lt;/p>
&lt;p>Floating point number is very similar to Decimal having the same restrictions, but is only stored as an approximation to your real number. This is done for performance reasons, normally there will be no difference to the end user. On rare occasions when you are dealing with large numbers that this may be of concern&lt;/p>
&lt;p>Lookup field link records together. This creates a parental relationship to the entity you select,This is a simple way of working with relationships, again a topic for a future video.&lt;/p>
&lt;p>Multi-option set is a great tool for data entry. The customiser decides on the options that they want to display and it is presented as a list where they can chose one or more of them. The options are stored globally across your orgainisation, allowing reuse&lt;/p>
&lt;p>Multi line text is for large paragraphs of text. You are limited to a million characters in this.&lt;/p>
&lt;p>Option set is identical to the Multi version, but restricts the user to only one choice.&lt;/p>
&lt;p>And finally two options is a specific option set for yes / no or on / off options. You can establish how these values are displayed, the user toggles between the two.&lt;/p>
&lt;p>Now that we have gone through the options, I&amp;rsquo;ll hit save. At this point, the field is not created. It is highlighted in bold to show those that have not been saved yet. You can go back and tweak the properties before you hit Save Entity&lt;/p></description></item><item><title>3 Minute Features : Episode 1 : Entities</title><link>https://linked365.blog/2020/01/09/3-minute-features-episode-1-entities/</link><pubDate>Thu, 09 Jan 2020 00:00:00 +0000</pubDate><guid>https://linked365.blog/2020/01/09/3-minute-features-episode-1-entities/</guid><description>&lt;p>My hiatus from blogging is due to my lack of creativity around thinking about problems and how to solve them and this got me thinking about a ready source of material that which would give me a infinite number of things to write about.&lt;/p>
&lt;p>As I always want to learn, and envy those that do these things, rather than a blog, I have started a video series which does a show and tell on a subject, in a set time frame.&lt;/p>
&lt;p>Welcome to 3 Minute Feature Thursdays&lt;/p>
&lt;h2 id="episode-1--entities">Episode 1 : Entities&lt;/h2>
&lt;p>&lt;div class="video-wrapper">
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/m72LASzFI3E"
allowfullscreen
title="YouTube Video"
>
&lt;/iframe>
&lt;/div>
//https://www.youtube.com/watch?v=m72LASzFI3E&amp;amp;list=PLm0EQNIOXEnNv34HhDOYP3PNbQqmaGK2Y&amp;amp;index=3&amp;amp;t=4s&lt;/p>
&lt;h3 id="transcript">Transcript&lt;/h3>
&lt;p>Hi and welcome to the first of a hopefully weekly topic on the fundamentals of the Common Data Service.&lt;/p>
&lt;p>There are a lot of blogs and videos out there that are documenting all the changes that are forever coming into the platform, so I thought we should take some time to ensure everyone knows the fundamentals.&lt;/p>
&lt;p>I will be diving into a topic each week in some depth, but trying to do it in 2 minutes. This gives me a timeframe to work to, reduces unnecessary words and hopefully gives a refresher or introduction to the topic in a bite sized portion.&lt;/p>
&lt;p>The first topic is Entities, so here we go&lt;/p>
&lt;p>Firstly, go to make.powerapps.com. Once there, check that you are in the correct environment. This is essential to ensure you are adding components to the right place.&lt;/p>
&lt;p>As with all development, it should start with a solution, so using the menu on the left, select Solutions, and new Solution.&lt;/p>
&lt;p>Give it a name and a publisher, both allow for the ability to differentiate our solutions and to patch solutions as we move the solution between environments for testing etc.&lt;/p>
&lt;p>The default version is 1.0.0.0&lt;/p>
&lt;p>Now hit publish, you can see that the solution is empty, so the next step is to create an entity using the menu top left&lt;/p>
&lt;p>The display and plural names are used by default in lists and records. The Name is the physical table name in SQL, so can not be changed after the entity is created. The name is prefixed with the publisher prefix.&lt;/p>
&lt;p>The primary field is what is selected when the user chooses a record to link 2 records together, like Contact name or company name. You can choose to change the default name and the field name.&lt;/p>
&lt;p>As we go down the properties, those with a little cross next to them can not be changed after you set it. You can set it if it is not set, but once it is set, there is no going back&lt;/p>
&lt;p>A key checkbox is the &amp;ldquo;Enable attachments&amp;rdquo;. This enables the entity for attachments, basically links the notes entity to your new one.&lt;/p>
&lt;p>Description allows your entity to be found later on and should describe it&amp;rsquo;s useage. More documentation the better&lt;/p>
&lt;p>If you change the Entity type to Activity, it will be allowed to be treated as an activity, such as email, tasks or call. Great if your entity is a new version of these things.&lt;/p>
&lt;p>If you want to restrict access to certain records in your entity, like opportunities typically, then ownership needs to be User or Team. Organisation level is used for data shared across your whole system, such as products.&lt;/p>
&lt;p>In the Collaboration section, Allow Feedback links your entity to the Feedback entity, allowing users, external or internal, to feedback and rate a record. Typically used for case or survey scenarios&lt;/p>
&lt;p>In the out of the box, meetings can have followup tasks that are associated with them, if your entity fits into this scenario, then enable this.&lt;/p>
&lt;p>Connections allow a user to link 2 disparate records together, typically used between employees / contacts / accounts to denote relationships.&lt;/p>
&lt;p>If you think that you want to be able to link your entity to incoming emails, then check Send email to Entity. The entity needs at least 1 email field. Leads and contacts are examples of this out of the box.&lt;/p>
&lt;p>Mail merge and sharepoint checkboxes enable the corresponding functionality too. Sharepoint needs more configuration, but here is where you enable each entity.&lt;/p>
&lt;p>Access teams complement the security via ownership. If you enable this checkbox, and set up a template, an access team for each record is automatically created when via code you add your first user to the team.&lt;/p>
&lt;p>Queues are typically used in a service scenario, but allows assignment of your record to a queue to be managed by a helpdesk or group of users.&lt;/p>
&lt;p>Quick create forms are useful in a lot of scenarios, where you want the user to easily create a new record with a subset of all the fields.&lt;/p>
&lt;p>Duplicate detection is common on most records. This setting enables it, but you will have to configure the rules to prevent duplicates.&lt;/p>
&lt;p>Flow change tracking allows Flow to subscribe to &amp;ldquo;When a record is updated&amp;rdquo; triggers on your entity. Essential in most scenarios.&lt;/p>
&lt;p>The final option is enabling your entity for offline outlook. There is a lot more to consider on this, but here is where you start the journey&lt;/p>
&lt;p>Once configured, hit Create and wait. You can go ahead and add fields and other stuff as you wait. Eventually you will be displayed with a nice green banner and a list of the default fields.&lt;/p>
&lt;p>So that’s it.&lt;/p>
&lt;p>Next time, I will dig into Fields, continuing on our journey.&lt;/p>
&lt;p>Please subscribe if you find these useful and provide feedback either via Twitter, LinkedIn or my blog.&lt;/p>
&lt;p>Cheers, see you next week.&lt;/p></description></item><item><title>D365 Org DB Settings - Other</title><link>https://linked365.blog/2019/11/03/d365-org-db-settings-other/</link><pubDate>Sun, 03 Nov 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/11/03/d365-org-db-settings-other/</guid><description>&lt;p>This is the second of a series where I &lt;strong>try&lt;/strong> to document all the rarely used settings available to your Dynamics organisation to tweak the standard behaviour.&lt;/p>
&lt;p>If you want to tweak your settings, see my previous &lt;a class="link" href="https://linked365.blog/2019/10/01/d365-org-db-settings-email/" >post&lt;/a>, or if you want to use a canvas app, see this &lt;a class="link" href="https://linked365.blog/2019/10/16/d365-org-db-settings-canvas-app/" >post&lt;/a>.&lt;/p>
&lt;p>Alternatively, I have created an XrmToolBox tool to do this, documented &lt;a class="link" href="https://linked365.blog/OrgSettingsTool" >here.&lt;/a>&lt;/p>
&lt;h3 id="activityconvertdlgcampaignunchecked">ActivityConvertDlgCampaignUnchecked&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Controls the default value of the Record Closed Campaign Response option. When you&lt;br>convert an activity to an opportunity, this default option controls whether&lt;br>the source campaign is set or not.&lt;br>False- Record Closed Campaign Response checked and source campaign will be set.&lt;br>True&amp;nbsp;- Record Closed Campaign Response not checked and source campaign is not set.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-39.png?w=437"
loading="lazy"
>&lt;/p>
&lt;p>When you convert activity to an opportunity, you have the option to populate a related campaign and also record a closed campaign response. This setting implies that you can default the Record a closed campaign response to true, forcing the selection of a campaign, but in my environment, it isn&amp;rsquo;t working.&lt;/p>
&lt;p>Someone prove me wrong&lt;/p>
&lt;h3 id="activateadditionalrefreshofworkflowconditions">ActivateAdditionalRefreshOfWorkflowConditions&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enables an additional refresh of workflows that contain wait conditions and that may&lt;br>have to be resumed. This is required to be enabled to enable a fix that was originally&lt;br>released as a Critical On Demand hotfix, and was publically released starting with&lt;br>Update Rollup 13. When events in a Wait Until condition are met, the condition is not&lt;br>triggered as documented in KB&amp;nbsp;&lt;a href="https://support.microsoft.com/en-us/help/2918320">2918320&amp;nbsp;&lt;/a>.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3445&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3731&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Redundant fix for what looks like an issue in a specific version&lt;/p>
&lt;h3 id="allowroleassignmentondisabledusers">allowRoleAssignmentOnDisabledUsers&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enables the assignment of a security role for user accounts&amp;nbsp;with a disabled status. This allows for&lt;br>scenarios where&amp;nbsp;stub users can be created and assigned a different security role. This is needed&lt;br>when&amp;nbsp;a stub/disabled user account&amp;nbsp;needs to own records, especially when&amp;nbsp;these records are from&lt;br>custom entities where custom security roles are required.&lt;br>False - By default, a security role cannot be assigned to users with disabled status.&lt;br>This is shipped by default.&lt;br>True - Allows security role to be assigned to users with disabled status.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.5610&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>There are lots of times, particularly around migrating systems, where you are not ready for users to have access to a new system but want to import their data. Think about where you are migrating department by department. The long-term goal would be for users to all have access, so temporarily assigning the records to another user or a system user may not be appropriate. Ownership is usually an indicator and first point of contact in most systems and a driver for security, etc.&lt;/p>
&lt;p>Toggling this setting to true allows assignment of roles, therefore records to disabled or stub users.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-41.png?w=515"
loading="lazy"
>&lt;/p>
&lt;p>Set to false, it displays this error message when you save any changes.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-40.png?w=573"
loading="lazy"
>&lt;/p>
&lt;h3 id="changedoublequotetosinglequote">ChangeDoubleQuoteToSingleQuote&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>false&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes double quotation marks to single quotation marks within KB articles when the article is viewed.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3541&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting will do as it says, convert double quotes to single, but is only relevant for the old Knowledgebase Articles in your system, superseded by Knowledge articles that now have an appropriate WYSIWYG editor, this becomes redundant.&lt;/p>
&lt;h3 id="clearsystemuserprincipalswhendisable">ClearSystemUserPrincipalsWhenDisable&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Clear and/or populates SystemUserPrincipals values for systemUsers when they're disabled/enabled&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.1.1.123&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="clientueipdisabled">ClientUEIPDisabled&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the sending of customer experience feedback for the organization.&lt;br>This option can also be disabled from the user settings area for each user.&lt;br>False&amp;nbsp;- Enables the sending of experience feedback.&lt;br>True&amp;nbsp;- Disables the sending of experience feedback.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9688.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This, apparently, disables the option to send feedback to Microsoft when you get an error, great little setting, but until I get a repeatable error, can not see it in action&lt;/p>
&lt;h3 id="createspfoldersusingnameandguid">CreateSPFoldersUsingNameandGuid&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>True: creates SharePoint folders using the format of {Name}+{GUID}.-&lt;br>false: Creates SharePoint folders using just the name&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>When you integrate SharePoint, a folder in the site is created for each defined entity, normally with the name of the record and a GUID of the record. This can be ugly and not necessary if you have account names that are pretty unique. This setting allows you just to use the record name.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-42.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>This screenshot shows with the setting as the default, true, at the top and the setting as false for JKL Sales&lt;/p>
&lt;h3 id="defaultheightforwizardreports">DefaultHeightForWizardReports&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>8.25&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Double&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>With a default value 0: CRM will use 8.25 inches (A4), any other double value will&lt;br>override the default of 8.25.&amp;nbsp; Some printers may reject printed reports if the&lt;br>height is any less than the height of the paper loaded in the tray, this setting will&lt;br>override the height used&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3541&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Printing can be problematic with different paper sizes etc. Not really a problem with modern printers, but this setting allows you to configure default printing sizes to ensure printing works for your organisation.&lt;/p>
&lt;h3 id="disableiecompatmode">DisableIECompatMode&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes the server-side, automatic, IE Compatibility Mode Flag for Internet Explorer browsers.&lt;br>If you want pages to render in the most recent version of Internet Explorer set this to True.&lt;br>If you have form scripts or other customizations that require earlier versions of&lt;br>Internet Explorer this should be set to False.&lt;br>This is also controlled via Settings | Administration | System Settings | Customization&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3233&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Compatibility mode was a big thing, particularly in the IE10 / 11 era. Making sure your website properly displayed across multiple browsers with inconsistent approaches to standards can still be a big gripe, but thankfully a thing of the past, with modern browsers adhering to standards a lot better.&lt;/p>
&lt;h3 id="disableinactiverecordfilterformailmerge">DisableInactiveRecordFilterForMailMerge&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When you perform a mail merge, inactive records are not included.&lt;br>This option lets you&amp;nbsp;override that functionality.&lt;br>False&amp;nbsp;- Inactive records will not be included in the mail merge.&lt;br>True&amp;nbsp;- Inactive records will be included in the mail merge.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9688.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Mail Merge is a deprecated function, but if you still use it, when you call a mail merge from a campaign, inactive contacts or leads are not included.&lt;/p>
&lt;p>Mail merge is similar to the quick campaign, and I checked that this flag does not override the selection for quick campaigns, but it seems to have no effect.&lt;/p>
&lt;h3 id="enableactivitiestimelineperfimprovement">EnableActivitiesTimeLinePerfImprovement&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>1 to enable, 0 to disable(preserve existing behavior)&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.1639&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>In 2019 Wave 2, October 2019, enhancements were made to the timeline, to improve the density of activities and allowing the user to filter by multiple types etc. Details &lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365-release-plan/2019wave2/dynamics365-customer-service/timeline-usability-enhancements" target="_blank" rel="noopener"
>here&lt;/a>&lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365-release-plan/2019wave2/dynamics365-customer-service/timeline-usability-enhancements" target="_blank" rel="noopener"
>.&lt;/a>&lt;/p>
&lt;p>The new timeline can be seen below, which is toggled with EnableActivitiesFeatures described below. This setting toggles improvements to the performance of the new timeline, which may have an impact on your application.&lt;/p>
&lt;p>Thought the official line is that this is disabled by default, in any new environment it seems to be enabled.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/image-23.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="enableactivitiesfeatures">EnableActivitiesFeatures&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Bitmask to Enable various activities feature in UCI;&lt;br>1 to enable, 0 to disable(preserve existing behavior)&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.1639&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>In 2019 Wave 2, October 2019, enhancements were made to the timeline, to improve the density of activities and allowing the user to filter by multiple types etc. Details &lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365-release-plan/2019wave2/dynamics365-customer-service/timeline-usability-enhancements" target="_blank" rel="noopener"
>here&lt;/a>&lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365-release-plan/2019wave2/dynamics365-customer-service/timeline-usability-enhancements" target="_blank" rel="noopener"
>.&lt;/a>&lt;/p>
&lt;p>The new timeline can be seen below, toggled on and off by this setting.&lt;/p>
&lt;p>Thought the official line is that this is disabled by default, in any new environment it seems to be enabled.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/image-23.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="enablebulkreparent">EnableBulkReparent&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables and reparents using a one record at a time approach&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I am not sure this is relevant any more. I assume this is for where you have large datasets and on premise, that could (with cascading) lead to large data changes for each ownership change, but with my environment, I did not notice any change between the two options.&lt;/p>
&lt;h3 id="enablequickfindoptimization">&lt;strong>EnableQuickFindOptimization&lt;/strong>&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>&lt;br>For more information, see the&amp;nbsp;"Optimizing the Performance of Quick Find Queries"&amp;nbsp;&lt;br>section in the&amp;nbsp;&lt;a href="http://go.microsoft.com/fwlink/?linkid=213093">Optimizing and Maintaining the Performance of a Dynamics CRM 2011 Server Infrastructure&lt;/a>.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Another one I assume has gone the way of the dodo for D365, this was initially configured to roll back the changes made to Quick find back in CRM 2011. I have toggle this on a new system and can not find any effect. This may be because of my minor data load etc and the optimisations that Microsoft has done since 2011.&lt;/p>
&lt;h3 id="enableretrievemultipleoptimization">EnableRetrieveMultipleOptimization&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>For more information, see the&amp;nbsp;"Optimizing the Performance of Queries against&lt;br>Large Datasets section" in the&amp;nbsp;&lt;br>&lt;a href="http://go.microsoft.com/fwlink/?linkid=213093">Optimizing and Maintaining the Performance of a Dynamics CRM 2011 Server Infrastructure&lt;/a>.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.1533&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is another one that is probably redundant for anyone not on CRM 2011, and I would think those that are administering these systems already know about these settings. There is a full table of the configuration for this setting in the linked document, tweaking the way (away from the default) for returning multiple records in a list.&lt;/p>
&lt;p>As I do not have a CRM2011 environment and also don&amp;rsquo;t have the data volumes to see the effect, not sure I can or should add to this.&lt;/p>
&lt;h3 id="exportedexcelretentionwindow">ExportedExcelRetentionWindow&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>5&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>The number of days to temporarily store Excel exported Office Document Records.&lt;br>30 days max was selected arbitrarily as this is only a cache.&lt;br>Must be at least 2.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.1.0.1065&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Learning is great isn&amp;rsquo;t it? Researching this one led me to a great article from &lt;a class="link" href="https://twitter.com/bshastri" target="_blank" rel="noopener"
>Bhavesh Shastri&lt;/a> about the &lt;a class="link" href="https://community.dynamics.com/crm/b/crminthefield/posts/dynamics-365-customer-engagement-orgdborgsettings-configurations-might-affect-instance-size-storage" target="_blank" rel="noopener"
>settings that may affect storage size&lt;/a>, which has this setting in it.&lt;/p>
&lt;p>Basically, when you export a data set into Excel, D365 stores the result in a temporary table so that you can get back to the result quickly. There is a deletion service that goes and tidies up these temporary tables and this setting defines how old these records are before it removes them. If you have a very active system, these records could adversely effect the size of your instance.&lt;/p>
&lt;h3 id="expirechangetrackingindays">ExpireChangeTrackingInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>30&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum number of days to keep change tracking deleted record ID's.&lt;br>You want this value larger than the max# of days any change tracking dependent&lt;br>services sync with your system.&lt;br>Default is 30 days.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.1.0.0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is another storage related one like the previous, again jump over to Bhavesh&amp;rsquo;s &lt;a class="link" href="https://community.dynamics.com/crm/b/crminthefield/posts/dynamics-365-customer-engagement-orgdborgsettings-configurations-might-affect-instance-size-storage" target="_blank" rel="noopener"
>blog&lt;/a> to get more detail. This setting doesn&amp;rsquo;t appear in the Microsoft KB article where the others are, even more confusing and makes me wonder what else Microsoft are hiding&lt;/p>
&lt;p>If you have change tracking services running and worry about deleted records, this setting can be configured to increase the time these records are stored. Obviously, this will impact on storage if nothing else.&lt;/p>
&lt;h3 id="enabletdsendpoint">EnableTDSEndpoint&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enable a SQL TDS Endpoint for your CDS Environment&lt;br>NOTE: your region will also have to support TDS endpoints, the regions with support for TDS may&lt;br>vary (as documented in the docs url provided here).&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.17162&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This, as it says, allows you to enable the CDS SQL TDS Endpoint, which allows you to use SQL Studio to query your live CDS environment. This is only recent, but is a great addition if you need more complexity in your queries.&lt;/p>
&lt;p>&lt;a class="link" href="https://twitter.com/MarkMpn" target="_blank" rel="noopener"
>Mark Carrington&lt;/a> did a great set of posts on it&amp;rsquo;s usage &lt;a class="link" href="https://markcarrington.dev/2020/05/13/cds-t-sql-endpoint-pt-2-first-thoughts/" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;h4 id="forceretrievepublishedmetadataforretrieveallentities">ForceRetrievePublishedMetadataForRetrieveAllEntities&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>All RetrieveAllEntities requests will ignore the AsIfPublished flag so that it always&lt;br>retrieves the published metadata from cache.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.1.1.1020&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h4 id="fulltextspecialcharacterstoremovefromsearchtoken">FullTextSpecialCharactersToRemoveFromSearchToken&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>null&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>string&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>This allows an organization to remove certain characters from a fulltext search string.&lt;br>Example: To remove a wildcard character from a FullText search, add “*”.&lt;br>To remove multiple characters, add them all together in a single string value “*.’#”.&lt;br>The characters are separated by ToCharArray&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.1.1.1020&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="grantfullaccessformergetomasterowner">GrantFullAccessForMergeToMasterOwner&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When two records owned by the same team are merged, the final record is shared with the&lt;br>owner of the record it was merged from. This creates redundant POA records, as a result,&lt;br>if the owner of the record is changed in the future it will be visible to&lt;br>team members of the previously owning team.&lt;br>To do this, set to false.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.4449&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Another one of those security options that most people don&amp;rsquo;t know about. I would hazard to guess that most people don&amp;rsquo;t know that the owner of a subordinate record in a merge has the new master shared with them. Mark Carrington has a great explanation of this setting and the next in his blog &lt;a class="link" href="https://markcarrington.dev/2019/08/31/msdyn365-internals-merge-permissions/" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;p>The default setting puts a row in the Share table for the original owner, even if it is same as the new owner, which is useful in a lot of cases, but also could break your security model if the owner changes again.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-45.png?w=793"
loading="lazy"
>&lt;/p>
&lt;p>With the setting put to false, the original owner does not have the record shared with them&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-44.png?w=838"
loading="lazy"
>&lt;/p>
&lt;p>The wording of this setting implies that only the master owner will have the sharing stopped, but it seems that the original does as well.&lt;/p>
&lt;h3 id="grantsharedaccessformergetosubordinateowner">GrantSharedAccessForMergeToSubordinateOwner&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>To turn this setting off, this must be set to false. Records are shared with inherited access&lt;br>to subordinate owners during merge. This will not occur when set to false.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3911&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>If you have a contact and merge the account, the contact will be moved to be owned by the master owner, but the owner of the contact will have the master record shared with them too. Obviously, this just makes the system work, but doesn&amp;rsquo;t help if you have a specific security prinicple in place.&lt;/p>
&lt;p>Please see Mark&amp;rsquo;s &lt;a class="link" href="https://markcarrington.dev/2019/08/31/msdyn365-internals-merge-permissions/" target="_blank" rel="noopener"
>blog&lt;/a> to fully understand these values.&lt;/p>
&lt;h3 id="hidestageandupgrade">HideStageAndUpgrade&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changing this setting to 0 will allow users to see the upgrade solution option in solution&lt;br>import wizard when importing solutions with higher version than previously imported.&lt;br>This setting has a default of 1 which hides the option to perform a stage for upgrade.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.3&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Back in 2016, Microsoft gave us the ability to stage an upgrade solution, which means we can more easily remove parts of a managed solution, rather that using holding solutions.&lt;/p>
&lt;p>Nishant Rana has an excellent blog &lt;a class="link" href="https://nishantrana.me/2016/10/16/how-to-delete-components-from-managed-solution-in-dynamics-crm-2016-without-using-holding-solution/" target="_blank" rel="noopener"
>here&lt;/a> that describes the process. The process relies on having the Stage for upgrade tick box available to you, which is now hidden by default presumably because Microsoft has provided us the ability to create patches for solutions and it is no longer needed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-47.png?w=547"
loading="lazy"
>&lt;/p>
&lt;h3 id="hierarchylevelforhierarchyfeature">HierarchyLevelForHierarchyFeature&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>3&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>The hierarchy level used for hierarchal security&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Another security tweak. There are 2 security models that may be in use in your instance, namely managerial or positional security.&lt;/p>
&lt;p>Both can take into account a number of managers above you who have the same access to records that you do, which is traditionally 3, and anything above this can cause performance issues. As you can set the hierarchy level on the hierarchy configuration, this setting is now redundant I think, as any change you make to the org setting is not reflected in the setting on the Hierarchy setting screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/wp-content/uploads/2019/11/image.png?w=330"
loading="lazy"
>&lt;/p>
&lt;h3 id="ifdauthenticationmethod">IfdAuthenticationMethod&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>null&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>String&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes the request sent to the ADFS server, this settings default value&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2835&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting is for on premise only, as it defines which SSO an internet facing deployment (an external facing on premise deployment) uses to establish the user has the right access credentials.&lt;/p>
&lt;p>This &lt;a class="link" href="https://community.dynamics.com/crm/b/1984crm/posts/ifd-claims-adfs-what-now" target="_blank" rel="noopener"
>blog&lt;/a> has a more detailed explanation.&lt;/p>
&lt;h3 id="includehtc">IncludeHTC&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>true&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Set whether forms should support HTML component.&amp;nbsp;&lt;br>The CRM 4.0 API uses this feature which is deprecated and will no longer be included&lt;br>after the next major release.&amp;nbsp; If you&amp;nbsp; have javascript code relying on CRM 4.0&lt;br>javascript API's you should enable this and work to update your code to support CRM 2011.&lt;br>This is also controlled via Settings | Administraton | System Settings | Customization.&lt;br>This setting is NOT SUPPORTED IN CRM 2013&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3233&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting is only applicable to CRM 4, I know there are still users out there, but I can not get access to a system to try out this setting &amp;amp; assume even the CRM 4 people won&amp;rsquo;t be using this feature still&lt;/p>
&lt;h3 id="inheritedroleprivilegesfromteamroles">inheritedRolePrivilegesFromTeamRoles&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>true&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the Azure AD Group team functionality of the organization in an event that there is a&lt;br>performance related issue. The Azure AD Group team feature is shipped enabled by default.&lt;br>False - Disable Azure AD Group Team and members of group teams are required to have their&lt;br>own security role assigned to them directly.&amp;nbsp; Run-time calls to Azure AD to obtain the user’s&lt;br>AAD groups are stopped.&lt;br>True - Azure AD GroupTeam is enabled and members of group teams shall inherit user/basic&lt;br>privileges directly and user privileges are derived at run-time.&amp;nbsp; Run-time calls to&lt;br>Azure AD to obtain user’s AAD groups are invoked.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.4632&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Earlier this year, Microsoft gave us the ability to give security permissions to all the members of an Azure AD group, rather than having to duplicate security across Azure and Dynamics. This can be a time consuming god-send for your administrative staff, but also can impact performance. Setting this value to false forces the old method of security, with each user having to be configured with a role in D365.&lt;/p>
&lt;p>Debajit Dutta has an excellent walkthrough on how to utilise this functionality &lt;a class="link" href="https://community.dynamics.com/crm/b/debajitcrm/posts/azure-ad-groups-can-own-your-dynamics-365-records-learn-it-how" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;h3 id="idscountbeforeusingjoinsforsecurity">IdsCountBeforeUsingJoinsForSecurity&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>1000&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Not documented in optimization paper.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h4 id="idscountforusingguidstringsforsecurity">IdsCountForUsingGuidStringsForSecurity&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>20&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Not documented in optimization paper.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="integratedauthenticationmethod">IntegratedAuthenticationMethod&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>null&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>string&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes the request sent to the ADFS server, this settings default value&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2835&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>An On-premise property, which I can not find anything on.&lt;/p>
&lt;h3 id="jumpbaralphabetoverride--jumpbarnumberindicatoroverride">JumpBarAlphabetOverride / JumpBarNumberIndicatorOverride&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>null&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>string&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>&lt;a href="https://support.microsoft.com/help/2494984">How to customize the Alphabet &lt;strong>Bar &lt;/strong>for the CRM Application Grids for Microsoft Dynamics&lt;/a>&lt;br>&lt;a href="https://support.microsoft.com/help/2494984">CRM 4.0&lt;/a>&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2243&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I didnt know this was a thing, but only for CRM 4.0. Basically, you could override what appears at the bottom of a search display.&lt;/p>
&lt;p>Shivam Dixit has a walkthrough &lt;a class="link" href="https://shivamdixit.wordpress.com/tag/jumpbaralphabetoverride/" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;h3 id="listcomponentinstalled">ListComponentInstalled&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>If CRM and SharePoint use ADFS and users click to create a folder for a record in CRM 2011,&lt;br>intermittently, the SharePoint page is shown instead of the list part grid page causing&lt;br>confusion with users. This setting allows you to force CRM to use the installed list grid&lt;br>component in SharePoint when using ADFS.&lt;br>false: use the standard method of detecting Sharepoint Authentication&amp;nbsp;&lt;br>true: If CRM and SharePoint have ADFS enabled, force CRM to use the grid display.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3911&lt;br>6.1.0.581&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This was a bug fix to force display of the SharePoint list instead of the page in a SharePoint created folder when a list is available.&lt;/p>
&lt;h3 id="lookupnamematchesduringimport">LookupNameMatchesDuringImport&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Importing a solution that was created from an upgraded 4.0 deployment fails.&lt;br>Changing this setting makes the import solution look up the names for forms, views,&lt;br>workflows and security roles.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I have no access to CRM 4 to create a solution to test this out, but if anyone can create me screenshots, I&amp;rsquo;ll add in.&lt;/p>
&lt;h3 id="maximumchilduserscountlimitbeforeusingjoinforhsm">MaximumChildUsersCountLimitBeforeUsingJoinForHSM&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>80&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum Child/Subordinate Users Count Before Using a Join Query for Heirarchical Security Model&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>As mentioned, hierarchical security model gives your manager (or managers manager etc) the same access to your data that you have. As a manager with lots of reports, this can cause performance problems, so limiting the maximum unions it makes when deciding on your access makes sense. After this number is reached, an outer join will be used to improve performance.&lt;/p>
&lt;p>If you have scenarios that require that number of child users to a manager, I would recommend not using Hierarchical security.&lt;/p>
&lt;h3 id="minrowcountforfkindexcreateinreferencingentity">MinRowCountForFKIndexCreateInReferencingEntity&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>100&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting min row count in referencing table for ForeignKey index creation&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>In the D365 world, the back end SQL optimisation is out of an administrators hands mostly, with indexes automatically been created for Primary keys or alternative keys for example. This setting tweaks the creation of indexes for FK keys.&lt;/p>
&lt;p>If an account has a foreign key to a location entity, there needs to be more than 100 rows (by default) before the system will create an index on the account table using the location foreign key.&lt;/p>
&lt;h3 id="officedocumentpersistencetimeindays">OfficeDocumentPersistenceTimeInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>7&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>The number of days to temporarily store Office Document Records. 30 days&lt;br>max was selected arbitrarily as this is only a cache.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.1.0.1059&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>When an office document is retrieved from the database, it is stored in the cache, by default for 7 days. This can be altered. This is one option that impacts the size of your tenant.&lt;/p>
&lt;h3 id="pagesizeforhierarchyfeature">PageSizeForHierarchyFeature&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>5&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>The hierarchy page size used for hierarchal security&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I assume that this is used in the same way as the MaximumChildUsersCountLimitBeforeUsingJoinForHSM setting, but I can not find any documentation for it&lt;/p>
&lt;h3 id="reassignallextendedtimeout">ReassignAllExtendedTimeout&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Increase script timeout for reassigning all records of a user or team - this allows you to exceed&lt;br>the default extended timeout value. Default extended timeout is 1000000 ms&lt;br>(roughly 15 minutes).&lt;br>WARNING: Care should be taken when increasing this value above the default -&lt;br>always double check the number of minutes before setting this to a value higher than the default&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.1.2.1020&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>If you have a security model that relies on a cascade of ownership, when a parent owner is changed, this ownership is also done for children and children of children etc.&lt;/p>
&lt;p>This can be a time-consuming process which you can increase the time-out for, possibly temporarily if you have an occasion that required it, though the default 15 minutes is a very long time.&lt;/p>
&lt;h4 id="recordcountlimittoswitchtoctesecuritysql">RecordCountLimitToSwitchToCteSecuritySql&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>75000&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>For more information see the&amp;nbsp;Optimizing the Performance of&lt;br>Queries against Large Datasets"&amp;nbsp;section in the&lt;br>&amp;nbsp;&lt;a class="" href="http://go.microsoft.com/fwlink/?linkid=213093">Optimizing and Maintaining the Performance of a Dynamics CRM 2011 Server Infrastructure&lt;/a>.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I didnt know this was a thing, but only for CRM 4.0. Basically, you could override what appears at the bottom of a search display.&lt;/p>
&lt;p>This setting is for On-premise only, impacting the switching to use a temporary table or CTE (Common Table Expression) to generate the results. I have not got enough data to check if this still has an impact on D365 environments.&lt;/p>
&lt;p>The linked paper has a lot of good stuff about optimisations, that thankfully the more modern SAAS environments have taken care of.&lt;/p>
&lt;h3 id="retrievemultiplesharingcountthreshold">RetrieveMultipleSharingCountThreshold&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>1000&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>For more information, see the&amp;nbsp;"Optimizing the Performance of Queries against Large Datasets&lt;br>section" in the&amp;nbsp;&lt;a href="http://go.microsoft.com/fwlink/?linkid=213093">Optimizing and Maintaining the Performance of a Dynamics CRM 2011 Server Infrastructure&lt;/a>.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is another setting that is for optimisation of the on-premise architecture, defining the number of shared records the user has for the entity being searched for (either direct or via teams) that the system will convert the query to joins rather than table value functions.&lt;/p>
&lt;p>As sharing with individuals should be an increment to your security model rather than the main part, having 1000 shares per entity would be pretty rare.&lt;/p>
&lt;h3 id="securityqueryhint">SecurityQueryHint&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Used to hint the query within GetRightsFromPrincipalObjectAccess.&lt;br>0=None;&lt;br>1=Recompile (default);&lt;br>2=OptimizeForUnkown&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.1.0.141&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I can&amp;rsquo;t find any information on this. Will update when I find out.&lt;/p>
&lt;h3 id="sharinglimitforpoasnapshottable">SharingLimitForPOASnapshotTable&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>10&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Not documented in optimization paper.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I can&amp;rsquo;t find any information on this. Will update when I find out.&lt;/p>
&lt;h3 id="skipaadgroupobjectidvalidation">skipAadGroupObjectIdValidation&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the validation of Azure AD Group objectID and allows application to create Group&lt;br>team in CDS.&amp;nbsp; This is used to mitigate the latency in the Azure AD distributed cache&lt;br>where a newly created Azure AD group cannot be validated if the subsequent&lt;br>Azure AD Group graph call goes to a distributed cache server that does not&lt;br>have the new Azure AD group yet.&lt;br>False - do not skip Azure AD group objectID validation during Group Team creation.&amp;nbsp;&lt;br>This is shipped by default.&lt;br>True - skip Azure AD group objectID validation to allow application to create Group team.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.5808&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>If you use the new functionality to connect teams to AD groups, allowing a single location to manage security, setting up the teams needs a link back to the AD group.&lt;/p>
&lt;p>As AD group creation takes time to propagate to the various caches, the group you want to link to might not be available, so, by default, no check is made to see if you have got the GUID right. This can be forced if you need that extra piece of mind by setting this value true.&lt;/p>
&lt;h3 id="skipgettingrecordcountforpaging">SkipGettingRecordCountForPaging&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the record count query. This query is responsible for retreiving the total number of records returned for each view.&lt;br>This query can cause longer search times and may cause SQL timeouts or exceptions.&lt;br>False&amp;nbsp;- Enables record depend on views.&lt;br>True&amp;nbsp;- Disables record depend on views.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.0.0503&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>When you have a large dataset, knowing that you have thousands of records rather than just the 100 the view is showing is invaluable, but this query has to be done, as well as the query to retrieve the data, impacting performance&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/wp-content/uploads/2019/11/annotation-2019-11-03-143906.png?w=292"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/wp-content/uploads/2019/11/image-1.png?w=306"
loading="lazy"
>&lt;/p>
&lt;p>With the setting applied, the query doesn&amp;rsquo;t display an accurate number, but it does display a number, which is mis-leading in my opinion.&lt;/p>
&lt;h4 id="skipgettingrecordcountforpagingforaudit">SkipGettingRecordCountForPagingForAudit&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disabled the record count query for just the Audit entity.&lt;br>False enables the record count, and True disables the record count&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.0.0503&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is the same as the previous setting, but just for the auditing views, which are notoriously large.&lt;/p>
&lt;h2 id="skipsuffixonkbarticles">SkipSuffixOnKBArticles&lt;/h2>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the suffix from being used on the automatically generated KB article numbers.&lt;br>False&amp;nbsp;- Enables the suffix on KB articles.&lt;br>True&amp;nbsp;- Disables the suffix on KB articles.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.1992&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Pretty self-explanatory, but for old KB articles rather than the new Knowledge Articles.&lt;/p>
&lt;h3 id="tabletclientmaxfields">TabletClientMaxFields&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>75&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum Tablet Fields max-500/ min- 1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>These tablet settings are not for D365, v9 as Unified interface has removed the limitations&lt;/p>
&lt;h3 id="tabletclientmaxlists">TabletClientMaxLists&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>10&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum Tablet Lists max-50/min-1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>These tablet settings are not for D365, v9 as Unified interface has removed the limitations&lt;/p>
&lt;h3 id="tabletclientmaxmashups">TabletClientMaxMashups&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>3&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum Tablet Mashups&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>These tablet settings are not for D365, v9 as Unified interface has removed the limitations&lt;/p>
&lt;h3 id="tabletclientmaxtabs">TabletClientMaxTabs&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>5&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Maximum Tablet Tabs max-50/min-1&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>These tablet settings are not for D365, v9 as Unified interface has removed the limitations&lt;/p>
&lt;h3 id="tracelogpersistencetimeindays">traceLogPersistenceTimeInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>30&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>This sets the amount of time that TraceLog data is maintained before being removed by the Deletion Service&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.1.1.1020&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is another setting that can impact the size of your instance. The logs are stored by default for 30 days, if you have a heavily used system, this will be a lot of data, so reducing this will reduce costs. Trace logs are part of a separate pricing tier now, but still worth a look.&lt;/p>
&lt;h3 id="useorganizationserviceformultientityquickfind">UseOrganizationServiceForMultiEntityQuickFind&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Allows Multi-entity Quick Find to run serially rather than in parallel.&lt;br>This allows plugins to be executed on RetrieveMultiple.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.1.0135&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Retrieve multiple plugins can do a little more security to prevent the display of records or adding in data to a record set if you need it to be really truly accurate.&lt;/p>
&lt;p>Whilst this is frowned upon as is a real impact on system performance, it might be necessary. If you need this functionality, quick view doesn&amp;rsquo;t honour this logic as the queries run in parallel. Toggling this to true makes each quick query run in serial, allowing retrieve multiple plugins to work.&lt;/p>
&lt;h3 id="workflowxamlvalidationerrorreport">WorkflowXamlValidationErrorReport&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>WorkflowXamlValidationErrorReport is used to fail workflow loads if the XAML is not valid&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.5808&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I can&amp;rsquo;t find any information on this. Will update when I find out.&lt;/p></description></item><item><title>D365 Org DB Settings - Canvas App</title><link>https://linked365.blog/2019/10/16/d365-org-db-settings-canvas-app/</link><pubDate>Wed, 16 Oct 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/10/16/d365-org-db-settings-canvas-app/</guid><description>&lt;img src="https://linked365.blog/images/2019/10-image-28.png" alt="Featured image of post D365 Org DB Settings - Canvas App" />&lt;p>On the back of one of my other posts on the &lt;a class="link" href="https://linked365.blog/2019/10/01/d365-org-db-settings-email/" target="_blank" rel="noopener"
>D365 Org DB Settings&lt;/a> I thought it would be good to re-imagine the method to update these settings in a Canvas app.&lt;/p>
&lt;p>The solution from Sean McNellis is great and has been a big influence on my design, including the settings xml is pretty much a copy. I am hoping that I give users a more visual experience and this is a starter for a bunch of D365 CE admin apps in PowerApps.&lt;/p>
&lt;p>I am now looking for people to test it and give me feedback on the solution, so if anyone has a little time to be critical, please contact me on the blog, via Twitter or on GitHub as an issue.&lt;/p>
&lt;p>&lt;a class="link" href="https://github.com/CooksterC/D365-Admin-Tools" target="_blank" rel="noopener"
>https://github.com/CooksterC/D365-Admin-Tools&lt;/a>&lt;/p>
&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-28.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Hope you like green&amp;hellip;.&lt;/p>
&lt;p>On the left is a list of the options for configuration. By default, it only shows the ones that are already configured, but we can alter this to show all settings by toggling the top button. You can also search at the top for the setting you want.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-29.png?w=872"
loading="lazy"
>&lt;/p>
&lt;p>The list is also colour coded, to highlight the ones you have changed, the ones that are configured already and the ones that have no setting.&lt;/p>
&lt;p>The grid shows the official documentation of the setting and a link to the KB article.&lt;/p>
&lt;p>The Bin button will remove this setting from your configuration, returning it to the default.&lt;/p>
&lt;p>The + button will add the setting to your configuration using the default value.&lt;/p>
&lt;p>The Value entered can be different controls depending on the value been configured.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-30.png?w=837"
loading="lazy"
>&lt;/p>
&lt;p>At the top right, you can save any configuration changes, which refreshes the list and the bottom right panel, which shows the current configuration&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-31.png?w=770"
loading="lazy"
>&lt;/p>
&lt;p>The top panel will display the documentation on the settings. There is also the ability to copy a configuration from another system or manually edit the xml.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-32.png?w=741"
loading="lazy"
>&lt;/p>
&lt;p>NO WARRANTIES GIVEN. If you get this wrong, then don&amp;rsquo;t blame me!&lt;/p>
&lt;h2 id="installation">Installation&lt;/h2>
&lt;p>The package is a solution, with 2 components, the Canvas App and a custom connector.&lt;/p>
&lt;p>As part of the app, the settings xml is cleared before it replaces with the new configuration, using the standard connector gives an error when this is done, so I reverted to doing this via a custom connector. Also, the settings are reliant on the version of your D365, less of an issue now that everyone is on the same version, but for those on premise, the version is required, again not available in a normal connector.&lt;/p>
&lt;p>I have found that if I include that in a solution, it has the intended effect of bringing with it the connection to the api that it is configured for. This is great for deploying apps using a common api, but in this scenario, I don&amp;rsquo;t want you to use my tenant, but your own. Not sure how this could be improved, particularly for ISVs etc. Also, as the solution matures, everytime you import the solution, the connector needs reconnecting, which isn&amp;rsquo;t ideal.&lt;/p>
&lt;p>So there is 2 parts, the Canvas App exported as a package and the connector.&lt;/p>
&lt;h2 id="connector-configuration">Connector Configuration&lt;/h2>
&lt;p>Select New Custom Connector / Import as OpenAPI file&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-36.png?w=370"
loading="lazy"
>&lt;/p>
&lt;p>Put in your environment link here. This is mine, and the solution method of connectors copies these settings, thankfully it is OAuth, so unless you know my password (and this is a trial).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-33.png?w=586"
loading="lazy"
>&lt;/p>
&lt;p>Next is security. Edit the OAuth 2.0 settings.&lt;/p>
&lt;p>You need to enter the Client Id and Client Secret taken from the Azure AD authentication as well as the Resource URL being the address of your environment.I stepped through this when I created my first custom connector for &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365/" target="_blank" rel="noopener"
>LUIS&lt;/a> integration.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-34.png?w=554"
loading="lazy"
>&lt;/p>
&lt;p>Update the connector and move on to testing.&lt;/p>
&lt;p>I have only got 3 actions defined here, keeping it to the actions I need for the application and WhoAmI, which is so simple, allows me to confirm the connection prior to worrying about syntax.&lt;/p>
&lt;p>As this is OAuth, you need to configure a connection, which is a prompt for you enter your credentials.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-35.png?w=537"
loading="lazy"
>&lt;/p>
&lt;p>Test the operation to prove you have got your connector up and running.&lt;/p>
&lt;h2 id="install-the-canvas-app">Install the Canvas App&lt;/h2>
&lt;p>Got to your apps and select Import package. Select the zip file from GitHub repository.&lt;/p>
&lt;p>The first time you install, it has nothing to update, so you will need to change the action to &amp;ldquo;Create as new&amp;rdquo; and give it a new name if you don&amp;rsquo;t like it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-37.png?w=363"
loading="lazy"
>&lt;/p>
&lt;p>On the connector, you should connect it to the one that has just been created&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-38.png?w=1010"
loading="lazy"
>&lt;/p>
&lt;p>Hit import and you are done! Run the app to see a default configuration.&lt;/p>
&lt;p>Like I have said, I would like feedback, particularly on how to improve the installation process. It is rather fiddly, would love to be able to just install a solution and you are done.&lt;/p></description></item><item><title>IFTTT - Stopping Freezer melt</title><link>https://linked365.blog/2019/10/07/ifttt-stopping-freezer-melt/</link><pubDate>Mon, 07 Oct 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/10/07/ifttt-stopping-freezer-melt/</guid><description>&lt;img src="https://linked365.blog/images/2019/10-image.png" alt="Featured image of post IFTTT - Stopping Freezer melt" />&lt;p>I have a problem, well my family has a problem. We can&amp;rsquo;t shut the freezer door. Regularly (once a month) our freezer would be left open just enough to defrost but not enough to sound the audible alarm, resulting in squishy food.&lt;/p>
&lt;p>Annoying.&lt;/p>
&lt;p>To combat this, I bought myself a &lt;a class="link" href="https://sonoff.tech/product/wifi-diy-smart-switches/th10-th16" target="_blank" rel="noopener"
>Sonoff TH10&lt;/a> temperature sensor and configured this to send me an alert when it reached a certain temperature. The problem is I became blase to the alert, as it would go off as soon as someone opened the door or was not around to react. The module would only alert me once, when a warm temperature was reached, not keep reminding me or escalate to someone else when I didnt react by shouting at a teenager to close the door. So how could I ensure it alerted me less frequently and also alert the rest of the family when there was a real issue?&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image.png?w=862"
loading="lazy"
>&lt;/p>
&lt;p>I know that this article is a little bit of fun with no real business benefit, but using Flow to fix a problem in my life is worth talking about. Everyone will have a little annoyance that Flow can help with, and it acts as a training exercise for us all.&lt;/p>
&lt;h2 id="design">Design&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-1.png?w=458"
loading="lazy"
>&lt;/p>
&lt;p>As with all problems, starting with a flow chart helps. This is what I need to achieve. The Sonoff device is configured to turn on and off when a certain temperature is hit. IFTTT is triggered by Sonoff on both of these conditions.&lt;/p>
&lt;p>When the hot temperature is hit, wait 30 minutes (to allow for the temp change when a door is opened and closed naturally) then check if freezer is still is over temperature. If it is still hot, send out a notification.&lt;/p>
&lt;p>Then, wait 60 minutes now and check again if the temperature is too high, before repeating the loop, sending out a further notification and waiting 60 more minutes.&lt;/p>
&lt;p>If we check the temperature and it is now back down to cold, stop the process.&lt;/p>
&lt;h2 id="ifttt-configuration">IFTTT configuration&lt;/h2>
&lt;p>If you don&amp;rsquo;t know the &lt;a class="link" href="https://ifttt.com/" target="_blank" rel="noopener"
>IF This Then That,&lt;/a> it is a great service to interact with disparate systems, a point-to-point integration to do something on a trigger. I have used it previously to &lt;a class="link" href="https://linked365.blog/2019/05/04/ifttt-flow-d365/" target="_blank" rel="noopener"
>log Sales users calls&lt;/a> from an android phone and I use it to change my phone&amp;rsquo;s background with the NASA wallpaper of the day. It is a free service which plugs the gaps where Flow does not have direct connections, such as with the Sonoff device.&lt;/p>
&lt;p>Sonoff can trigger IFTTT, which in turn can trigger a web service, triggering the Flow.&lt;/p>
&lt;p>Log into IFTTT and link your account to eWeLink (this is the app you install to manage the Sonoff switches).&lt;/p>
&lt;p>Select Create from your account&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-2.png?w=455"
loading="lazy"
>&lt;/p>
&lt;p>This presents you with the standard IFTTT applet creator.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-3.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Hit the big + to display all the available services, eWeLink should be on that list.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-4.png?w=868"
loading="lazy"
>&lt;/p>
&lt;p>Next, you get a long list of the options eWeLink make available for you, this is where you need to select the appropriate switch, for me just a single channel switch.&lt;/p>
&lt;p>Next step is to select your switch, named by you when you configure it in the eWeLink app, and whether you want this to be triggered when it is switched On or Off. For me, On means that the Freezer has gone below -20 ° C. Off means it has gone above -17 ° C.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-5.png?w=513"
loading="lazy"
>&lt;/p>
&lt;p>IFTTT then needs to know what to do.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-6.png?w=1002"
loading="lazy"
>&lt;/p>
&lt;p>Hitting the big + again lists the action services, the one we want is a WebHook.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-7.png?w=815"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-8.png?w=353"
loading="lazy"
>&lt;/p>
&lt;p>Next, the action requires a URL, which is from our Flow, so skip to that bit to get the URL, we aren&amp;rsquo;t posting anything to this hook, just a trigger. You could secure this a little more to pass in a key to know it is you that is triggering it.&lt;/p>
&lt;h2 id="flow-configuration">Flow Configuration&lt;/h2>
&lt;p>Our flow starts with a web trigger.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-9.png?w=501"
loading="lazy"
>&lt;/p>
&lt;p>I am passing a delay to the trigger, though the initial call will not have any delay.&lt;/p>
&lt;p>Next, initialise a variable for checking the freezer later as well as an ID for the SharePoint Item I will create later.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-13.png?w=497"
loading="lazy"
>&lt;/p>
&lt;p>If this has come from the initial IFTTT trigger, then we assume the delay is 30 minutes. You could just update a delay variable, but as you will see, I want to do something different if I am passed a delay, the second time we call it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-11.png?w=533"
loading="lazy"
>&lt;/p>
&lt;p>In the yes branch, we now wait for the default 30 minutes.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-12.png?w=564"
loading="lazy"
>&lt;/p>
&lt;h2 id="cancelling-the-flow">Cancelling the Flow&lt;/h2>
&lt;p>Now, according to our design, we need to check the temperature to see if it has dropped back below our trigger point.&lt;/p>
&lt;p>Ideally, you would call the Sonoff and ask for a reading, and I am sure more expensive IoT devices allow you to do this, but I am cheap. The Sonoff and eWeLink interfaces allow you to look at the temperature on your phone, but do not broadcast the temperature out to anyone apart from the App, just the on / off trigger. Checking the temperature is not an option.&lt;/p>
&lt;p>What about creating another trigger to turn off this looping? Unfortunately, this isn&amp;rsquo;t possible; there is an idea on the flow community; you can vote for &lt;a class="link" href="https://powerusers.microsoft.com/t5/Flow-Ideas/Terminate-a-single-running-flow-from-Flow/idc-p/376465#M16692" target="_blank" rel="noopener"
>here&lt;/a>. I would also like to be proven wrong, reach out if there is a way to cancel a flow run.&lt;/p>
&lt;p>I started doing this by adding a file in a Google drive location (it could be SharePoint or OneDrive but wanted to expand my use of connectors) when the temperature went down, but this was inconsistent. I ended up getting multiple emails as the file create did not happen every time. I am sure I could sort this out, but wasn&amp;rsquo;t really the point of the flow.&lt;/p>
&lt;p>I ended up with creating an item in a SharePoint List when the flow was first triggered, complete the delay and check this item to see if another process has updated the same item while I was in pause mode. If that item has been updated, just stop the Flow. If it hadn&amp;rsquo;t send the email alert and trigger the flow again, to repeat the process.&lt;/p>
&lt;p>First, create the item in SharePoint, with the current time (this is just for my interest, knowing how many times it triggers the freezer temp)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-15.png?w=514"
loading="lazy"
>&lt;/p>
&lt;p>The Id of the item that is created is copied so we can pass it to the next iteration of the flow if needed.&lt;/p>
&lt;p>After the delay, check the item that was created for a cold temperature. Using a bit of odata filtering here to only return the item that was just created and only if there is no cold time.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-16.png?w=522"
loading="lazy"
>&lt;/p>
&lt;p>This Scope useage is only to allow me to copy the contents to the other branch, saving me time. The copy function is really useful, if you havent seen it, why not?&lt;/p>
&lt;p>Next, if any items are returned (the item that was created was updated with a cold temperature), the title is changed to Cancelled. This is not really needed, but gave me something to do in the apply for each. The boolean is set to true, meaning Freezer is now cold and this flow can cancel itself.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-17.png?w=511"
loading="lazy"
>&lt;/p>
&lt;p>Out of the loop, check the value. If the previous loop did anything, it will be true, if not false. If the freezer is now cold, just terminate gracefully. If it has not updated the temperature, let it fall through to the next action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-18.png?w=764"
loading="lazy"
>&lt;/p>
&lt;p>The final part of the original check to see if it sent a delay count is to email. In this no delay sent path, an email is just sent to me. I am using Gmail here, just because it was a new connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-19.png?w=517"
loading="lazy"
>&lt;/p>
&lt;p>Finally, call the same flow but pass in the delay we want and the Id of the SharePoint item that was created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-22.png?w=494"
loading="lazy"
>&lt;/p>
&lt;h2 id="what-about-if-it-gets-really-serious">What about if it gets really serious?&lt;/h2>
&lt;p>Telling me if the freezer has been open is fine, it usually results in a yell to a teenager to shut the f**king door. What about if I am not in?&lt;/p>
&lt;p>After the first 1/2 hour delay, if the freezer is still showing hot, I need to escalate, for me means emailing my whole family. In the No branch, I delay for whatever value was sent in, set a variable to pass on to the next iteration and do the same code as in the other branch, the difference is that I include more people on the next email.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-23.png?w=522"
loading="lazy"
>&lt;/p>
&lt;p>Here, I email all my family, with a nice in your face subject and also hike up the importance. Hopefully, they won&amp;rsquo;t ignore this email like they ignore me.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-24.png?w=585"
loading="lazy"
>&lt;/p>
&lt;h2 id="triggering-when-it-is-cold">Triggering when it is cold&lt;/h2>
&lt;p>Using IFTTT the same as I have done early on, if the temperature hits -20 ° C, the second trigger is fired. This updates any items it finds in the list without a cold temperature with the trigger time&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-25.png?w=512"
loading="lazy"
>&lt;/p>
&lt;p>And that&amp;rsquo;s it.&lt;/p>
&lt;p>In my inbox, after I have taken the temperature controller out of the freezer for a little while, I get a series of Freezer is hot messages, also sent to the rest of the family.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-26.png?w=912"
loading="lazy"
>&lt;/p>
&lt;p>Once it gets back in, the notifications stop.&lt;/p>
&lt;p>And in SharePoint, there is a list of the hot &amp;amp; cold triggers, from natural door opening, thankfully&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-27.png?w=1005"
loading="lazy"
>&lt;/p></description></item><item><title>D365 Org DB Settings - Email</title><link>https://linked365.blog/2019/10/01/d365-org-db-settings-email/</link><pubDate>Tue, 01 Oct 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/10/01/d365-org-db-settings-email/</guid><description>&lt;img src="https://linked365.blog/images/2019/10-image-71.png" alt="Featured image of post D365 Org DB Settings - Email" />&lt;p>On a client recently I helped deploy Microsoft D365 App for Outlook. Unfortunately, the behaviour requested by the client and the default behaviour of the Server Side synchronisation was not aligned.&lt;/p>
&lt;p>This led to long discussions with Microsoft about some of the DB Org Settings we could utilise to tweak the way SSS works. As I researched these settings and discussed with my colleagues and during networking events, it became clear they remain unknown to most developers and administrators. If your deployment needed to tweak the settings, then people knew, but it is not common knowledge.&lt;/p>
&lt;p>Further, there seemed to be very little documentation on what each setting does, apart from Microsoft&amp;rsquo;s own information &lt;a class="link" href="https://support.microsoft.com/en-us/help/2691237/orgdborgsettings-tool-for-microsoft-dynamics-crm" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>This is a series of posts explaining each of the Org settings, understanding how it affects your environment. Hopefully it will raise awareness of these settings.&lt;/p>
&lt;p>Bear in mind that there a lot of settings that I can not find any information on or have no experience on. This is frustrating for me, but assume someone in the community will push me in the right direction and I will update the page when I find out.&lt;/p>
&lt;h2 id="how-to-change-org-db-settings">How to Change Org DB Settings&lt;/h2>
&lt;p>&lt;a class="link" href="https://twitter.com/seanmcne" target="_blank" rel="noopener"
>Sean McNellis&lt;/a> has an excellent tool on GitHub &lt;a class="link" href="https://github.com/seanmcne/OrgDbOrgSettings" target="_blank" rel="noopener"
>here&lt;/a> which allows interaction with the org settings via a solution in your environment.&lt;/p>
&lt;p>One the solution is imported, selecting the solutions gives you an interface where you can check the current status of each setting and change them.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/10-image-71.png?w=902"
loading="lazy"
>&lt;/p>
&lt;p>To change the default, you need to select the Add hyperlink. This creates an XML file including your property which is uploaded to your system to change the setting.&lt;/p>
&lt;p>Selecting the Edit link for the attribute now gives you a popup window, where you can edit the value&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-72.png?w=435"
loading="lazy"
>&lt;/p>
&lt;p>Also, Sean has included a copy of the Microsoft description with each setting.&lt;/p>
&lt;p>On the right side of the grid is a link to to the KB article that mentions the setting, though normally it is just to KB 2691237 which is the central list of all Org settings.&lt;/p>
&lt;h3 id="activityrollupchildrecordlimit">ActivityRollupChildRecordLimit&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>50,000&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Limit the number of total aggregated activities to rollup in the Activity Rollup&lt;br>Default:50,000.&lt;br>Used with: VisibleRecordThreshholdSwitchToMultiplelineTVF&lt;br>and TotalRecordThreshholdSwitchToMultiplelineTVF&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.8031&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is a new one on me. Activities roll up. You put an email against a contact, the email is available on the account the contact is associated with. This applies to custom entities as well, if you configure the relationship correctly. Inogic has a great post on it &lt;a class="link" href="https://www.inogic.com/blog/2017/01/configure-rollup-view-for-activities-with-dynamics-crm365/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>This setting must have come about to limit this as the numbers where getting too big for some. I have not got the data to do this one justice unfortunately.&lt;/p>
&lt;h3 id="addressbookmaterializedviewsenabled">AddressBookMaterializedViewsEnabled&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes the way the CRM Client queries SQL CE&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2903&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>The description doesnt tie up with the title, and when you google it, this setting revolves around a previous setting, Disable MAPI cache, that was around in CRM 2011 and helped improve performance. Not a lot more I can say.&lt;/p>
&lt;h3 id="allowpromoteduplicates">AllowPromoteDuplicates&lt;/h3>
&lt;p>Duplicates in D365 are not unheard of, but when Outlook sync comes in, there are more chances to get duplicates. When a user syncs an Outlook Contact,&lt;/p>
&lt;h3 id="allowsaveasdraftappointment">AllowSaveAsDraftAppointment&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting value to true will provide the capability to create appointments in Dynamics 365&lt;br>as “draft” without synchronizing with Exchange.&lt;br>Appointment form will have a “Save as Draft” command and a “Send” command, so that you&lt;br>can save, add details and update an appointment activity without synchronizing to Exchange.&lt;br>Default value is set to false to preserve existing behavior.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>&lt;br>9.0.2.2275&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This flag opens up the possibility that you don&amp;rsquo;t always get a meeting correct the first time and allows you to save a draft.&lt;/p>
&lt;p>Ulrik Carlsson aka &lt;a class="link" href="https://twitter.com/crmchartguy" target="_blank" rel="noopener"
>@CRMChartGuy&lt;/a> from eLogic solutions has a great article about this attribute.&lt;/p>
&lt;p>The default behaviour is that users are not presented with a Save as Draft option for appointments, when a appointment is saved, if you are using SSS it will synchronise to Outlook and send out invites to the attendees as normal.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-74.png?w=619"
loading="lazy"
>&lt;/p>
&lt;p>If you change AllowSaveAsDraftAppointment to true, the users get a different set of buttons.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-75.png?w=737"
loading="lazy"
>&lt;/p>
&lt;p>Both Send and Send &amp;amp; Close buttons behave like the original Save and Save &amp;amp; Close. They will initiate a server side sync one the record is saved.&lt;/p>
&lt;p>The new button Save as Draft will save the appointment but not send it to Outlook etc. It adds a [Draft] prefix to the appointment header and also a new field on the appointment, isdraft, is populated with true.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-76.png?w=532"
loading="lazy"
>&lt;/p>
&lt;p>Weirdly, this field can not be added to a form. It just doesn&amp;rsquo;t appear in the field list. You can add it as view filter criteria, but you can&amp;rsquo;t display it as a column in a view.&lt;/p>
&lt;h3 id="heading">&lt;/h3>
&lt;p>AutoCreateContactOnPromote&lt;/p>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the ability of the organization to create contact records automatically when an email&lt;br>message is tracked in CRM. This option can also be disabled from the user settings area&lt;br>for each user.&lt;br>False&amp;nbsp;- Disables the automatic creation of contacts.&lt;br>True&amp;nbsp;- Enables the automatic creation of contacts.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9688.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>By default, when a user sets regarding within the Outlook app, if any email address is in the To / CC / BCC etc that D365 does not know about, it creates it automatically.&lt;/p>
&lt;p>Most of the time this is fine, but consider when your business process requires a lot more data fields to be populated in the contact, this default process will create a contact that hasn&amp;rsquo;t got what your business needs. Forcing the contact creation away from this automation may be required.&lt;/p>
&lt;p>Users have an option under their personal settings which will mimic this settings, but this does it for everyone.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-77.png?w=728"
loading="lazy"
>&lt;/p>
&lt;p>Setting the AutoCreateContactOnPromote to false removes the option from users and no contacts are created automatically when emails etc are synced.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-78.png?w=907"
loading="lazy"
>&lt;/p>
&lt;h3 id="autotracksentfolderitems">AutoTrackSentFolderItems&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting value to TRUE will result in Server Side Sync auto tracking of emails from Sent Items.&lt;br>This setting only applies if the mailbox is configured to track "All Email Messages"&lt;br>Default value is set to False to preserve the existing behavior.&lt;br>To enable functionality on the organization "AutoTrackSentFolderItems" should be set to True.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.0840&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting works in hand with the selected option under &amp;ldquo;Select the email messages to track in D365&amp;rdquo; option under Personal Options.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-79.png?w=772"
loading="lazy"
>&lt;/p>
&lt;p>By default, sent emails are ignored, only picking up emails that arrive to send to D365.&lt;/p>
&lt;p>By marking the AutoTrackSentFolderItems to true, sent items will also be tracked, from the next sync, not retrospectively&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-80.png?w=386"
loading="lazy"
>&lt;/p>
&lt;h3 id="backgroundsendbatchsize">BackgroundSendBatchSize&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>10&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Integer&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Sets the number of email messages to download in one batch for the BackgroundSend API.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="clientdisabletrackingforreplyforwardemails">ClientDisableTrackingForReplyForwardEmails&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enables a user not to automatically track replies and forwarded email messages.&lt;br>Set this to&amp;nbsp;"True" to disable tracking replies and forwarded email messages.&amp;nbsp;&lt;br>&amp;nbsp;NOTE: This setting only applies to Dynamics 365 for Outlook (not Dynamics 365 App for Outlook).&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2903&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>When a user receives a reply to an email that has already been tracked, the reply will also be tracked by default. This is great for keeping the chains of emails all within D365. Unfortunately, this may lead to conversations being tracked that shouldn&amp;rsquo;t and give visibility to sensitive conversations - a manager receiving an email that was a complaint about a particular email that their report sent for example.&lt;/p>
&lt;p>Whilst this is mostly a training exercise, it can be quite embarrassing and this setting stops that. It does mean that you could lose out on a part of a conversation and rely on the user to track a response separately.&lt;/p>
&lt;p>This settings, as noted, only works with D365 for Outlook not the App for Outlook.&lt;/p>
&lt;h3 id="disableclientupdatenotification">DisableClientUpdateNotification&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting DisableClientUpdateNotification to true will disable the outlook client from checking for newer versions&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.0000.3027&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Only for the D365 for Outlook, will prevent the application checking for a new version. This will help if you are in a locked down environment and need the stability.&lt;/p>
&lt;p>With the D365 App for Outlook, it is a constant deployment rolled out with other fixes by Microsoft.&lt;/p>
&lt;h3 id="disableimplicitsharingofcommunicationactivities">DisableImplicitSharingOfCommunicationActivities&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changing this to "True" will disable implicit sharing of records to recipients that are added to existing activities.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2903&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>When an email, meeting, phone call etc. is created and an internal user is included in the recipients list, it shares the record with them. This allows the internal user to have visibility of the record within D365.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-82.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>If your security model has an issue with this, then this implicit sharing can be removed.&lt;/p>
&lt;p>Your model may restrict the visibility of activities depending on what record the activity is associated with in a team scenario. If the original recipient is no longer in the team, they should not have access to that information any longer. With the OOTB logic, this activity will still be visible.&lt;/p>
&lt;p>This email will still be in the recipients Outlook, nothing changes to the visibility in exchange, it is just the visibility in D365.&lt;/p>
&lt;h3 id="disablelookupmruonoutlookoffline">DisableLookupMruOnOutlookOffline&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>LookupMRUItems in UserEntityUISettings can cause a large data volume when going online,&lt;br>setting this to true will stop MRU's from syncing back ONLINE&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.1.0002.0106&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This one is not obvious to me and there is no information online. I&amp;rsquo;ll update when I find anything out&lt;/p>
&lt;h3 id="disablemapicaching">DisableMapiCaching&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When this value is set to "True," users can still pin the views. However, the query is sent to the&lt;br>CRM Server to retrieve the results instead of to the local cache to prevent performance issues.&amp;nbsp;&amp;nbsp;&lt;br>&lt;br>Note&amp;nbsp;This value is not valid with CRM 2013.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2903&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This was present to prevent server performance issues, typically seen with on-premise solutions, when results are retrieved from the cache of the server, rather than direct from the database. It is unclear if still needed.&lt;/p>
&lt;h3 id="disablesmartmatching">DisableSmartMatching&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Disables the smart matching functionality and relies on the tracking token on the incoming e-mails for email tracking.&lt;br>False&amp;nbsp;- Enables smart matching.&lt;br>True&amp;nbsp;- Disables smart matching.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9688.583&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Smart Matching is how Microsoft works out that the email you just sent in belongs to a conversation that you have already synced, hence it will sync that email when it comes in.&lt;/p>
&lt;p>In System Settings, you have several options when it comes to matching. Correlation is the default, where it is using a conversation id on each email to match them. You can supplement this with a tracking token and/or smart matching.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-83.png?w=906"
loading="lazy"
>&lt;/p>
&lt;p>Token is generally used for support scenarios, to ensure any replies to an email are tracked against the same case.&lt;/p>
&lt;p>Smart matching does what it suggests, using keywords in the subject and an algorithm to determine if the email is linked to a previous conversation.&lt;/p>
&lt;p>Using the DisableSmartMatching flag does the same as un-ticking the box on the system settings, where conversation id and tracking tokens are relied on.&lt;/p>
&lt;h4 id="distinctphysicalandlogicaldeletesforexchangesync">DistinctPhysicalAndLogicalDeletesForExchangeSync&lt;/h4>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Server-Side synchronization needs a mechanism to distinguish between Logical and Physical deletes of entities in CRM&lt;br>False : No distinction between physical and logical deletes for exchange sync delete scenario&lt;br>True : Physical and logical deletes will be distinguished for exchange sync delete scenario&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.0840&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is another where security takes over and users expectations can differ from the way Microsoft thinks it should work.&lt;/p>
&lt;p>If a user has been invited to a meeting, and it is recorded in D365, a copy of that exists within D365 and Exchange. If, for whatever reason, the user loses access (reas access) to that meeting in D365, the default behaviour would be to delete the copy in Exchange. Makes sense, to keep those in sync.&lt;/p>
&lt;p>With the DistinctPhysicalAndLogicalDeletesForExchangeSync set to true, lose of access to any activity does not mean that the activity is deleted in Exchange. Use this with DisableImplicitSharingOfCommunicationActivities to fully get control of activity access.&lt;/p>
&lt;h3 id="heading-1">&lt;/h3>
&lt;p>DoNotIgnoreInternalEmailToQueues&lt;/p>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>&lt;em>Version 5.0.9690.1533 to 8.2.2.1300:&lt;/em>&amp;nbsp;&lt;strong>False&lt;/strong>&lt;br>&lt;em>Version 8.2.2.1309 and higher:&lt;/em>&amp;nbsp;&lt;strong>True&lt;/strong>&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>If you disable the "Track email sent between CRM users as two activities" setting,&lt;br>email messages from a CRM user to a queue are not delivered.&lt;br>Additionally, if a workflow rule sends an email message to a queue,&lt;br>email messages that are sent by the workflow rule are not delivered.&lt;br>False&amp;nbsp;- Internal email messages to queues will not be delivered.&lt;br>True&amp;nbsp;- Internal email messages to queues will be delivered.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.1533&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is used in combination with the Track emails sent between Dynamics 365 users as two activities available in the system settings&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-84.png?w=838"
loading="lazy"
>&lt;/p>
&lt;p>If you enable the Track as a separate option, normally any email from internal user to a queue mailbox will be ignored. This seems a weird consequence, but they have provided you with an override so that these internal mails are not ignored.&lt;/p>
&lt;h3 id="enableappointmentbroadcastingforoutlooksync">EnableAppointmentBroadcastingForOutlookSync&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting for Appointment broadcasting for Outlook Synchronization&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.1.121&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I can&amp;rsquo;t find any information on this. Will update when I find out.&lt;/p>
&lt;h3 id="enablecrmstatecodeonoutlookcategory">EnableCrmStatecodeOnOutlookCategory&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enables Statecode data on contact sync&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.1.0.581&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="enablesssitemlevelmonitoring">EnableSssItemLevelMonitoring&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting value to True will enable a new dashboard accessible by users and administrators&lt;br>called Server-Side Synchronization Failures.&lt;br>This dashboard allows the owner of a mailbox to have information about all non-synched&lt;br>incoming/outgoing emails and also appointment, contact, and task (ACT) items.&lt;br>Information is provided for the reason items are not synchronized.&lt;br>Default value is set to False to preserve the existing behavior.&lt;br>You can use the ExchangeSyncIdMappingPersistenceTimeInDays setting to control how&lt;br>long the data for failed emails is retained.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.1661&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>There is a dashboard available to admin already called Server-Side Sync failures, without this setting. Not sure what this does, as the dashboard seems to be available regardless.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-85.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;h3 id="exchangesyncidmappingpersistencetimeindays">ExchangeSyncIdMappingPersistenceTimeInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>3&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>The number of days for which the ExchangeSyncIdMappings are to be persisted for failed emails.&lt;br>This setting is used in relation to the EnableSssItemLevelMonitoring setting.&lt;br>It is not recommended to increase this value higher than 7 days as it can lead&lt;br>to the table growing very large.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.2059&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting defines how many days of sync failures are kept, useful when you are troubleshooting, but table will get huge quickly, so only increase if you need to.&lt;/p>
&lt;h3 id="expiresubscriptionsindays">ExpireSubscriptionsInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>90&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Max number of days before deleting inactive Outlook client subscriptions.&lt;br>We recommend you keep this to the default unless you absolutely need to change it,&lt;br>be mindful of keeping the tracking info too long, or deleting it too soon.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>On creating my second post in this series I came across several configurations that were not documented in the KB article and hence were missed when I wrote this.&lt;/p>
&lt;p>When you track an contact in Outlook, you are subscribing to changes made to those contacts in D365 so that they are mimicked in your Outlook. This is great, but each subscription is stored in a database record, hence impacting storage costs. There is a deletion service that works through the subscriptions and deletes these expired lines. after the value is reached, with an outlook Client refreshing it&amp;rsquo;s subcriptions as part of it&amp;rsquo;s sync routine.the&lt;/p>
&lt;h3 id="hideemailautotrackoptions">HideEmailAutoTrackOptions&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Default value is false, if it's set to True: do not show the following track options in&lt;br>Personal Options (Email): 'All email messages', 'Email messages from D365 Leads, Contacts&lt;br>and Accounts', 'Email messages from D365 records that are email enabled'&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.1639&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This setting goes one further to the one below by stripping out &amp;ldquo;All email messages&amp;rdquo;, &amp;ldquo;Email messages from D365 Leads, Contact and Accounts&amp;rdquo; and &amp;ldquo;Email messages from D365 records taht are email enabled&amp;rdquo;, just leaving you with the two below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-46.png?w=737"
loading="lazy"
>&lt;/p>
&lt;h3 id="hidetrackalloption">HideTrackAllOption&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Removes “&lt;strong>All email messages&lt;/strong>” option from users’ Personal Options under Email&lt;br>tab&amp;nbsp;&lt;strong>Select the email messages to track in Microsoft Dynamics 365&lt;/strong>&amp;nbsp;area.&lt;br>False – "All email messages" option is shown in the dropdown.&lt;br>True – "All email messages" option is not shown in the dropdown.&lt;br>If a user already has "All email messages" selected, their synchronization option is&amp;nbsp;&lt;strong>not&lt;/strong>&amp;nbsp;updated&lt;br>in DB. Administrators will need to update this value via SDK.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.0.2.264&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Under personalisation settings for each user, they can decide to track all emails they receive from any source. Great for a shared mailbox or customer mailbox, but not for a normal user who receives spam and invites to cake sales etc.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-86.png?w=795"
loading="lazy"
>&lt;/p>
&lt;p>The default here is Email messages in response to D365 mail, but to stop users filling your D365 instance, setting the HideTrackAllOption to true will remove that top option.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-87.png?w=743"
loading="lazy"
>&lt;/p>
&lt;p>Any users that had this setting prior to it&amp;rsquo;s removal need to be updated manually or via the SDK.&lt;/p>
&lt;h3 id="ignorecopieditemsinsssformailbox">IgnoreCopiedItemsInSSSForMailbox&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Ignore creating duplicate for copied items for Server Side Sync&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.11129&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Normally, when an email or meeting or task is synced, it doesn&amp;rsquo;t matter where that content came from. If it appears new, it will be created new, even if it is a copy of another item. This will reduce the amount of synced items but may be a concern for your environment.&lt;/p>
&lt;h3 id="mailboxstatisticspersistencetimeindays">MailboxStatisticsPersistenceTimeInDays&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>3&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>If value is 0, dont store ANY MailboxStatistics Data, if the value is greater than zero then&lt;br>store that number of days statistics data. Max value arbitrarily chosen at 1 year,&lt;br>this generates at lot of data so 1 year should be plenty of time&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.0.0.1088&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>The Mailbox statistics records how frequently a mailbox is accessed and synced. This way, the more active mailboxes are synced more regularly. A mailbox that is infrequently used will be checked less regularly.&lt;/p>
&lt;p>On a high user system, with SSS on, it can get populated quickly, so 3 days will normally be appropriate.&lt;/p>
&lt;h3 id="outlookclientemailtaggerenabled">OutlookClientEmailTaggerEnabled&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>here are 3 values for this Boolean setting - true, false, and NULL (which is the value when NOT set).&lt;br>True: Will override any and all client registry setting to True.&lt;br>False: Will override any and all client registry setting to False.&lt;br>NULL: If the setting is NULL the outlook clients will use whatever is in the registry of the client.&lt;br>TO SET THIS VALUE TO NULL YOU WILL NEED TO CLICK EDIT, THEN REMOVE THE VALUE&lt;br>TO HAVE IT DEFAULT TO NULL.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.0.1.121&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="outlooksyncdatasubscriptionclientsbatchsize">OutlookSyncDataSubscriptionClientsBatchSize&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>100&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>This setting is used to determine how many record changes (deletes, inserts, and updates)&lt;br>to send back to a syncing client for each request.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>7.1.0.1059&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;h3 id="overridetrackincrmbehaviour">OverrideTrackInCrmBehaviour&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When this option is Enabled, the ‘Track in CRM’ button functions as the Set Regarding&lt;br>button in Dynamics 365 for Outlook. In Dynamics 365 App for Outlook,&lt;br>‘Track without regarding’ command is not displayed, with Set Regarding as&lt;br>the only way to synchronize Outlook items to Dynamics 365.&lt;br>0 - Normal behavior of the "Track in CRM" button not having to set a Regarding record&lt;br>in Dynamics 365 for Outlook.&lt;br>‘Track without regarding’ command is displayed in Dynamics 365 App for Outlook.&lt;br>1 - The ‘Track in CRM’ button functions as the ‘Set Regarding’ button, and makes you&lt;br>select a regarding record in Dynamics 365 for Outlook.&lt;br>In Dynamics 365 App for Outlook, ‘Track without regarding’ command is not displayed,&lt;br>with Set Regarding as the only way to synchronize Outlook items to Dynamics 365.&lt;br>NOTE: This setting applies to&amp;nbsp;both&amp;nbsp;Dynamics 365 for Outlook and Dynamics 365 App for Outlook.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.6200&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Normally, a user can track an activity to D365 without associating with a record, the Set regarding. This could lead activities in your tenant not associated with a record, orphaned. Depending on your business requirements, disabling this feature could be required.&lt;/p>
&lt;p>Normally, under the &amp;hellip; under Not Tracked, the user has an option to Track without Regarding&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-88.png?w=384"
loading="lazy"
>&lt;/p>
&lt;p>Setting OverrideTrackInCrmBehaviour to 1 will override this behaviour, removing the ellipses button altogether. The user has to establish a link to an existing record to sync the email or activity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-89.png?w=300"
loading="lazy"
>&lt;/p>
&lt;h3 id="overridev5senderconflictresolution">OverrideV5SenderConflictResolution&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When multiple records with the same email address exist in the Dynamics CRM Organization&lt;br>and email is automatically tracked, the email address is resolved to the record for the owner&lt;br>record that was created first. This option lets you override that functionality.&lt;br>False&amp;nbsp;- E-mails are tracked to the first record created.&lt;br>True&amp;nbsp;- E-mails are not tracked automatically if there are multiple records&lt;br>with the same email address.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2243&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Michael Sulz has a good write up on this, &lt;a class="link" href="https://michaelsulz.wordpress.com/tag/crm/" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>Normally, if there are 2 or more contacts with the same email address (data quality is always a problem, however much you take care of it, though &lt;a class="link" href="https://www.data-8.co.uk/" target="_blank" rel="noopener"
>data8&lt;/a> do a real good job of removing duplicates and improving your data) the contact chosen is the first contact owned by the syncing user, sorted by create date or the first created if that doesn&amp;rsquo;t match.&lt;/p>
&lt;p>Setting this option to true will force the user to make a decision and not sync the email automatically.&lt;/p>
&lt;h3 id="restrictirmemailitems">RestrictIRMEmailItems&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting value to TRUE will result in Server Side Sync NOT synchronizing ALL emails&lt;br>that are marked as IRM emails.&lt;br>Default value is set to False to preserve the existing behavior.&lt;br>To enable this restriction on the organization " RestrictIRMEmailItems " should be set to True.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.0840&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Bhavesh Shastri has a great write up of this configuration &lt;a class="link" href="https://community.dynamics.com/crm/b/crminthefield/posts/dynamics-365-customer-engagement-how-to-choose-system-settings-and-personal-options-for-automatic-email-tracking" target="_blank" rel="noopener"
>here&lt;/a>&lt;/p>
&lt;p>Restricted messages, those that the sender has marked as any of the restricted types in Azure information Protection, may not be suitable to be included in your D365 system.&lt;/p>
&lt;p>If you set his flag to true, the user will not be able to sync those that are protected and will be given an error message if they try to.&lt;/p>
&lt;h3 id="securitysettingforemail">SecuritySettingForEmail&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Number&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>1: Display a Warning Message And give an option to open -&lt;br>2: Display a Warning Message and do not give an option to open&lt;br>3: Do not display a Warning Message and do not give any option to open.&lt;br>This setting is NOT SUPPORTED IN CRM2013 as of build 809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.3731&lt;br>6.1.0.581&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>The majority of emails that a user receives and hence sync to D365 contain HTML to some degree, whether it is simple formatting or full on marketing emails.&lt;/p>
&lt;p>In all scenarios, the interface presents a stripped down version of the email, but formatting etc will be lost.&lt;/p>
&lt;p>There is a risk when these are displayed in all their glory in D365, that parts of the email could be nefarious, including scripts etc that could include phishing or other attacks. Microsoft by default warns the user that this is the case, but allows the user to click through to the content, putting the decision in the users&amp;rsquo; hands.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-90.png?w=722"
loading="lazy"
>&lt;/p>
&lt;p>If you change the setting to 2, the link to the full content is removed&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-91.png?w=679"
loading="lazy"
>&lt;/p>
&lt;p>Changing the setting to 3 removes the message and always shows the full version of the email&lt;/p>
&lt;h3 id="sendemailsynchronously">SendEmailSynchronously&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>0&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Int&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>If you have a plugin registered on the email send flow, you&amp;nbsp;should&amp;nbsp;change this setting to&amp;nbsp;"1."&amp;nbsp;&lt;br>0&amp;nbsp;- Email is sent asynchronously.&lt;br>1&amp;nbsp;- Email is sent synchronously.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Depending on your logic, you may interact by workflow when an email is sent via Outlook. This setting moves the send email to a synchronous operation rather than asynchronous, allowing a more immediate interaction with the email. This may have a performance impact on the user in Outlook.&lt;/p>
&lt;h3 id="sortemailbyreceivedon">SortEmailByReceivedOn&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>When the Activities tab of the social pane is show, the data ordered by the 'modifiedon'&lt;br>date in descending order, toggling this setting to True will enable the social pane to sort&lt;br>emails by RecievedOn Desc instead of modifiedon&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.0.1.79&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I am not sure that this is a problem any more, in Social pane in D365 we have a lot of options for searching, but back in the legacy UI this allowed you to change the email sorting from the date the email was edited or added to D365 to the date the email was received. This could be several days difference, so it could give a different perspective to the conversation.&lt;/p>
&lt;h3 id="traceexchangesyncdata">TraceExchangeSyncData&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>true&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enables exchange sync tracing&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>6.0.0.809&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Logging of the sync data is essential for any troubleshooting, but it adds to the size of your database. With the separation of log and data in storage costs, I am not sure this should ever be turned off if you are using SSS.&lt;/p>
&lt;h3 id="trackappointmentsfromnonorganizer">TrackAppointmentsFromNonOrganizer&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Enabled users to track appointments organized by another Dynamics 365 user via&lt;br>Dynamics 365 App for Outlook.&lt;br>False &amp;nbsp;– &amp;nbsp;Dynamics 365 App for Outlook and Server-Side Synchronization users cannot track&lt;br>Outlook appointments whose organizer is a Dynamics 365 user.&lt;br>True &amp;nbsp;– &amp;nbsp;Dynamics 365 App for Outlook and Server-Side Synchronization users can track Outlook&lt;br>appointments whose organizer is a Dynamics 365 user.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>9.1.0.0294&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>You can always track a meeting if it was sent from an external user and by default, you can track any appointment where the organiser is a D365 user. This setting prevents the user from tracking an appointment if it is not them organising it.&lt;/p>
&lt;h3 id="trackcategorizeditems">TrackCategorizedItems&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>True&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Setting value to False will remove the category tracking flag and functionality.&lt;br>Default value is set to True to allow category tracking and tracking status visibility for users&lt;br>whom do not use Dynamics 365 for Outlook or Dynamics 365 App for Outlook.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2.2.0840&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Using &lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/use-outlook-category-track-appointments-emails" target="_blank" rel="noopener"
>Category based tracking&lt;/a> is a great way to allow users to track multiple emails at once. In the App for Outlook, this is the only way.&lt;/p>
&lt;p>With the OOTB behaviour, the user gets a new category added and is able to select multiple emails to sync. It also appears as a great indicator in Outlook that the activity is synced.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-92.png?w=733"
loading="lazy"
>&lt;/p>
&lt;p>Setting the flag to false removes this category and ability.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-93.png?w=769"
loading="lazy"
>&lt;/p>
&lt;p>Be warned on this, if you leave any item with the category on it after you have disabled this functionality, re-enabling the functionality will mean that these items will be synced. Also, this category doesn&amp;rsquo;t respect the fact you upgrade. An email with the category that was synced to an on premise version will create a duplicate if that user is moved to the online version and the originating email was migrated as part of the data migration from on-prem to online.&lt;/p>
&lt;h3 id="usecrmorganizerforemptyexchangeorganizer">UseCrmOrganizerForEmptyExchangeOrganizer&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Use the CRM Organizer of an Appointment if the Exchange Organizer doesn't exist.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.1.1.1020&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>I think this is more to do with rare cases when the sync doesn&amp;rsquo;t work correctly, but another one that I can not find any information for.&lt;/p>
&lt;h3 id="usefilteringmethodofsyncingmailboxonlyforcorrelation">UseFilteringMethodOfSyncingMailboxOnlyForCorrelation&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>This is for controlling which users’ filtering settings will be used &amp;nbsp;for correlation.&amp;nbsp;&lt;br>False &amp;nbsp;– filtering method of all recipients of the email will be checked to decide if any&lt;br>user/queue accepts email or not.&lt;br>True &amp;nbsp;– filtering setting of user who synced email to CRM will be used. Filtering &amp;nbsp;setting&lt;br>of other recipients of the emails will be ignored.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>8.2&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>Each user has a seperate filter list to decide which emails are synced to D365. These can be various settings on what that individual user requires.&lt;/p>
&lt;p>The default for this setting, the standard OOTB behaviour, is false, where any user can sync this email if it matches their settings. True means that the user who created the email or synced it will be able to have the email included in the selection for the filter. It is in effect an additional filter for the user to only include emails I have created.&lt;/p>
&lt;h3 id="useplaintextforemailtemplatebody">UsePlainTextForEmailTemplateBody&lt;/h3>
&lt;table>&lt;tbody>&lt;tr>&lt;td>&lt;strong>Default Value&lt;/strong>&lt;/td>&lt;td>False&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Type&lt;/strong>&lt;/td>&lt;td>Boolean&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Description&lt;/strong>&lt;/td>&lt;td>Changes the Email Template to use plain text where otherwise text with the following&lt;br>symbols would not appear &amp;lt;text&amp;gt;.&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Min Version&lt;/strong>&lt;/td>&lt;td>5.0.9690.2720&lt;/td>&lt;/tr>&lt;tr>&lt;td>&lt;strong>Max Version&lt;/strong>&lt;/td>&lt;td>&lt;/td>&lt;/tr>&lt;/tbody>&lt;/table>
&lt;p>This is one of the older settings, presumably when people had email clients that could not handle html formatted text.&lt;/p></description></item><item><title>MS Certifications - Sharing my Mind Maps</title><link>https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/</link><pubDate>Mon, 16 Sep 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/09/16/ms-certifications-sharing-my-mind-maps/</guid><description>&lt;img src="https://linked365.blog/images/2019/09-Presentation1-e1587137237672.png" alt="Featured image of post MS Certifications - Sharing my Mind Maps" />&lt;p>Over the last 3 years, I have completed 11 Microsoft certifications and have used various sources on the internet to get me through.&lt;/p>
&lt;p>My method of remembering facts relies on completing a mind map. This way, I note down the key points (key to me anyway) for a subject and link them together, serving as a quick refresher on the day but forces me to fill out my knowledge as I research the content and develop my understanding.&lt;/p>
&lt;p>Please don&amp;rsquo;t think that memorising these maps will be all you need to do to pass any of the exams. I share them to assist you in getting that certificate and maybe trigger something that you don&amp;rsquo;t understand so you can research that area more effectively. I also don&amp;rsquo;t guarantee that they are all accurate. The vagaries of time and my ineptitude will ensure they are not.&lt;/p>
&lt;p>It goes without saying that practice is the best way of ensuring you have the right understanding of the product, but I have found that there are always areas where you have not come across, even if you have been working on an application for years. Microsoft never stops developing.&lt;/p>
&lt;p>I will keep this page up to date as I complete more exams with the mind map and any resources I used, with the exam I took most recently at the top.&lt;/p>
&lt;p>All the mind maps can be found &lt;a class="link" href="https://1drv.ms/u/s!AueNWhtMOmpUirAn6Ppk5mVCK_1eEA?e=6DoAEg" target="_blank" rel="noopener"
>here&lt;/a>. I use &lt;a class="link" href="https://www.freeplane.org" target="_blank" rel="noopener"
>Freeplane&lt;/a> as my mind mapping tool of choice, because it is open source, free for unlimited maps, allows tweaking of styles etc and is not trying to sell you it&amp;rsquo;s bigger brother. There are others out there which offer increased functionality, but this works for me. You can import Mindmap files into most other services&lt;/p>
&lt;h2 id="pl-200---microsoft-power-platform-functional-consultant">PL-200 - Microsoft Power Platform Functional Consultant&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21298589&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>This is the bigger brother, supposedly, of the PL-100 but I found them on the same level. More emphasis on the non-technical aspects but still covers a wide range of subjects, from Power BI to AI similar to PL-100. Full review &amp;amp; review of Julian Sharps excellent book which stimulated my learning is &lt;a class="link" href="https://linked365.blog/2021/02/12/pl-200-power-platform-functional-consultant/" >here&lt;/a>.&lt;/p>
&lt;h2 id="pl-100---microsoft-power-platform-app-maker">PL-100 - Microsoft Power Platform App Maker&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21288972&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>This is more than a functional exam, delves deep into the making experience and complexity of Canvas Apps. Includes a wide breadth of Power Platform technology from Power BI to AI Builder functionality. Full views are on a separate post &lt;a class="link" href="https://linked365.blog/2020/08/17/pl-100-microsoft-power-platform-app-maker/" >here&lt;/a>.&lt;/p>
&lt;h2 id="mb-400---microsoft-power-apps--dynamics-developer">MB-400 - Microsoft Power Apps + Dynamics Developer&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21171275&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>This is the developer exam, an extension of MB2-716 for modern times and covers all aspects of that exam and more. &lt;a class="link" href="https://crmchap.co.uk/" target="_blank" rel="noopener"
>CRM Chap,&lt;/a> Joe Griffin has a great series of posts about this one for you to revise with. My views on this are in a separate post &lt;a class="link" href="https://linked365.blog/2020/04/18/mb-400-power-apps--dynamics-365-developer-associate-exam/" >here&lt;/a>&lt;/p>
&lt;h2 id="mb-600---microsoft-power-apps--dynamics-365-solution-architect-beta">MB-600 - Microsoft Power Apps + Dynamics 365 Solution Architect (beta)&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21171131&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>This exam is the pinnacle of certifications for D365 / Power Platform at the moment. My views on this are shared in a separate post &lt;a class="link" href="https://linked365.blog/2020/04/04/mb-600-microsoft-power-apps--dynamics-365-solution-architect-beta/" >here&lt;/a>&lt;/p>
&lt;p>Resources for this one are rare, none that I found are a good representation of the exam I faced. It is still in beta, so as more people do it, and official training/courses become available I would expect this to improve.&lt;/p>
&lt;h2 id="mb-210---sales">MB-210 - Sales&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AIMPm5W911n1ePM&amp;amp;id=546A3A4C1B5A8DE7%21170060&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>Sales is my bread and butter, with lots of experience in what the life-cycle is etc, but the new parts, Sales Insights was new.&lt;/p>
&lt;p>Again, I used Neil&amp;rsquo;s &lt;a class="link" href="https://neilparkhurst.com/2019/02/24/mb-210-microsoft-dynamics-365-for-sales-revision-guide/" target="_blank" rel="noopener"
>blog&lt;/a>. Great insight, though I would also get an understanding of the minimum requirements for some services, which I wasn&amp;rsquo;t ready for.&lt;/p>
&lt;p>The scenarios are full on too, though the advise is to read it through before tackling a question and re-read the sections before giving your answer&lt;/p>
&lt;h2 id="mb-240---field-service">MB-240 - Field Service&lt;/h2>
&lt;p>&lt;a class="link" href="https://1drv.ms/u/s!AueNWhtMOmpUirAq2gx6mB95JUeTYQ?e=Ymmx6q" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>Field service was a stretch goal for me, as I have never used it in anger on a client site. It is a relatively new product in the suite, but one that is getting a lot of traction in the D365 community.&lt;/p>
&lt;p>I went into this exam thinking I was not prepared, but managed a decent pass with my learning. The exam itself is quite short, but did stretch my understanding.&lt;/p>
&lt;p>My first resource, as always was Neil Parkhurst. He has a great series of posts on this exams predecessor, &lt;a class="link" href="https://neilparkhurst.com/2018/02/13/mb2-718-certification-microsoft-dynamics-365-customer-service-field-service-introduction/" target="_blank" rel="noopener"
>MB2-718&lt;/a> Whilst being slightly dated, it is still relevant.&lt;/p>
&lt;p>Further, I went through the Microsoft Learn topics on Field Service here&lt;/p>
&lt;h2 id="mb-200---customer-engagement-core">MB-200 - Customer Engagement Core&lt;/h2>
&lt;p>As I have been working with D365 a while, I was very lazy when going into this one. I just assumed I knew it all, brushed up on the new stuff and went for it. Thankfully, this didn&amp;rsquo;t bite me in the ass.&lt;/p>
&lt;p>I didn&amp;rsquo;t do a map for this one, but I reviewed the map for MB2-716 &lt;a class="link" href="https://1drv.ms/u/s!AueNWhtMOmpUirAose9YNbgITha_iw?e=ndn87a" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>I also review Neil&amp;rsquo;s &lt;a class="link" href="https://neilparkhurst.com/2019/09/09/mb-200-microsoft-dynamics-365-customer-engagement-core-revision-guide/" target="_blank" rel="noopener"
>posts&lt;/a> on this one and &lt;a class="link" href="https://twitter.com/nz365guy" target="_blank" rel="noopener"
>@NZ365Guy&lt;/a> videos on the subject on the OpenEdx &lt;a class="link" href="https://openedx.microsoft.com/courses/course-v1:Microsoft&amp;#43;MB-200.1&amp;#43;2019_T1/about" target="_blank" rel="noopener"
>course&lt;/a> which are a great, particularly for the new stuff in the application, like Flows.&lt;/p>
&lt;h2 id="az-203---developing-solutions-for-azure">AZ-203 - Developing Solutions for Azure&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21170027&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>I consider myself to be a lapsed developer. I love coding, but my career has taken myself into more of an advisor and designer than a &amp;ldquo;coder&amp;rdquo;. This exam was proof to myself that I could still run with the cool kids and also exposed me to a lot of the azure stack that I did not know.&lt;/p>
&lt;p>As I was preparing for this exam back in January, to get an Azure Developer Associate certification, it swapped from 2 exams to 1, AZ-200 being the first, that is why they references to AZ-200 linger.&lt;/p>
&lt;p>For this exam I was indebted to the &lt;a class="link" href="https://app.pluralsight.com/paths/certificate/microsoft-azure-developer-core-solutions-az-200" target="_blank" rel="noopener"
>course&lt;/a> by Pluralsight which I am thankful that I had access to.&lt;/p>
&lt;p>From a D365 developer point of view, this was a tough one. It was a step above and beyond what I expected. There is so much content, each area to a decent understanding level it really taxed me. This is the first exam to push the time I had available to complete it, with a large number of questions and a lot of deliberation.&lt;/p>
&lt;h2 id="mb2-718---d365-for-customer-service">MB2-718 - D365 for Customer Service&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21170028&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>This was the last of the older exams I took before Microsoft revamped the exams. Neil Parkhurst has an excellent &lt;a class="link" href="https://neilparkhurst.com/2018/01/26/mb2-718-certification-microsoft-dynamics-365-for-customer-service-revision-guide/" target="_blank" rel="noopener"
>blog&lt;/a> on this one, which was my source. I have been doing service for quite a while, but the intricacies around SLAs and Queues were something that I had to learn. It also contained Unified Service Desk and Voice of the Customer, both subjects I had not come across.&lt;/p>
&lt;h2 id="mb2-716---customisation--configuration">MB2-716 - Customisation &amp;amp; Configuration&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21170024&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>Another old exam, and something I take pride in as it is my bread and butter. This was another re-cap of my understanding, particularly around the bits where I would just Google when I came across it in my day job. Neil Parkhurst again provided the &lt;a class="link" href="https://neilparkhurst.com/2017/06/30/mb2-716-certification-microsoft-dynamics-365-customization-and-configuration-revision-guide/" target="_blank" rel="noopener"
>detail&lt;/a> which saw me through. Bits on auditing and configuring email etc. were items that I knew the fundamentals, but Microsoft has a knack of slightly tweaking the wording giving a separate answer, so it is vital you know your stuff.&lt;/p>
&lt;h2 id="mb2-715---d365-online-deployment">MB2-715 - D365 Online Deployment&lt;/h2>
&lt;p>&lt;a class="link" href="https://onedrive.live.com/?authkey=%21AOj6ZOZlQiv9XhA&amp;amp;id=546A3A4C1B5A8DE7%21170025&amp;amp;cid=546A3A4C1B5A8DE7" target="_blank" rel="noopener"
>Mind Map&lt;/a>&lt;/p>
&lt;p>I am fortunate to have come to D365 after online was the chosen deployment method. I have not got nightmares like some older community members around installing and configuring on-premise solutions. This is another exam that is part of my day-to-day role so it was just a matter of brushing up on where I did not have enough knowledge.&lt;/p>
&lt;p>Neil Parkhurst (who doesn&amp;rsquo;t owe Neil a beer?) has it covered &lt;a class="link" href="https://neilparkhurst.com/2017/09/29/mb2-715-certification-microsoft-dynamics-365-customer-engagement-online-deployment-revision-guide/" target="_blank" rel="noopener"
>again&lt;/a>. There is a lot you take for granted here, that you need to get to grips with, such as licensing, what you need to do in the Office Admin portal vs D365 admin, Email configuration and integration with other apps like SharePoint.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-70.png?w=390"
loading="lazy"
>&lt;/p></description></item><item><title>Cloning Flows: Location triggers for everyone</title><link>https://linked365.blog/2019/09/14/cloning-flows-location-triggers-for-everyone/</link><pubDate>Sat, 14 Sep 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/09/14/cloning-flows-location-triggers-for-everyone/</guid><description>&lt;img src="https://linked365.blog/images/2019/09-image-69.png" alt="Featured image of post Cloning Flows: Location triggers for everyone" />&lt;p>Sometimes ideas don&amp;rsquo;t work out. This is one of these times. But the reason I blog is to learn, expand my knowledge of the PowerPlatform, expand my knowledge of components outside of it. So, I figured I would blog about my failure, learning is learning. As I started testing the flow again, moving environments etc, it started working. I guess this is down to the location trigger being a work in progress. Moral of the story: If it is broke last month, try again this month.&lt;/p>
&lt;p>Back in July, I started working on this scenario, but couldn&amp;rsquo;t get it working. I noticed &lt;a class="link" href="https://twitter.com/Flow_joe_" target="_blank" rel="noopener"
>@Flow_Joe_&lt;/a> &amp;amp; &lt;a class="link" href="http://twitter.com/JonJLevesque" target="_blank" rel="noopener"
>@JonJLevesque&lt;/a> did a &lt;a class="link" href="https://www.youtube.com/watch?v=J0vZCotp9Pw&amp;amp;t=1493s" target="_blank" rel="noopener"
>video walkthrough&lt;/a> of using the Geofence trigger to send out a summary of the customer when a sales person enters an area, which reminded me of my failure, hence why I have written it up. While from Joe &amp;amp; Jon&amp;rsquo;s video shows us how easy it is to create a flow, for Salespeople in general, I think this is too far. You can not expect a Salesperson to have any interest in creating flows to do this, you can expect them to click a button on a form within their D365 application.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario&lt;/li>
&lt;li>Creating the Flow button&lt;/li>
&lt;li>Cloning the Flow&lt;/li>
&lt;li>Outcome&lt;/li>
&lt;/ul>
&lt;h2 id="the-scenario">The Scenario&lt;/h2>
&lt;p>Numerous times when I have been a customer, a salesperson would come to us not knowing that we have several major cases logged with them against their product. This is mainly down to lazy sales people (I know, they don&amp;rsquo;t exist), but it would be awesome for the salesperson to get a summary of the account when they get in the door of a customer. The number of support cases, a list of the open opportunities and orders, any complaints that have been logged. All of this information is available to the salesperson via the D365 mobile app, but it would be good to ensure that they get this information and are less likely to get caught out by a customer venting at them for 5 critical bugs that have been sat around for a month.&lt;/p>
&lt;h2 id="the-solution">The Solution&lt;/h2>
&lt;p>Flow has a new trigger, still in preview, Location, which is triggered via the Flow application when an user enters or exists an area. This is perfect for our scenario, stick a GeoFence around a customers location, when the user enters the area, it gets triggered. Look up the Customer, format an email and send it to the user.&lt;/p>
&lt;p>Flow is user friendly, a low code solution, but you can not expect a salesperson to create a flow for each account they want to create this trigger for. What can be done, is put a button on a form, automatically create a Flow for the user against the account they have selected which would then be triggered when the user enters the location.&lt;/p>
&lt;p>There are 2 separate series of flows that are required, firstly to start with an action from the user on the account record, which triggers cloning of a template.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>The second series is the clone of the template, which triggers sending the salesperson the relevant information when they enter the customers property.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-32.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="creating-a-flow-button">Creating a Flow Button&lt;/h2>
&lt;p>Starting with a CDS &amp;ldquo;When a record is selected&amp;rdquo; trigger, configure it to be used when an account is selected.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-33.png?w=514"
loading="lazy"
>&lt;/p>
&lt;p>The next step is to retrieve who is running this flow. As mentioned, it will publish this button on a Account form, so it is essential to know who is running this, so an email can be sent to them. The account information and who the user is is sent as the body to a HTTP Post trigger, which is the next flow in the chain.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-39.png?w=502"
loading="lazy"
>&lt;/p>
&lt;p>An HTTP trigger is used because the next Flow requires enhanced access. An admin user needs to clone a Flow, which you would not want a normal user to be able to do. The admin is used as well to ensure any runs that happen are legitimate. The admin or sys account shouldn&amp;rsquo;t belong to someone who could have Flow in their pocket.&lt;/p>
&lt;p>To have the URL to send to, the next Flow needs to be created first, but just to show where this button appears within the D365 interface. The first time we run it, there are few confirmations that you need to do, finally you can run the flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-button-on-account.gif?w=1024"
loading="lazy"
>&lt;/p>
&lt;h2 id="cloning-the-flow">Cloning the Flow&lt;/h2>
&lt;p>This flow clones an existing template, tweak it slightly and gets it up and running as the user.&lt;/p>
&lt;p>Starting with an HTTP Trigger, I use a sample payload to build the schema.&lt;/p>
&lt;p>Next is retrieving the account. As the account id is passed in from the calling Flow, a simple Get Record is used.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-40.png?w=516"
loading="lazy"
>&lt;/p>
&lt;p>Next, configure the name of the Flow that will be created, making it unique for the user by adding their email address in. A flow definition string is also initialised for later&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-41.png?w=546"
loading="lazy"
>&lt;/p>
&lt;p>In this Flow, the user that called it from the button is needed, so it retrieves the profile using the Office 365 Users action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-43.png?w=539"
loading="lazy"
>&lt;/p>
&lt;p>Next, retrieve my template flow. Flow has several actions around management of Flows, which are incredibly useful to a Flow administrator. The template flow is a simple flow which has a location trigger and a call to a http trigger to call a secondary flow. I will discuss later the detail about this.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-44.png?w=502"
loading="lazy"
>&lt;/p>
&lt;p>The next couple of actions try to determine if a flow with the FlowName defined already exists, firstly by getting a list of all my flows (as an admin) then getting a list of Flows in the organisation, then filtering it with the flowname that was defined in the initial steps&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-45.png?w=701"
loading="lazy"
>&lt;/p>
&lt;p>If there is a flow already, just stop. If not, carry on &amp;amp; clone the template flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-46.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;h2 id="the-template">The Template&lt;/h2>
&lt;p>The Log Template is a very easy, small location trigger with an HTTP call action. The HTTP call passes in the user&amp;rsquo;s location and the account id and the user who started the process. Both email and account will be swapped out as part of the clone.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-63.png?w=523"
loading="lazy"
>&lt;/p>
&lt;p>The trigger region is essential for any location trigger. It triggers this one of the Microsoft campus in Redmond. Someday I will be fortunate to go to the motherland. I chose this as it is not likely that the user would have them as a client, but it doesn&amp;rsquo;t really matter where you chose, as what you need is the latitude and longitude from it so you can replace it when you clone the flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-48.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>If you click on the peek code button against the trigger, it shows a JSON representation of the trigger. The latitude and longitude are that of the Microsoft office and this is the bit I need to replace&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-50.png?w=491"
loading="lazy"
>&lt;/p>
&lt;h2 id="cloning-the-flow-part-2">Cloning the Flow (part 2)&lt;/h2>
&lt;p>All a Flow is a JSON file. Obviously, how it is rendered and how the hooks and actions work are the power, but the definition is a JSON file. Using this knowledge, we can create a new version of the template, with a location specific to the account.&lt;/p>
&lt;p>The template in all it&amp;rsquo;s glory is below. Just using simple find / replace, we tweak it to the specific location, account and user.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;span class="lnt">49
&lt;/span>&lt;span class="lnt">50
&lt;/span>&lt;span class="lnt">51
&lt;/span>&lt;span class="lnt">52
&lt;/span>&lt;span class="lnt">53
&lt;/span>&lt;span class="lnt">54
&lt;/span>&lt;span class="lnt">55
&lt;/span>&lt;span class="lnt">56
&lt;/span>&lt;span class="lnt">57
&lt;/span>&lt;span class="lnt">58
&lt;/span>&lt;span class="lnt">59
&lt;/span>&lt;span class="lnt">60
&lt;/span>&lt;span class="lnt">61
&lt;/span>&lt;span class="lnt">62
&lt;/span>&lt;span class="lnt">63
&lt;/span>&lt;span class="lnt">64
&lt;/span>&lt;span class="lnt">65
&lt;/span>&lt;span class="lnt">66
&lt;/span>&lt;span class="lnt">67
&lt;/span>&lt;span class="lnt">68
&lt;/span>&lt;span class="lnt">69
&lt;/span>&lt;span class="lnt">70
&lt;/span>&lt;span class="lnt">71
&lt;/span>&lt;span class="lnt">72
&lt;/span>&lt;span class="lnt">73
&lt;/span>&lt;span class="lnt">74
&lt;/span>&lt;span class="lnt">75
&lt;/span>&lt;span class="lnt">76
&lt;/span>&lt;span class="lnt">77
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;$schema&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;contentVersion&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1.0.0.0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;$authentication&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;defaultValue&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;SecureObject&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;triggers&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;manual&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Request&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;kind&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Geofence&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;parameters&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;serializedGeofence&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Circle&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;latitude&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">47.64343469631714&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;longitude&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mf">-122.14205669389771&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;radius&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">35&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;actions&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;HTTP&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;runAfter&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Initialize\_Email\_Variable&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Succeeded&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Http&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;method&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;POST&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;uri&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://prod-68.westeurope.logic.azure.com:443/workflows/&amp;lt;GUID&amp;gt;/triggers/manual/paths/invoke?api-version=2016-06-01&amp;amp;sp=%2Ftriggers%2Fmanual%2Frun&amp;amp;sv=1.0&amp;amp;sig=&amp;lt;SIG&amp;gt;-JQQvYT0&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;lat&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;@{triggerBody()?\[&amp;#39;currentLatitude&amp;#39;\]}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;long&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;@{triggerBody()?\[&amp;#39;currentLongitude&amp;#39;\]}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;user&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;@{variables(&amp;#39;Email&amp;#39;)}&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;account&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;@{variables(&amp;#39;accountId&amp;#39;)}&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Initialize\_Account\_Variable&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;runAfter&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;InitializeVariable&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;variables&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;accountId&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;String&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;value&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;accountId&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Initialize\_Email\_Variable&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;runAfter&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Initialize\_Account\_Variable&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Succeeded&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;InitializeVariable&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;inputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;variables&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Email&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;String&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;value&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;&amp;lt;email&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;outputs&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Back on the clone flow, the next step is to convert the template to a string. This makes it easier to replace the latitude, longitude etc. with the ones we want.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-51.png?w=488"
loading="lazy"
>&lt;/p>
&lt;p>On the account OOTB record there is a latitude and longitude. This data is not normally populated, but it is used by Field Service and other applications. I used Field Service to populate it using the Geo Code button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-52.png?w=356"
loading="lazy"
>&lt;/p>
&lt;p>As you can see from the above, Field service populates both latitude and longitude to 5 decimal places. This is common precision when you use any mapping software such as Google. so I am not sure why if you do the same by the Flow trigger you get precision to 15 dp for latitude and 17 for longitude.&lt;/p>
&lt;p>The next 2 steps are because of me trying to get the flow to work. One of my thoughts was that the flow was expecting the all 15 of the decimal places to be populated, so these steps pad out the number you have against the account with additional numbers.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-53.png?w=517"
loading="lazy"
>&lt;/p>
&lt;p>The expression is the same for both&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">concat&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">body&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Get&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Account&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">address1&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_latitude&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="mi">111111&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The next step replaces the newly calculated values for latitude and longitude in the JSON definition&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-54.png?w=500"
loading="lazy"
>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">replace&lt;/span>&lt;span class="p">(&lt;/span> &lt;span class="nf">variables&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">flowdefstring&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="mf">47.643434696317136&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nf">outputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Replace&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Lat&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)),&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="mf">122.14205669389771&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nf">outputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Replace&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Long&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The accountid is also replaced. This is used in the cloned flow to define which account the user selected. The trigger only gives you the user&amp;rsquo;s current location, not the centre of the circle you configured. You could use these values &amp;amp; find the account, with difficulty, unless there is something I am missing. I prefer to add a variable in the clone, which is the account id.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-60.png?w=486"
loading="lazy"
>&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">outputs&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Replace&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Lat&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Long&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">accountId&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="nf">triggerBody&lt;/span>&lt;span class="p">()&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Account&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">])&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The same with the email to send to, it should be the user who triggers the geofence, but seems to be the person who is the admin. As I clone the Flow with an admin account then add the user as an admin, it runs under the admin account.&lt;/p>
&lt;p>There is enough info now to create this flow. Using the Create Flow action, the new flow is created and up and running.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-68.png?w=497"
loading="lazy"
>&lt;/p>
&lt;p>I use a JSON expression to convert the string I have used to find / replace the latitude, longitude etc. to ensure the Flow is created with JSON.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">json&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">variables&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">flowdefstring&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The final step is to add a Flow owner. As the sales person who triggered the flow is who it should trigger on, make them the owner, so it should run under their context.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-56.png?w=524"
loading="lazy"
>&lt;/p>
&lt;h2 id="outcome-v1">Outcome V1&lt;/h2>
&lt;h4 id="ignore-this-bit-if-you-want-to-avoid-the-author-moaning-about-stuff-that-doesnt-work">Ignore this bit if you want to avoid the author moaning about stuff that doesn&amp;rsquo;t work.&lt;/h4>
&lt;p>If I run the whole flow, I do generate a new Flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-57.png?w=912"
loading="lazy"
>&lt;/p>
&lt;p>Going into what was generated, using peek code again, you can see that the Microsoft location has been replaced with the Avanade office&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-58.png?w=630"
loading="lazy"
>&lt;/p>
&lt;p>The trigger is active, but this is where it stops. I can not get this to trigger to fire. Changing the location to my home, going for a walk, coming back doesn&amp;rsquo;t trigger it.&lt;/p>
&lt;p>If I don&amp;rsquo;t put in the padding for the latitude and longitude, it doesnt trigger.&lt;/p>
&lt;p>If I clone from my location, not changing the latitude and longitude, still the trigger doesn&amp;rsquo;t fire.&lt;/p>
&lt;p>If I configure a new trigger from scratch, that works.&lt;/p>
&lt;p>Everything about the trigger look the same when you get it in code view, but there must be something different.&lt;/p>
&lt;p>This is where I started reaching out, I &lt;a class="link" href="https://twitter.com/linked365/status/1153218060632952834" target="_blank" rel="noopener"
>tweeted&lt;/a> about it to the gods of flow and asked in the Flow &lt;a class="link" href="https://powerusers.microsoft.com/t5/Building-Flows/Cloning-a-flow-Location-Trigger/m-p/330343" target="_blank" rel="noopener"
>forum&lt;/a> where I did get a response, basically saying the same, and that the location trigger is in preview.&lt;/p>
&lt;p>So, if you have got this far, how do I fix it?&lt;/p>
&lt;h2 id="outcome-v2">Outcome V2&lt;/h2>
&lt;p>Like I said at the outset, this didn&amp;rsquo;t work for me. Frustration set in, and I forgot the idea. But, as I was putting together this blog post, re-deploying the components as my demo system had expired, it worked!&lt;/p>
&lt;p>So, moving on, we need to sent an email to the user with the playbook for the account. I want to list the last 5 critical cases, last 5 open opportunities, last 5 notes and any description the user has put in.&lt;/p>
&lt;p>It triggers an HTTP request, the schema defined by a sample payload, but contains who triggered the workflow and which account.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-62.png?w=501"
loading="lazy"
>&lt;/p>
&lt;p>Then, a great time for a parallel branch. The Flow retrieves the cases, notes and opportunities in a parallel branch.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-64.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>Each branch does a similar thing, looking at the Notes branch, firstly retrieve the records with a CDS List Records action, using an OData filter and order by, return the top 5 only.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-65.png?w=497"
loading="lazy"
>&lt;/p>
&lt;p>Next, put this in an HTML table, selecting the output from the Get Notes action. I select Advanced option, then Custom columns, this way I can define the order and which columns I want to display.&lt;/p>
&lt;p>The final step is to send an email&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-66.png?w=494"
loading="lazy"
>&lt;/p>
&lt;p>Obviously, this can be customised to your business need, but my example list the cases, opportunities &amp;amp; notes, and reminds them to fill in a contact report.&lt;/p>
&lt;h2 id="summary">Summary&lt;/h2>
&lt;p>So, the user selects a button on an account form, which allows them to receive updates about one of their customers when they enter the location of the account. Easy.&lt;/p>
&lt;p>I tested this with my home address and with a different user and you can see that I get the email through. Veronica is in the US, I wasn&amp;rsquo;t up at 1am writing blogs &amp;amp; fixing Flows.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-67.png?w=1024"
loading="lazy"
>&lt;/p>
&lt;p>You can also see that Flow notifies the user that it has made them an administrator on a Flow.&lt;/p>
&lt;p>This Flow starts with a Flow button on a record, making it a user-initiated process. It could be triggered off a record creation process - If the user follows an Account, create this automation for them, as long as they have opted in.&lt;/p>
&lt;p>There is location tracking in the Field Service application, but that requires the Field Service mobile app and not suited to a Sales person. They just need to install the Flow app on their device and forget it is there.&lt;/p></description></item><item><title>AI Builder - Text AI</title><link>https://linked365.blog/2019/09/05/ai-builder-text-ai/</link><pubDate>Thu, 05 Sep 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/09/05/ai-builder-text-ai/</guid><description>&lt;img src="https://linked365.blog/images/2019/09-image-30.png" alt="Featured image of post AI Builder - Text AI" />&lt;p>My blogging journey started with using &lt;a class="link" href="https://www.luis.ai" target="_blank" rel="noopener"
>LUIS&lt;/a>, one of Microsoft&amp;rsquo;s Cognitive Services to automate case assignment. This &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/" >blog&lt;/a> goes into detail about how this all hung together, using a model defined in LUIS, calling the LUIS endpoint when a new cases are created and classifying the case, by the subject, with the result from the call.&lt;/p>
&lt;p>After my summer break (sorry, but family etc comes first) I thought I would revisit this scenario, but using one of Microsoft&amp;rsquo;s shiny, new AI Builder capabilities, &lt;a class="link" href="https://docs.microsoft.com/en-us/ai-builder/text-classification-overview" target="_blank" rel="noopener"
>Text Classification AI Model&lt;/a>.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario&lt;/li>
&lt;li>Training your Model&lt;/li>
&lt;li>Getting Data&lt;/li>
&lt;li>Publishing the Model&lt;/li>
&lt;li>Using the Tags&lt;/li>
&lt;/ul>
&lt;h2 id="the-scenario">The Scenario&lt;/h2>
&lt;p>In my first blog, I went through the scenario, so not wanting to repeat myself, but for the lazy who don&amp;rsquo;t want to click &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/" >through&lt;/a>&amp;hellip;..&lt;/p>
&lt;p>Big Energy is a supplier of energy products to end users. They have a call centre which handles any query form the customer. As a perceived leader in the sector, it is always wiling to use the latest technology to allow users to interact with them, which reduces the pressure on the customer support centre.&lt;/p>
&lt;p>Big Energy has a mail box configured to accept customer emails about anything and, rather than have a group of 1st line support employees filtering out and categorising the emails based on the content, want to use cognitive services to improve the process of getting the email (the generated case) to the right team.&lt;/p>
&lt;h2 id="using-ai-to-file-the-case">Using AI to file the case&lt;/h2>
&lt;p>LUIS does a great job of this, with a BA providing sample utterances for the model and training it.&lt;/p>
&lt;p>Text Classification AI Model does it slightly differently. The model expects users to provide data (in the CDS) in the form of text blocks and representative tags for the data. Both need to be in the same entity in CDS.&lt;/p>
&lt;p>On a standard Case record, the classification or tag is the subject field. This is a parent record of Case and the tag would be the name of the subject. As subject and case are separate entities, the Text Classification AI model will not work. A field, be it a calculated one, has to be introduced to enable the classification AI to work. Adding data to an entity from a parent entity breaks my &lt;a class="link" href="https://en.wikipedia.org/wiki/Database_normalization" target="_blank" rel="noopener"
>Third Normal Form&lt;/a> training (anyone remember that? Is it still a thing?).&lt;/p>
&lt;p>I have raised this issue as a new &lt;a class="link" href="https://powerusers.microsoft.com/t5/PowerApps-Ideas/Parent-fields-available-as-tags-for-Text-Classification/idi-p/354238" target="_blank" rel="noopener"
>idea&lt;/a> on the PowerApps ideas forum, go there and give it a vote!&lt;/p>
&lt;p>The new logic for our AI model is that the AI will classify the incoming case, adding a tag. This will trigger a flow, changing the subject of the linked case accordingly. This will trigger re-routing of the case like it did in the original LUIS method.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-30.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="training-your-ai">Training your AI&lt;/h2>
&lt;p>With any AI model, it needs training. The AI needs to separate the wheat from the chaff. Creating a model is simple in PowerApps.&lt;/p>
&lt;p>Start at &lt;a class="link" href="https://make.powerapps.com" target="_blank" rel="noopener"
>make.powerapps.com&lt;/a> and select AI Builder, then Build&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>There are 4 options here&lt;/p>
&lt;p>Binary Classification is useful to give a yes / no decision on whether data meets certain criteria. The criteria can be up to 55 fields on the same entity. For example, is a lead with a low current credit limit, high current account value, no kids but has a pink toe nail (shout out to &lt;a class="link" href="https://twitter.com/Themarkchristie" target="_blank" rel="noopener"
>Mark Christie&lt;/a>) likely to get approved for a new loan?&lt;/p>
&lt;p>Form processing is intended to assist users in automated scanned documents to prevent re-keying. An example would be any forms hand written as part of a sales or service process (before you convert to a PowerApp obviously).&lt;/p>
&lt;p>Object detection assists in classification of items, be in types of drink, crisps or bikes, etc.&lt;/p>
&lt;p>Text classification decides on a tag for a block of text, for example, a user could enter a review of a product online and text classification could understand what product it was for or whether it is a positive review.&lt;/p>
&lt;p>All 4 of these have origins in the Cognitive services provided by Azure, LUIS being the big brother of Text Classification.&lt;/p>
&lt;p>Ensure you are in the correct environment. Text Classification only works on data within your CDS environment, so don&amp;rsquo;t expect to reach out to your on-premise SQL server. There are ways to bring data into CDS, not in scope for this discussion.&lt;/p>
&lt;p>Selecting Text Classification displays a form to give you more understanding, and it is here that you name your model&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit Create and then Select Text. This will list all your entities in your CDS environment (in my case, a D365 demo environment).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Select the entity you want, Case for our PoC.&lt;/p>
&lt;p>The interface will then list all the fields suitable for the AI model, namely anything that is a text field. I chose the description field, which is typically the email that the user enters when emailing in a case to the support department.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit the Select Field button and it will present you with a preview of the data in that table.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The next screen is to select your tags. This needs to be in the same table, and as already discussed, is a bit of a limitation to the AI builder. Less normalised data is more common in Canvas apps or SharePoint linked apps, but for structured data environments with relationships and normalised data this is a limitation that will hopefully be removed as Text Classification matures.&lt;/p>
&lt;p>Also, option sets are not available, again another common categorisation technique. Multi-select option sets are an ideal tagging method too. Assume that this will come in time.&lt;/p>
&lt;p>For my PoC, I created a new field, put it on the Case form and started filling it in for a few records.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>Select the separator. If your tag field contains multiple tags, separated by a comma or semi-colon, this is where you configure it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>It also gives you a preview of what the tags the AI build would find using your chosen method. You can see in the No separator option, &amp;ldquo;printer; 3d&amp;rdquo; is one tag, rather than the assume 2 tags as displayed if semi-colon is selected. This depends on your data.&lt;/p>
&lt;p>The next page displays a review for your data and the tags that the AI builder finds.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, select a language for the text field dependent on your data.&lt;/p>
&lt;p>Once selected, train your model. This is where I started to run into problems. My initial population of tags was not enough. The training came back quickly with an error. There should be a minimum of 10 texts per tag, which I didn&amp;rsquo;t have. That would be hundreds of rows. How was I going to automate creating data to give the Text AI enough data to be a suitable demo?&lt;/p>
&lt;h2 id="getting-data">Getting Data&lt;/h2>
&lt;p>I need thousands of records to train my model properly, thousands of records relevant to the tags I create. No online data creator seemed suitable, as it wasn&amp;rsquo;t specific enough, so how? A flow.&lt;/p>
&lt;p>First I created a column in the Contact table to store a number for my contact, a unique no so I can randomise the selection of a contact.&lt;/p>
&lt;p>Next, I need some data for the case description and the tags. This is already done as it is the same as the utterances and intents I used for LUIS, so I exported the LUIS configuration, put the data in an excel file &amp;amp; added a number to that.&lt;/p>
&lt;h2 id="ready-for-the-flow">Ready for the Flow&lt;/h2>
&lt;p>My simple flow is described below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>Ask for the number of cases to create, keep creating cases until you have reached that limit using a random contact and a random description.&lt;/p>
&lt;p>This flow is triggered manually so I start with a manual trigger and also prompt for the number of cases to create,&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>The Subject variable is used later to define the reference for the subject we have chosen.&lt;/p>
&lt;p>The default for loops is 60. I realised late on in the day that you can change that, but breaking up loops is good practice, to limit the scope of what could go wrong, so created a loop within a loop structure for my flow.&lt;/p>
&lt;p>I restrict the inner loop to 50 loops maximum, which means the number of times I run this loop has to be calculated. If I want a 920 cases created, my outer loop would occur 45 times, each creating 50 cases. I would then do a final set for the rest.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>The next steps will initialise some counters used in the loops. I also want to ensure that if the user wants to create less than 50 records, the outer loop doesn&amp;rsquo;t run at all.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>The outer loop will run for the number of loops I have calculated. This is the loop condition. The counter increments as the last thing in the outer loop. The first thing in my outer loop is to reset the case counter. This is the counter for the 0-50. If we are in this inner loop, at least 50 cases will be created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>The first thing it does is get a random contact by using a odata filter to filter on the number field created specifically using a random number from 0-875 (875 being the highest number in that table).&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>Once the contact is retrieved, find a random description / tag combination. The data from the LUIS utterances is held in an Excel file on a Teams site. Again, a rand() function takes a random number up to the maximum in that file.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>Because more than one subject row could be returned and the fact I don&amp;rsquo;t like apply to each inside each other, set the subject Id variable.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>Ready to create a case now.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>Nothing special. It also populates the tag field.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>After some testing, to ensure that the case has the necessary fields entered, the flow was run for a thousand records without an issue.&lt;/p>
&lt;p>Creating data this way isn&amp;rsquo;t quick, 20 mins for 1000 records, but it is easy and allows you to bring in reference data quickly. Superb for PoC environments.&lt;/p>
&lt;h2 id="training-your-model-with-data">Training your Model (with data)&lt;/h2>
&lt;p>Once this data is generated, it was time to re-train my model. It ran through with success this time.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>The model is 97% sure that whatever I throw at it, it should be able to match it against the tags. There is a quick test option here too, which allows entry of a sample phrase to check your model&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>All ready to publish.&lt;/p>
&lt;h2 id="publishing-your-model">Publishing your Model&lt;/h2>
&lt;p>Publishing the model allows it be used within Flow and PowerApps.&lt;/p>
&lt;p>Clicking Publish generates a child table of the entity you first chose where the predictions are stored. The &lt;a class="link" href="https://docs.microsoft.com/en-us/ai-builder/publish-text-classification-model" target="_blank" rel="noopener"
>documentation&lt;/a> states the table will be TC_{model_name} but it created mine with gobbledegook.&lt;/p>
&lt;p>The link on the form helpfully allows you to go straight to the entity in the new customisation interface, where you can change the label of the entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>Also, it is useful to change some of the views, particularly the associated results view. By default it includes name &amp;amp; date, which is pretty useless, so add the tag and the probability.&lt;/p>
&lt;p>As this is a child table of Case, it is by default visible in the case form Related navigation item. In the classic customisation interface, you can change the label of this view.&lt;/p>
&lt;p>As it is published, users can use flow and the Predict action to predict the tag for a given section of text, useful if you want to do stuff before it reaches an environment.&lt;/p>
&lt;p>Now that it is published, you need to allow the model to run. This means it runs every time there is a change to the text field. This is all done via Flow, so will use your flow runs. It stores the result in the new entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>If a case is created now, it automatically creates the tag secondary record.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-case-creation.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="using-the-tags">Using the tags&lt;/h2>
&lt;p>As AI builder generates a record for you with its prediction, and the data is in CDS, it is a simple Flow to utilise that. As it creates a record in the AI Tags table, update the corresponding case to change the subject accordingly.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>Simple trigger when a record is created. The first action is to find the subject from the tag.&lt;/p>
&lt;p>Update the case record with the subject and the tag so the AI can be retrained later.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/09-image-28.png"
loading="lazy"
>&lt;/p>
&lt;p>That&amp;rsquo;s it. Replacing LUIS with a more user friendly environment is definitely a tick in the box for Microsoft. The AI in PowerApps feels like a simple, user friendly stepping stone for a lot of businesses into the AI world. Hopefully, businesses will embrace these simple models to leverage tools to shortcut processes, improving Employee and customer experiences.&lt;/p></description></item><item><title>User Admin - Published App</title><link>https://linked365.blog/2019/07/19/user-admin-published-app/</link><pubDate>Fri, 19 Jul 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/07/19/user-admin-published-app/</guid><description>&lt;img src="https://linked365.blog/images/2019/07-image-33.png" alt="Featured image of post User Admin - Published App" />&lt;p>After being asked on LinkedIn to publish both the apps that I built for the User Security Admin walk-through I have done so on Dynamics Communities &lt;a class="link" href="https://dynamics365society.uk/pab-directory/" target="_blank" rel="noopener"
>Power Platform Bank&lt;/a>&lt;/p>
&lt;h2 id="stand-alone-security--user-app">Stand-Alone Security / User App&lt;/h2>
&lt;p>The first one, which if you remember is a stand-alone application detailed &lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" >here&lt;/a> can be downloaded here&lt;/p>
&lt;p>&lt;a class="link" href="https://dynamics365society.uk/powerappsbanklist/dynamics-ce-security-user-profile-powerapp/" target="_blank" rel="noopener"
>https://dynamics365society.uk/powerappsbanklist/dynamics-ce-security-user-profile-powerapp/&lt;/a>&lt;/p>
&lt;h2 id="embedded-security-app">Embedded Security App&lt;/h2>
&lt;p>The second app was the one after I converted the original to a embedded form in the User record, detailed &lt;a class="link" href="https://linked365.blog/2019/07/07/user-admin-powerapp-part-4/" >here&lt;/a>&lt;/p>
&lt;p>&lt;a class="link" href="https://dynamics365society.uk/powerappsbanklist/dynamics-ce-embedded-security-powerapp/" target="_blank" rel="noopener"
>https://dynamics365society.uk/powerappsbanklist/dynamics-ce-embedded-security-powerapp/&lt;/a>&lt;/p>
&lt;p>Both apps require the custom connector to read and update teams and role, which are included in the package.&lt;/p>
&lt;p>Please let me know if it works for you via &lt;a class="link" href="https://twitter.com/linked365" target="_blank" rel="noopener"
>Twitter&lt;/a> or &lt;a class="link" href="https://www.linkedin.com/in/carlcookson/" target="_blank" rel="noopener"
>LinkedIn&lt;/a>&lt;/p>
&lt;p>Thanks goes to &lt;a class="link" href="https://twitter.com/WeAreTDG" target="_blank" rel="noopener"
>Those Dynamics Guys&lt;/a> for the great Dynamics Community &amp;amp; the PPB as well as &lt;a class="link" href="https://www.linkedin.com/in/schladot/" target="_blank" rel="noopener"
>Joergen Schladot&lt;/a> to giving me the kick up the arse to get it done.&lt;/p></description></item><item><title>User Admin PowerApp (Part 4)</title><link>https://linked365.blog/2019/07/07/user-admin-powerapp-part-4/</link><pubDate>Sun, 07 Jul 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/07/07/user-admin-powerapp-part-4/</guid><description>&lt;img src="https://linked365.blog/images/2019/07-image-33.png" alt="Featured image of post User Admin PowerApp (Part 4)" />&lt;p>As putting a canvas app on a model driven form is now out of &lt;a class="link" href="https://docs.microsoft.com/en-us/business-applications-release-notes/April19/microsoft-powerapps/embedding-canvas-apps-model-driven-forms-generally-enhanced" target="_blank" rel="noopener"
>preview&lt;/a> I thought that my &lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" >PowerApp to add security roles&lt;/a> and teams might be a suitable candidate to be migrated to an embedded canvas app.&lt;/p>
&lt;h2 id="not-going-to-repeat">Not going to repeat&lt;/h2>
&lt;p>There are lots of &lt;a class="link" href="https://www.youtube.com/watch?v=ivvh49bsH0M" target="_blank" rel="noopener"
>videos&lt;/a> and blog &lt;a class="link" href="https://the365hero.com/blog/2018/12/24/embedded-canvas-apps-for-dynamics-365/" target="_blank" rel="noopener"
>posts&lt;/a> out there which detail how to embed a canvas app into model, so there is no point repeating that, just stand on their shoulders.&lt;/p>
&lt;p>Needless to say, there are a few gotchas. I will walk through how I addressed each one.&lt;/p>
&lt;h2 id="the-connection-isnt-there-straight-away">The connection isn&amp;rsquo;t there straight away&lt;/h2>
&lt;p>Rather than displaying the first user selection screen, the embedded app goes straight to the display of user roles and teams. The user selected should come from the record the end user is on. In the original code, I used the selected record, which is available as the user clicked on it.&lt;/p>
&lt;p>From the embedded app, there is a connection to the underlying record, using the ModelDrivenFormIntegrationData property. I found that this was not populated straight away, prior to form visible anyway. To get around this, and I think &lt;a class="link" href="https://twitter.com/ScottDurow" target="_blank" rel="noopener"
>Scott Durrow&lt;/a> demoed this in a &lt;a class="link" href="https://twitter.com/d365uguk" target="_blank" rel="noopener"
>D365 User Group&lt;/a> meeting, you need a wait screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>The Timer has configured to have a duration of 2000ms, with Auto start enabled. On Timer End Event is a simple navigation to the actual start screen.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>I found that this was more than enough to get the data available in my application, so that the On Visible on the main screen could do all the things it needed to do.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-loadscreen.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="dont-forget-to-publish">Don&amp;rsquo;t forget to publish&lt;/h2>
&lt;p>The only way you can really see what is going on in your app is to run it within the D365 form. The debugging of the application is a little contrived when using the embedded app, so I used a liberal amount of labels with string values in there to understand what is being set and which value is being used.&lt;/p>
&lt;p>Fundamentally, you need to publish everytime you need to see the application in your environment. Without the publish, the previous version is shown.&lt;/p>
&lt;h2 id="screen-size-wows">Screen size wows&lt;/h2>
&lt;p>This app is now configured with landscape mode, with Scale to fit, locked aspect ration and locked orientation. This seems to work more effectively for higher resolution screens on Windows machines. The screen scales with its size, which is great, but I would like to see the option for better use of the real estate.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-32.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see, when the screen is large, the buttons and text in the PowerApp gets very big, over the top for mouse users.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-screensizing.gif"
loading="lazy"
>&lt;/p>
&lt;p>If you change the screen properties to remove scale to fit, and alter some of the properties to ensure proper positioning as the screen moves, you get a more appropriate display for large screens, but are limited on tablets etc. Know your audience I guess.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-screensizing2.gif"
loading="lazy"
>&lt;/p>
&lt;h2 id="back-to-the-code">Back to the code&lt;/h2>
&lt;p>The first part is to create a variable with the user data in it. ModelDriverFormIntegration will always be a table, all be it with only row in our case. Using a variable, this single record is available elsewhere. Just a method of not having to repeat that long property line throughout the application.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">userdata&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">First&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">ModelDrivenFormIntegration&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Data&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The next step, was copy and paste from the other version, replacing where the app is expecting a selection of a user with the user id taken from the userdata. Firstly, creating a FetchXML string to derive the teams for the user, then passing this into the flow connector to retrieve the teams.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teamstring&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch top=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; &amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">team&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">isdefault&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemmanaged&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teammembership&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">from&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teamid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teamid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">intersect&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuserid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&amp;#34; &amp;amp; userdata.SystemUserId &amp;amp; &amp;#34;&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">// Stick it in a collection for display on the form
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">ClearCollect&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teams&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">D365FlowConnector&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">GetTeams&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">teamstring&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The format of the application has changed, to a landscape view. I made both the teams and roles grid visible, with a search field at the top. The Teams grids items is set to the collection, with filtering and sorting applied&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-31.png"
loading="lazy"
>&lt;/p>
&lt;p>Next in the on visible event, the FetchXML is built to help in adding teams to the user. Firstly, create a table with the snippets in for the existing teams filters, then creating the actual FetchXML&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teamTable&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span> &lt;span class="nf">ForAll&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teams&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;condition attribute=&amp;#34;&amp;#34;teamid&amp;#34;&amp;#34; operator=&amp;#34;&amp;#34;neq&amp;#34;&amp;#34; value=&amp;#34;&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">teamid&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;&amp;#34;&amp;#34; /&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// create the fetchXML to restrict the teams to those that user has not already got
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teamsNotGot&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch top=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; &amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">team&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">isdefault&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemmanaged&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; Concat(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teamTable&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The process above is also done for the roles. The one gotcha around roles is that there is a business Id field user, but that gives you the name of the BU. If you use the BusinessUnitIdName field, that actually holds the GUID of the BU. Seems counter intuitive to me.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rolesNotGot&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch top=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; &amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">role&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; Concat(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rolesTable&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">businessunitid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; userdata.BusinessUnitIdName &amp;amp; &amp;#34;&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="o">/&amp;gt;&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The final app I think is a much better interface to manage roles and teams for a user. It works well in this context and allows managers to quickly change the roles for who they are concerned with.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-33.png"
loading="lazy"
>&lt;/p></description></item><item><title>Adaptive Cards - Improved Approvals (Part 2)</title><link>https://linked365.blog/2019/07/05/adaptive-cards-improved-approvals-part-2/</link><pubDate>Fri, 05 Jul 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/07/05/adaptive-cards-improved-approvals-part-2/</guid><description>&lt;img src="https://linked365.blog/images/2019/07-image-24.png" alt="Featured image of post Adaptive Cards - Improved Approvals (Part 2)" />&lt;p>Continuing on a walkthrough of creating a more effective adaptive card for approvals, this part will describe the flow I created to generate the card as well as complete the action in D365 depending on the response&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario (&lt;a class="link" href="https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>Preventing progress of an Opportunity ( &lt;a class="link" href="https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/" >Part 1&lt;/a> )&lt;/li>
&lt;li>Using Flow to create a basic Approval ( &lt;a class="link" href="https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/" >Part 1&lt;/a> )&lt;/li>
&lt;li>Creating an Adaptive Card ( &lt;a class="link" href="https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/" >Part 1&lt;/a> )&lt;/li>
&lt;li>Using Flow to create the Approval (This Part)&lt;/li>
&lt;li>Updating the Opportunity (This Part)&lt;/li>
&lt;/ul>
&lt;h2 id="starting-out">Starting out&lt;/h2>
&lt;p>As previously described, the Flow is triggered when a user updates the Develop Propsal checkbox. In the first stages, the flow also retrieves some records that are needed later on for population of the card. There are also initialisations of 2 arrays that are used to populate the approvers and product lines on the card.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>The next section is used to retrieve the approvers for the territory. In part 1, a many to many relationship was added, linking User to Territory via the territory approvers table.&lt;/p>
&lt;p>As the territory approvers table is a many to many relationship, it does not appear as a standard table in the common data service connector, nor the D365 connector. There are various blog posts out there which state you can just use a custom value, naming the table, but I couldn&amp;rsquo;t get it working, so I fell back to my custom connector.&lt;/p>
&lt;p>In my previous post on &lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" target="_blank" rel="noopener"
>Security roles via a PowerApp&lt;/a>, the custom connector which allows an FetchXML string to be sent against an object is used a lot to get the teams and the roles for a user. This connector is again used to find the users associated with a territory via the new relationship. The FetchXML is below.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;fetch&lt;/span> &lt;span class="na">top=&lt;/span>&lt;span class="s">&amp;#39;50&amp;#39;&lt;/span> &lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#39;systemuser&amp;#39;&lt;/span> &lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#39;internalemailaddress&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#39;fullname&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;link-entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#39;cc\_territory\_approver&amp;#39;&lt;/span> &lt;span class="na">from=&lt;/span>&lt;span class="s">&amp;#39;systemuserid&amp;#39;&lt;/span> &lt;span class="na">to=&lt;/span>&lt;span class="s">&amp;#39;systemuserid&amp;#39;&lt;/span> &lt;span class="na">intersect=&lt;/span>&lt;span class="s">&amp;#39;true&amp;#39;&lt;/span> &lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#39;territoryid&amp;#39;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#39;eq&amp;#39;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;@{body(&amp;#39;&lt;/span>&lt;span class="err">Get\_Account\_Manager&amp;#39;)?\[&amp;#39;\_territoryid\_value&amp;#39;\]}&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/link-entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/fetch&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p> This will return JSON which corresponds to the users linked as approvers to the territory.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;@odata.etag&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;W/\\&amp;#34;&lt;/span>&lt;span class="mi">3421832&lt;/span>&lt;span class="err">\\&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;internalemailaddress&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;veronicaq@CRM568082.OnMicrosoft.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;fullname&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Veronica Quek&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;systemuserid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;824da0b2-6c88-e911-a83e-000d3a323d10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ownerid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;824da0b2-6c88-e911-a83e-000d3a323d10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;@odata.etag&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;W/\\&amp;#34;&lt;/span>&lt;span class="mi">1742271&lt;/span>&lt;span class="err">\\&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;internalemailaddress&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;danj@CRM568082.OnMicrosoft.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;fullname&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Dan Jump&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;systemuserid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;e3b305bf-6c88-e911-a83e-000d3a323d10&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ownerid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;e3b305bf-6c88-e911-a83e-000d3a323d10&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;@odata.etag&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;W/\\&amp;#34;&lt;/span>&lt;span class="mi">3422353&lt;/span>&lt;span class="err">\\&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;internalemailaddress&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;CarlC@CRM568082.onmicrosoft.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;fullname&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Carl Cookson&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;systemuserid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;113f1e3a-db90-e911-a822-000d3a34e879&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ownerid&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;113f1e3a-db90-e911-a822-000d3a34e879&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p> An approval needs a list of email addresses, separated with a ; . To achieve this, firstly put each of the returned email addresses in an array, then use the Join function to create the string used for approvers&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-17.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="populated-the-main-approval">Populated the Main approval&lt;/h2>
&lt;p>The next part the body of the approval that is going to be sent. I&amp;rsquo;ll link the full version of this at the end of the article, but effectively, you copy your design, remembering to insert appropriate dynamic content on the way.&lt;/p>
&lt;p>Here, I create the 2 URLs that are displayed in the card, which combine the starting point of url and append Account or Opportunity Id.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>This is displayed at the top of the card.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>Further, formatting currencies is difficult in Flow. (I stand to be corrected). I found this &lt;a class="link" href="https://powerusers.microsoft.com/t5/Using-Flows/Format-number-with-thousands-separator-in-Flow-email/m-p/305263/highlight/true#M7484" target="_blank" rel="noopener"
>post&lt;/a> on Power Platform community which highlights the issue and degvalentine has the solution, which I have tweaked to take into account of null values in the fields in D365. This example is for one of the fields on the secondary grid.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">empty&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">])),&lt;/span> &lt;span class="sc">&amp;#39;0&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">concat&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">greaterOrEquals&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="mi">1000&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">concat&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">substring&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">sub&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">))),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sc">&amp;#39;,&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">substring&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">max&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">sub&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">))),&lt;/span> &lt;span class="mi">3&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">min&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="mi">3&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="nf">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">))))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">first&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">contains&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">concat&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">last&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">)),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="k">if&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">less&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">length&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">last&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">split&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">string&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">manualdiscountamount&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">]),&lt;/span> &lt;span class="sc">&amp;#39;.&amp;#39;&lt;/span>&lt;span class="p">))),&lt;/span> &lt;span class="mi">2&lt;/span>&lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="sc">&amp;#39;0&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="mo">00&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="populating-product-details">Populating Product details&lt;/h2>
&lt;p>As the approval body is built up, the next stage is to create a table with the product lines in it. Getting the lines is a simple filter query using the primary key on Opportunity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>Like with the approvers, an array is populated with a formatted version of each line, taking fields returned and combining them with formatting rules.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>The first expression deals with the fact one of the products chosen to demo had a double quote (&amp;quot;) in it, which messes up JSON if it isn&amp;rsquo;t escaped as it is the string delimiter. I used a simple replace expression to add a &amp;ldquo;\&amp;rdquo; before it.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">replace&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="nf">items&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Add&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_to&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_Prod&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="n">_LInes&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">)&lt;/span>&lt;span class="o">?&lt;/span>&lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">productname&lt;/span>&lt;span class="err">&amp;#39;\&lt;/span>&lt;span class="p">],&lt;/span> &lt;span class="sc">&amp;#39;&amp;#34;&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="err">&amp;#39;\\&lt;/span>&lt;span class="s">&amp;#34;&amp;#39;)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The next expression is the one above to format the currency with the appropriate commas and decimal places.&lt;/p>
&lt;p>The output of this looping of the product lines is then combined using a join again, then combined with the body main string.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>The bottom of this string starts the list of actions, which are the buttons.&lt;/p>
&lt;p>The next step is to create the Approval. This is pretty simple, using a first to respond type, and fleshing it out a bit, so if a user uses the standard Flow Approval interface, they have something to relate to. No notification is needed, this will send an email to the approver, but the Flow will alert the approver via Teams.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>My original design for this PoC was to push this notification / approval to a Team channel, one notice to the Approvers channel. As Teams integrates with D365, it did not seem much of a hop to highlight the Opportunity approval.&lt;/p>
&lt;p>The only issue is that approvals don&amp;rsquo;t work in team channels, only when sent to a user. Until this is resolved by MS, you are limited to sending the approval to an individual in Teams.&lt;/p>
&lt;h2 id="sending-the-approval">Sending the Approval&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>The key bits of this action is ensuring you have the Approvers tenant (can you post approvals across tenants?), the respond link, the approval ID and the creation time populated with the data coming from the approval. The same goes for the Reject action.&lt;/p>
&lt;p>That&amp;rsquo;s it, the new approval is sent.&lt;/p>
&lt;h2 id="waiting-for-the-approval">Waiting for the Approval&lt;/h2>
&lt;p>As the approval is configured that anyone could approve or reject, the next action is to wait for that approval to happen. Approvals can happen upto 30 days, which is another issue, but as this is to speed up the approval process, let&amp;rsquo;s not worry about that.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>If the outcome is approved, then the field Complete Internal Review is checked and a note is created, linked to the Opportunity logging who approved it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>This is in a loop, as, in theory, there could be more than one approver on an approval, if you use the Approval setting that forces everyone to approve something.&lt;/p>
&lt;p>The Regarding / Regarding type, highlighted above, need to be populated as you get orphan records and can spend 20 minutes wondering what is wrong (not me obviously)&lt;/p>
&lt;p>On the Reject side of the condition, the Opportunity is put back to the state it was in before the flow started, namely Develop Proposal is reset. This triggers our Flow again, but as long as the first condition is met, it won&amp;rsquo;t go any further. A note is also added, to highlight who rejected it and why.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-28.png"
loading="lazy"
>&lt;/p></description></item><item><title>Adaptive Cards - Improved Approvals (Part 1)</title><link>https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/</link><pubDate>Thu, 04 Jul 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/07/04/adaptive-cards-improved-approvals-part-1/</guid><description>&lt;img src="https://linked365.blog/images/2019/07-image-12.png" alt="Featured image of post Adaptive Cards - Improved Approvals (Part 1)" />&lt;p>&lt;a class="link" href="https://adaptivecards.io/" target="_blank" rel="noopener"
>Adaptive cards&lt;/a> are relatively new to the stack of tools available to PowerPlatform users, emerging from Message Cards. They are a great way of interacting with users who are not a typical D365 user, those on the periphery who are interested in the data but not the detail.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario (This Part)&lt;/li>
&lt;li>Preventing progress of an Opportunity (This Part)&lt;/li>
&lt;li>Using Flow to create a basic Approval (This Part)&lt;/li>
&lt;li>Creating an Adaptive Card (This Part)&lt;/li>
&lt;li>Using Flow to create the Approval&lt;/li>
&lt;li>Updating the Opportunity&lt;/li>
&lt;/ul>
&lt;h2 id="the-scenario">The Scenario&lt;/h2>
&lt;p>Big Energy is going well, they are now involved in some big deals for big enterprises which need a lot of time to land. The proposals that are generated are complicated, and they struggled with some dubious sales people reducing the margins just to get the deals and this is just bad for business.&lt;/p>
&lt;p>An approval process needs to be implemented, where one or more of a designated group of individuals per territory review the opportunity and decide if the margins are appropriate.&lt;/p>
&lt;p>Unfortunately, the approvers tend to be very busy senior directors, who use D365 sporadically, if at all, and Big Energy need to allow them to approve the opportunities where ever they are using Outlook or Teams as the preferred option.&lt;/p>
&lt;h2 id="tweaking-the-standard-sales-process">Tweaking the standard Sales process&lt;/h2>
&lt;p>Microsoft provides a Business Process Flow for Opportunity management, and in our scenario, only the approvers should be able to check the boolean Complete Internal Review. This is part of the standard Propose stage of the BPF.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>To &amp;ldquo;lock&amp;rdquo; (I know it isn&amp;rsquo;t foolproof, what is?) the progress on Propose, the Complete Internal Review is subject to a simple business rule, if the opportunity is at any stage, lock the field.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, no one can edit that field, if that field is made mandatory to progress the bpf stage, no one can progress the stage past propose.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>Territories are often used in Sales to group accounts or account managers and in our scenario, there is a set list of approvers for a territory. I have added a new many - to - many relationship for this, Approvers and ensured it is listed in the user form as one of the relationships&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-16.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="using-flow-to-create-an-approval">Using Flow to create an Approval&lt;/h2>
&lt;p>In the standard Propose stage, there is another boolean that is of interest, Develop Proposal. The Flow is triggered when this value is changed. A simple CDS update trigger is the starting point.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>The next stage is to confirm that this trigger is coming with the correct record state, the record has been marked with Develop Proposal, but the other field, Complete Internal Review is still empty.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The flow to create the adapted card is fairly intense, well, from my experience, as you will see, so for now, create an Approval using enough details to get the default experience that can be built on.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>In Details, there is a lot you can do, using &lt;a class="link" href="https://docs.microsoft.com/en-us/flow/approvals-markdown-support" target="_blank" rel="noopener"
>markdown&lt;/a> but this is not as comprehensive as the formating you get from adaptive cards.&lt;/p>
&lt;p>When this flow is run, you will get an email to the assigned to with a simple, standard approval, which is in itself, an adaptive card, but it is fairly plain.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Using the Flow history, this action also shows the adaptive card that was built&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Copying this value into the Adaptive card designer JSON section gives the format for a basic design, which can be augmented to show some proper information&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-10.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="building-an-adaptive-card">Building an Adaptive card&lt;/h2>
&lt;p>Adaptive Cards are a means to interact with your users via email, teams or any other app that handles the rendering of them. They have actions, allow images to be presented and can format text in a markup that imitates a comprehensive website. They are supported in Outlook mobile apps as well as O365, either using the main app or online.&lt;/p>
&lt;p>They work by rendering a JSON object, which can be formatted to match the host application (the dark black Teams theme for example renders it very differently, but the core actions are still there.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>Microsoft has built a superb tool to manage Adaptive cards, the new version, at adaptivecards.io/designer. This site has lots of examples to get you started, the &lt;a class="link" href="https://adaptivecards.io/samples/ExpenseReport.html" target="_blank" rel="noopener"
>Expense Report&lt;/a> is a good starting point from a design point of view, but the standard approval card forms the base for the card. There are bits in it that you need to incorporate into your card to allow the approval to work.&lt;/p>
&lt;p>The parts in the data section are the essential bits that, in our adopted JSON need to be duplicated or populated by Flow to allow our card to act as an approval.&lt;/p>
&lt;p>My card is a bit different than the standard, displaying key parts of the Opportunity and the associated product lines.&lt;/p>
&lt;p>&lt;img src="https://linkd365home.files.wordpress.com/2019/07/image-12.png?w=457"
loading="lazy"
>&lt;/p>
&lt;p>As you can see, there is a lot more information on what is happening on the opportunity, probably enough for a sales manager to make a decision in most cases. Included in the card are links to the Account and Opportunity if further review is needed.&lt;/p>
&lt;p>I would recommend starting from a sample and building your content, with dummy data, so you can get the layout correct.&lt;/p>
&lt;p>Each of the buttons are also cards on their own, allowing a comment to be made before the approval is approved or rejected.&lt;/p>
&lt;p>These have been copied from the standard adaptive card produced by the Flow approval so that the submitted approval works like a standard approval.&lt;/p>
&lt;h2 id="some-considerations-and-limitations">Some considerations and limitations&lt;/h2>
&lt;p>I first started trying to reproduce the Expense Approval card in full from the samples&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/07-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>This has a great use of hidden / visible sections of the expense lines which could give you a lot of real estate for Opportunity lines. Unfortunately, these are not rendered in Teams.&lt;/p>
&lt;p>Also, I thought I would be able to use HTTP trigger, but again, any button with an HTTP trigger is ignored in teams, you are only allowed to create actions for opening URLs, submitting, hiding parts and showing a secondary card.&lt;/p>
&lt;p>Below the main part of the designer is the JSON, which is created by any changes you make above but also can be edited and reflected in the visualiser. The snippet below is taken from the standard card, which contains all the bits that need duplicating to ensure the new, improved approval works correctly.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;span class="lnt">21
&lt;/span>&lt;span class="lnt">22
&lt;/span>&lt;span class="lnt">23
&lt;/span>&lt;span class="lnt">24
&lt;/span>&lt;span class="lnt">25
&lt;/span>&lt;span class="lnt">26
&lt;/span>&lt;span class="lnt">27
&lt;/span>&lt;span class="lnt">28
&lt;/span>&lt;span class="lnt">29
&lt;/span>&lt;span class="lnt">30
&lt;/span>&lt;span class="lnt">31
&lt;/span>&lt;span class="lnt">32
&lt;/span>&lt;span class="lnt">33
&lt;/span>&lt;span class="lnt">34
&lt;/span>&lt;span class="lnt">35
&lt;/span>&lt;span class="lnt">36
&lt;/span>&lt;span class="lnt">37
&lt;/span>&lt;span class="lnt">38
&lt;/span>&lt;span class="lnt">39
&lt;/span>&lt;span class="lnt">40
&lt;/span>&lt;span class="lnt">41
&lt;/span>&lt;span class="lnt">42
&lt;/span>&lt;span class="lnt">43
&lt;/span>&lt;span class="lnt">44
&lt;/span>&lt;span class="lnt">45
&lt;/span>&lt;span class="lnt">46
&lt;/span>&lt;span class="lnt">47
&lt;/span>&lt;span class="lnt">48
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="s2">&amp;#34;actions&amp;#34;&lt;/span>&lt;span class="err">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Action.ShowCard&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Approve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;card&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;AdaptiveCard&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;body&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;TextBlock&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;text&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Comments&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;wrap&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Input.Text&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;id&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;comments&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;placeholder&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Enter comments&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;maxLength&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1000&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;isMultiline&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;actions&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;type&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Action.Submit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;title&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Submit&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;data&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Environment&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Default-2821cf92-86ad-4c7b-ba9a-5c79a70d4a21&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ApprovalTitle&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Appoval required for Opportunity&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ApprovalLink&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://flow.microsoft.com/manage/environments/Default-2821cf92-86ad-4c7b-ba9a-5c79a70d4a21/approvals/received/6cce94f6-603c-40e7-adb6-8b20c75f724f&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ApprovalName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;6cce94f6-603c-40e7-adb6-8b20c75f724f&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ItemLink&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;https://.crm.dynamics.com/main.aspx?newWindow=true&amp;amp;pagetype=entityrecord&amp;amp;etn=opportunity&amp;amp;id=b7c47c42-a290-e611-80e3-c4346bacba3c&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ItemLinkDescription&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Opportunity for 7-Eleven and Udaside label - &amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;OnBehalfOfNotice&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Requested by Carl Cookson &amp;lt;CarlC@CRM.onmicrosoft.com&amp;gt;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;CreatorName&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Carl Cookson&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;CreatorEmail&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;CarlC@CRM.onmicrosoft.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;CreationTime&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;\\&amp;#34;&lt;/span>&lt;span class="mi">2019-07-03&lt;/span>&lt;span class="err">T&lt;/span>&lt;span class="mi">14&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">30&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="mi">02&lt;/span>&lt;span class="err">Z\\&lt;/span>&lt;span class="s2">&amp;#34;&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;MessageTitle&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Appoval required for Opportunity&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;Options&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Approve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s2">&amp;#34;Reject&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;SelectedOption&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;Approve&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;ActionType&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">1&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">],&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;$schema&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;http://adaptivecards.io/schemas/adaptive-card.json&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div></description></item><item><title>User Admin PowerApp (Part 3)</title><link>https://linked365.blog/2019/06/23/user-admin-powerapp-part-3/</link><pubDate>Sun, 23 Jun 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/06/23/user-admin-powerapp-part-3/</guid><description>&lt;img src="https://linked365.blog/images/2019/06-image-22.png" alt="Featured image of post User Admin PowerApp (Part 3)" />&lt;p>The user has been notified that they have a new report, the manager has updated some fields on their user record, they now want to add some roles and teams to allow them to start work.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario (&lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1//" >Part 1&lt;/a>)&lt;/li>
&lt;li>Notifying the manager of a new Employee (&lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>PowerApp to display and update User Data (&lt;a class="link" href="https://linked365.blog/2019/06/18/user-admin-powerapp-part-2/" >Part 2&lt;/a>)&lt;/li>
&lt;li>Update Roles and Teams (This Part)&lt;/li>
&lt;/ul>
&lt;h2 id="listing-roles-that-user-hasnt-got">Listing Roles that user hasn&amp;rsquo;t got&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>The grid at the bottom of the user screen shows the roles that the user has. If we want to add a role to that list, firstly lets display the roles available to them.&lt;/p>
&lt;p>On the form visible event, there is a lot going on. I have already discussed defining the XML to get the list of roles and teams for the user. In this code I also create XML to retrieve the roles the user hasn&amp;rsquo;t got. Again, &lt;a class="link" href="https://jonasr.app/fxb/" target="_blank" rel="noopener"
>FetchXML Builder&lt;/a> is your friend.&lt;/p>
&lt;p>A looping concatenation isn&amp;rsquo;t available (well not this week) in PowerApps, so you have to get around this by populating a table with one or more strings then concatenating the output of the table.Using the Set command, create a variable and populate it with a string like below using the ForAll command to repeat the string build for each of the roles the user has got.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rolesTable&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">(&lt;/span> &lt;span class="nf">ForAll&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">secGroups&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;condition attribute=&amp;#34;&amp;#34;roleid&amp;#34;&amp;#34; operator=&amp;#34;&amp;#34;neq&amp;#34;&amp;#34; value=&amp;#39;&amp;#34;&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">role2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;&amp;#39; /&amp;gt;&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">))&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This, when you then use the ConCat command creates one string with these as many parts in in as roles the user has.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#34;neq&amp;#34;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;0699ab9b-984c-4896-9c8a-38352fdc3c93&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#34;neq&amp;#34;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;d77e2e20-4eac-4fbf-b1a8-5bec6f853ebf&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The final string combines this string with the other bits that I am interested in, selecting the attributes that is required as well as filtering the roles return to only those in the users BU. If this condition is not put in, all the roles that are associated with all the BUs will be returned. In D365, a role is duplicated for each BU you create, and you need to associate the user with the right role for their BU.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rolesNotGot&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch top=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; &amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">role&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; Concat(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">rolesTable&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">businessunitid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; MyReports.Selected.&amp;#39;Business Unit&amp;#39;.businessunitid &amp;amp; &amp;#34;&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="o">/&amp;gt;&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>This produces an XML that looks like the below.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;fetch&lt;/span> &lt;span class="na">top=&lt;/span>&lt;span class="s">&amp;#34;50&amp;#34;&lt;/span> &lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;role&amp;#34;&lt;/span> &lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;name&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;filter&lt;/span> &lt;span class="na">type=&lt;/span>&lt;span class="s">&amp;#34;and&amp;#34;&lt;/span> &lt;span class="nt">&amp;gt;&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#34;neq&amp;#34;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;0699ab9b-984c-4896-9c8a-38352fdc3c93&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#34;neq&amp;#34;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;d77e2e20-4eac-4fbf-b1a8-5bec6f853ebf&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#34;businessunitid&amp;#34;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#34;eq&amp;#34;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;ec0e9d51-0e91-e911-a822-000d3a34e879&amp;#39;&lt;/span>&lt;span class="nt">/&amp;gt;&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/fetch&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>On selecting the plus button at the top of the grid for Roles, another collection is populated using the custom connector, passing the XML to the Roles definition.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Collect&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">groupsandteams&lt;/span>&lt;span class="p">,&lt;/span>&lt;span class="n">D365FlowConnector&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">GetAllRoles&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">rolesNotGot&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="add-role-screen">Add Role screen&lt;/h2>
&lt;p>The final screen is a simple gallery, with the name of the role displayed.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>All the work is done on the + icon. This calls another custom connector, adding the role to the user. Postman is your friend here. My Postman to insert a role for a user is shown below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>Basically, this is posting a body containing a systemuserroles_asscociation to the the webapi, which creates a new one. The user reference is in the URL and the roleId is in the body.&lt;/p>
&lt;p>Now, I confess I am not the most offay on the best way to use the Web API. This is one of the reasons I am writing a blog, learning. See that little highlighted $ref? I spent hours trying to get this working and only found that this is required at the end. If you omit the $ref, it returns a positive result. Same if you try to add a role that belongs to a BU that the user doesn&amp;rsquo;t. Someone tell me where this is logged so next time I can do some troubleshooting rather than trial &amp;amp; error?&lt;/p>
&lt;p>The D365 &lt;a class="link" href="https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/webapi/associate-disassociate-entities-using-web-api#associate-entities-on-update-using-collection-valued-navigation-property" target="_blank" rel="noopener"
>document&lt;/a> does mention it, but it is simply missed and it is part of the OData standard for &lt;a class="link" href="http://docs.oasis-open.org/odata/odata/v4.0/cs01/part2-url-conventions/odata-v4.0-cs01-part2-url-conventions.html#_Toc365046422" target="_blank" rel="noopener"
>addressing references between entities&lt;/a>. As I say, learn everyday.&lt;/p>
&lt;p>To convert this to a custom connector definition the GUID of the user account in the URL needs to be replaced with a parameter, note the curly brackets and looks like the below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-25.png"
loading="lazy"
>&lt;/p>
&lt;p>In PowerApps, after refreshing the connector, there is a new method on our connector. On click of the + in the Add role screen, this is called.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">D365FlowConnector&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">AddRole&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MyReports&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Selected&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;https://urlofyourcrm.crm.dynamics.com&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;/api/data/v9.0/roles(&amp;#34;&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="n">roleid&lt;/span> &lt;span class="o">&amp;amp;&lt;/span> &lt;span class="s">&amp;#34;)&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Even though the second parameter has been hidden and given a default value in the connector, it still prompts to be entered. Not sure why.&lt;/p>
&lt;p>The Teams addition is the same logic, but a different connecting entity. The postman for this is below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-26.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="deleting-a-role">Deleting a Role&lt;/h2>
&lt;p>To complete the circle, a manager should be able to delete a role or team that the user belongs to. This is again done via a custom connector, the postman is below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-27.png"
loading="lazy"
>&lt;/p>
&lt;p>As with the create definition, the 2 guids in the url need to be swapped out so the definition is created like this&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-28.png"
loading="lazy"
>&lt;/p>
&lt;p>Once refreshed in PowerApps, this is connected to the remove button on the Roles grid.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="n">D365FlowConnector&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">DeleteRole&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">MyReports&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Selected&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">User&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">role2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>After this call, the grids are refreshed to show the action has taken effect.&lt;/p>
&lt;p>Teams works in the same way, using the url like this&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>And that is it! This app works well to bridge the gap for onboarding users in a busy enterprise, especially as a PowerApp, it is available to users on the go.&lt;/p>
&lt;p>Custom Connectors really bring the availability of all the standard Customer Engagement functionality to the &amp;ldquo;citizen developer&amp;rdquo;. As enterprise level organisations get on board with PowerApps, small apps that make the employee experience easier will become necessary. This is only an example of how this could be done. Reach out if you would like me to share the app with you.&lt;/p></description></item><item><title>User Admin PowerApp (Part 2)</title><link>https://linked365.blog/2019/06/18/user-admin-powerapp-part-2/</link><pubDate>Tue, 18 Jun 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/06/18/user-admin-powerapp-part-2/</guid><description>&lt;img src="https://linked365.blog/images/2019/06-image-3.png" alt="Featured image of post User Admin PowerApp (Part 2)" />&lt;p>So, after notifying the user that there is a new employee in their team, the manager needs to be able to update the data.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario (&lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>Notifying the manager of a new Employee (&lt;a class="link" href="https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>PowerApp to display and update User Data (This Part)&lt;/li>
&lt;li>Update Roles and Teams&lt;/li>
&lt;/ul>
&lt;h2 id="my-reports">My Reports&lt;/h2>
&lt;p>I am not going to go through how to create a PowerApp, there are numerous blogs and pages that step you through this, may I recommend the Microsoft &lt;a class="link" href="https://powerapps.microsoft.com/en-us/blog/microsoft-powerapps-learning-resources/" target="_blank" rel="noopener"
>page&lt;/a> with it all on?&lt;/p>
&lt;p>My PowerApp is pretty straight forward at the start. The first screen is to retrieve all the users that the current logged in user manages, connected to a User data source in the CDS.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Start with a new List form, connect it to your CDS User data set and select a few fields. With the List form, there are several parts that you need to configure, to make the buttons at the top of the screen to work correctly.&lt;/p>
&lt;p>Firstly, the Items property needs to be configured to correctly display and filter the data according to the search the user has selected and the sort.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">SortByColumns&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">Search&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">Filter&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Users&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">Manager&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">internalemailaddress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">User&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Email&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">TextSearchBox2&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Text&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;fullname&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">),&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;fullname&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">If&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SortDescending&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SortOrder&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Descending&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">SortOrder&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">Ascending&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>The core to this is the Filter, where the Users (the data source) is filtered to only show those where the email address of the manager of the user is the current users email address.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Filter&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Users&lt;/span>&lt;span class="p">,&lt;/span> &lt;span class="n">Manager&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">internalemailaddress&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nf">User&lt;/span>&lt;span class="p">().&lt;/span>&lt;span class="n">Email&lt;/span>&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Wrapped around this is functionality to sort and search this grid.&lt;/p>
&lt;p>BTW, the picture is the &amp;lsquo;Entity Image&amp;rsquo; field in the data set, the picture that a user can upload into D365 against their user account.&lt;/p>
&lt;h2 id="user-details">User Details&lt;/h2>
&lt;p>The next screen is a standard edit form, navigated to via the little arrow with this logic&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Select&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">Parent&lt;/span>&lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Navigate&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">Employee&lt;/span> &lt;span class="n">Edit&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">ScreenTransition&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="n">CoverRight&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>The form again connects to the User data set, with the item in the edit portion being the significant bit&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>I have just selected some random fields to display here, where I think it would be appropriate to manage. The Business Unit is a key field for a user, and is a selection and needs a little help to display the right data and update the record appropriately.&lt;/p>
&lt;p>Start by adding the field. If you select the datacardvalue control (the drop down itself in the form), notice that a couple of things are wrong.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Business Unit is a parent of User, a relationship Lookup, and PowerApps has decided (not sure why, the default for lookups surely should be the name field, which is how D365 works) to select the Address1_City field to display to the user when they are selecting. Change this to &amp;ldquo;name&amp;rdquo;. Change the search as well to match.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Now, the form will display the BU of the user as well as allowing an update of this field.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-10.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="displaying-security-roles">Displaying Security Roles&lt;/h2>
&lt;p>At the bottom of the edit form are 2 grids to display the users security roles and their teams. Both operate in the same way.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>To get at the roles for a user, you have to use a bit of FetchXML. There is a hidden link table, or a collection value navigation, systemuserroles_association, which links a role with a user.&lt;/p>
&lt;p>If you are using any sort of FetchXML, &lt;a class="link" href="https://jonasr.app/fxb/" target="_blank" rel="noopener"
>&lt;/a>&lt;a class="link" href="https://jonasr.app/fxb/" target="_blank" rel="noopener"
>FetchXML Builder&lt;/a> (FXB) by &lt;a class="link" href="https://twitter.com/rappen" target="_blank" rel="noopener"
>Jonas Rapp&lt;/a> is essential. It allows a developer to define the exact fields, the connections and filters to form a query for data by looking at the data model. Start with a blank query, select the systemuser entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>In our scenario, the query should return the roles for one user, the one that has been selected by the manager. Add a filter, then a condition, select the systemuserroles entity, and the systemuserid attribute (field). The operator is equals and the value is the GUID of the user account.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>To test the query, paste in the GUID of the user. Another great tool is the Chrome Addon, &lt;a class="link" href="https://chrome.google.com/webstore/detail/level-up-for-dynamics-365/bjnkkhimoaclnddigpphpgkfgeggokam" target="_blank" rel="noopener"
>Level Up for Dynamics&lt;/a> by &lt;a class="link" href="https://twitter.com/RajYRaman/" target="_blank" rel="noopener"
>Natraj Yegnaraman&lt;/a> allows you to quickly get to the GUID of any record, as well as some other useful tools (please don&amp;rsquo;t tell an end user about God Mode). The query should retrieve all the fields on the User entity for the chosen user.&lt;/p>
&lt;p>Next, select a link-entity, namely the many to many systemuserroles.systemuserid -&amp;gt; systemuserid.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>Executing this query will result in a lot of fields been returned, most of no interest to our query, so add some attributes, which limits the fields returned. Only interested in the roleId and the name.&lt;/p>
&lt;p>Hit execute this time and this will display the roles that are associated with the user selected.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>This is all well and good, but how is this data getting into the PowerApp? A custom connector of course. I have used custom connectors a lot to get at the bits the standard CDS connector can&amp;rsquo;t in my other posts. I won&amp;rsquo;t discuss how to create the connector, my post on &lt;a class="link" href="https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/" target="_blank" rel="noopener"
>LUIS&lt;/a> covers that. I expand on it fixing the &lt;a class="link" href="https://linked365.blog/2019/05/11/creating-attachments-in-d365/" target="_blank" rel="noopener"
>bug on creating attachments in D365&lt;/a>.&lt;/p>
&lt;h2 id="creating-the-connector-definition">Creating the Connector Definition&lt;/h2>
&lt;p>Again, Postman is your friend here. Each of the main entities will accept FetchXML as a parameter, as in this is what is created in Postman&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;span class="lnt">19
&lt;/span>&lt;span class="lnt">20
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-xml" data-lang="xml">&lt;span class="line">&lt;span class="cl">{{WebAPIUrl}}/systemusers?fetchXml=&lt;span class="nt">&amp;lt;fetch&lt;/span> &lt;span class="na">mapping=&lt;/span>&lt;span class="s">&amp;#34;logical&amp;#34;&lt;/span> &lt;span class="na">count=&lt;/span>&lt;span class="s">&amp;#34;50&amp;#34;&lt;/span> &lt;span class="na">version=&lt;/span>&lt;span class="s">&amp;#34;1.0&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;systemuser&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;fullname&amp;#34;&lt;/span> &lt;span class="nt">/&amp;gt;&amp;lt;filter&lt;/span> &lt;span class="na">type=&lt;/span>&lt;span class="s">&amp;#39;and&amp;#39;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;condition&lt;/span> &lt;span class="na">attribute=&lt;/span>&lt;span class="s">&amp;#39;systemuserid&amp;#39;&lt;/span> &lt;span class="na">operator=&lt;/span>&lt;span class="s">&amp;#39;eq&amp;#39;&lt;/span> &lt;span class="na">value=&lt;/span>&lt;span class="s">&amp;#39;EBD3707B-6C88-E911-A83E-000D3A323D10&amp;#39;&lt;/span> &lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;lt;/filter&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;link-entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;systemuserroles&amp;#34;&lt;/span> &lt;span class="na">from=&lt;/span>&lt;span class="s">&amp;#34;systemuserid&amp;#34;&lt;/span> &lt;span class="na">to=&lt;/span>&lt;span class="s">&amp;#34;systemuserid&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;link-entity&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;role&amp;#34;&lt;/span> &lt;span class="na">from=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span> &lt;span class="na">to=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span>&lt;span class="nt">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;name&amp;#34;&lt;/span>&lt;span class="nt">/&amp;gt;&amp;lt;attribute&lt;/span> &lt;span class="na">name=&lt;/span>&lt;span class="s">&amp;#34;roleid&amp;#34;&lt;/span>&lt;span class="nt">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/link-entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/link-entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/entity&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="nt">&amp;lt;/fetch&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Paste this into a new connector action and PowerApps will convert the fetchXML as a new parameter for the action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>Test this action with a copy and paste of the XML that you generated in FetchXML Builder and the action will return a bit of XML itself&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-17.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="using-the-connector-in-the-app">Using the Connector in the app&lt;/h2>
&lt;p>Add the custom connector as a Data source in the App.&lt;/p>
&lt;p>To call the connector, on the OnVisible of the Employee Edit form, generate the XML first. Set a variable to the XML generated from FXB, substituing the current selected user id as appropriate&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl"> &lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">secString&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch mapping=&amp;#34;&amp;#34;logical&amp;#34;&amp;#34; count=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; version=&amp;#34;&amp;#34;1.0&amp;#34;&amp;#34;&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuser&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">fullname&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">systemuserid&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="err">&amp;#39;&lt;/span>&lt;span class="s">&amp;#34; &amp;amp; MyReports.Selected.User &amp;amp; &amp;#34;&lt;/span>&lt;span class="err">&amp;#39;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuserroles&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">from&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuserid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuserid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">role&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">from&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">roleid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>MyReports is the list on the first screen, Selected is the user that the manager has selected. PowerApps converts the User to the GUID of the user (handy). Be careful with the quotes here, I found when pasting, curly versions of the straight quotes came in ( “ rather than &amp;ldquo;) which took me a while to resolve. Also, ensure all the double quotes are present. FXB provides single quotes and hence you need to double up for PowerApps to infer an actual quote rather than the end of the string.&lt;/p>
&lt;p>Update: Thanks to &lt;a class="link" href="https://twitter.com/rappen" target="_blank" rel="noopener"
>Jonas Rapp&lt;/a> for reaching out on Twitter to put me right. In FXB there is a setting to use single quotes rather than double in the rendered XML&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>This then allows a straight copy / paste into your PowerApp&lt;/p>
&lt;p>Set(
secString,&amp;quot;&lt;fetch top='50' >
&lt;entity name='systemuser' >
&lt;filter type='and' >
&lt;condition attribute='systemuserid' operator='eq' value='" &amp; MyReports.Selected.User &amp; "' />
&lt;/filter>
&lt;link-entity name='systemuserroles' from='systemuserid' to='systemuserid' intersect='true' >
&lt;link-entity name='role' from='roleid' to='roleid' >
&lt;attribute name='name' />
&lt;attribute name='roleid' />
&lt;/link-entity>
&lt;/link-entity>
&lt;/entity>
&lt;/fetch>&amp;rdquo;&lt;/p>
&lt;p>After the string is created, pass this to the custom connector, inserting the return into a collection. This is the collection that is shown in the grid.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl"> &lt;span class="c1">// Get the groups for the selected user
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1">&lt;/span>&lt;span class="nf">ClearCollect&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">secGroups&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">D365FlowConnector&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nf">GetSecGroups&lt;/span>&lt;span class="p">(&lt;/span>&lt;span class="n">secString&lt;/span>&lt;span class="p">).&lt;/span>&lt;span class="n">value&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Put a gallery on the form, and use this collection as its items list, and sorted by the role just for usability.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>The Teams grid is populated very much the same. The connector is based around the teams entity rather than the system user (in hindsight, I should have based the roles one of roles, rather than user, but achieves the same result, and it is all about learning isn&amp;rsquo;t it?). The XML looks like this.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-c" data-lang="c">&lt;span class="line">&lt;span class="cl">&lt;span class="nf">Set&lt;/span>&lt;span class="p">(&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="n">teamstring&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="s">&amp;#34;&amp;lt;fetch top=&amp;#34;&amp;#34;50&amp;#34;&amp;#34; &amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">team&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">attribute&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">name&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">isdefault&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemmanaged&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="mi">0&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span> &lt;span class="n">name&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teammembership&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">from&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teamid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">to&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">teamid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">intersect&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="nb">true&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">filter&lt;/span> &lt;span class="n">type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">and&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;&lt;/span>&lt;span class="n">condition&lt;/span> &lt;span class="n">attribute&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">systemuserid&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">operator&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span>&lt;span class="n">eq&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&lt;/span> &lt;span class="n">value&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">&amp;#34;&amp;#34;&amp;#34; &amp;amp; MyReports.Selected.User &amp;amp; &amp;#34;&amp;#34;&amp;#34;&lt;/span> &lt;span class="o">/&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">filter&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">link&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">entity&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;/&lt;/span>&lt;span class="n">fetch&lt;/span>&lt;span class="o">&amp;gt;&lt;/span>&lt;span class="s">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">);&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>teammembership is the connecting table.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>So, that is enough for now, the app displays users that report to me, I can see their teams and roles. Next post will show how the teams and roles are updated.&lt;/p></description></item><item><title>User Admin PowerApp (Part 1)</title><link>https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/</link><pubDate>Mon, 10 Jun 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/06/10/user-admin-powerapp-part-1/</guid><description>&lt;img src="https://linked365.blog/images/2019/06-image-3.png" alt="Featured image of post User Admin PowerApp (Part 1)" />&lt;p>Sorry it has been a while since my last blog post, this scenario has taken a while to get it to the state where I was happy to show it off. Mainly due to my own lack of understanding of the intricacies of the D365 API, but also been busy external to the blog, you know real life.&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Scenario (This part)&lt;/li>
&lt;li>Notifying the manager of a new Employee (This Part)&lt;/li>
&lt;li>PowerApp to display and update User Data&lt;/li>
&lt;li>Update Roles and Teams&lt;/li>
&lt;/ul>
&lt;h2 id="the-scenario">The Scenario&lt;/h2>
&lt;p>Big Energy Co is going from strength to strength, presumably because of the innovative solutions using &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/" >LUIS&lt;/a>, &lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >Alexa&lt;/a> and &lt;a class="link" href="https://linked365.blog/2019/05/04/ifttt-flow-d365/" >IFTTT&lt;/a>.&lt;/p>
&lt;p>The HR department is ramping up recruitment and new teams are being shaped to support all the growth.&lt;/p>
&lt;p>One of the criticisms from the managers is that it takes a while for the IT / D365 administrators to get users in the correct teams and security roles so they can be effective in D365.&lt;/p>
&lt;p>A clever chap in the management team suggested that they be given an app that would allow a manager to update the roles and teams (and other relevant parts of a user) without resorting to logging into D365 administration. Something they can use wherever they have WiFi or a data connection.&lt;/p>
&lt;p>It would also be good to get a notification when they have a new employee, or someone is added to their reports.&lt;/p>
&lt;h2 id="the-flow">The Flow&lt;/h2>
&lt;p>This flow is quite simple, trigger an email when a user has the Manager field (parentsystemuserid) field updated. O365 will create the user for us (assuming you are in the cloud) and an administrator will still have to update the users manager.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Here, the attribute I am interested on is parentsystemuserid.&lt;/p>
&lt;p>Next, just check to see if the manager is actually populated. In a lot of businesses, removing their manager is part of the process on off-boarding an employee, to tidy up selection lists etc.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>Then, get the manager user record from D365 so that the email can be sent to it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/06-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>Told you it was simple. I am sure that this can have more logic - Do we need an approval step before assigning this user? Do we have to wait for HR to do some work and only activate the user once all the checks are done?&lt;/p>
&lt;p>Next, I&amp;rsquo;ll step through the PowerApps set up to retrieve data from my reports.&lt;/p></description></item><item><title>Archives</title><link>https://linked365.blog/archives/</link><pubDate>Tue, 28 May 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/archives/</guid><description/></item><item><title>Creating Attachments in D365</title><link>https://linked365.blog/2019/05/11/creating-attachments-in-d365/</link><pubDate>Sat, 11 May 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/05/11/creating-attachments-in-d365/</guid><description>&lt;img src="https://linked365.blog/images/2019/05-squirrel-eating.jpg" alt="Featured image of post Creating Attachments in D365" />&lt;p>This isn&amp;rsquo;t one of my usual posts as I always like to start with a business case. I intend to create a blog about the business case / solution that created this issue once all the other  pieces fall into place, so watch out for that (keep them keen by teasing they say)&lt;/p>
&lt;h2 id="the-problem">The Problem&lt;/h2>
&lt;p>You might not know there is a problem, but there is. Squirrels are a problem, but not my field of expertise, &lt;a class="link" href="https://twitter.com/dynamiccrmcat" target="_blank" rel="noopener"
>@dynamiccrmcat&lt;/a> will have other opinions.&lt;/p>
&lt;p>Attachments are a problem. More specifically, trying to add an attachment to D365 via a Flow or PowerApp is a problem. Yes I know we should be using SharePoint or Teams etc, but sometimes you want to keep your data in D365.&lt;/p>
&lt;p>You should just be able to &amp;ldquo;Patch&amp;rdquo; the Notes entity in a PowerApp with the file you want in the documentbody field of the entity, but you run into problems (bug) with objecttypecodes (it is expecting a GUID and all you know is an entity name).&lt;/p>
&lt;p>&lt;a class="link" href="https://twitter.com/jukkan" target="_blank" rel="noopener"
>@JukkaN&lt;/a> pointed me to this &lt;a class="link" href="https://powerusers.microsoft.com/t5/General-Discussion/Not-able-to-create-the-attachment-regarding-any-entity/td-p/193465" target="_blank" rel="noopener"
>article&lt;/a> on the PowerApp forum which explains the problem in more detail and clearer than I have. This was via a conversation with him and &lt;a class="link" href="https://twitter.com/TattooedCRMGuy" target="_blank" rel="noopener"
>@TattooedCRMGuy&lt;/a> where we came to the conclusion that there is a bug in the CDS connector.&lt;/p>
&lt;p>So my next thought was to call a Flow from the PowerApp, passing in the file as a parameter. This doesn&amp;rsquo;t work either. Any which way you try, it ends up with the file being passed as the link to the Azure blob the PowerApp is temporarily using to store the attachment.&lt;/p>
&lt;p>Then I started using the developers friend, Google. My first thought is that if I could pass to the Flow a file rather than the URL, this would work. This thought led me to an excellent Youtube &lt;a class="link" href="https://www.youtube.com/watch?v=mp-8B1fLrqs&amp;amp;feature=youtu.be" target="_blank" rel="noopener"
>video&lt;/a> by Paul Culmsee. He shows how to pass a Photo from PowerApps to Flow to save it to Sharepoint. He has the same issue, how to pass a file to flow, and thanks to him, I have duplicated it for saving a file to D365.&lt;/p>
&lt;p>So the logic I have deployed is&lt;/p>
&lt;p>PowerApps → Custom Connector → Flow → Custom Connector into D365&lt;/p>
&lt;p>2 custom connectors here, this is a relative expensive solution, as the user require a PowerApps Plan 1 license for this which might be an addon to their license.&lt;/p>
&lt;h2 id="the-d365-connector">The D365 Connector&lt;/h2>
&lt;p>Starting at the final step, I utilised a custom connector like in my &lt;a class="link" href="https://linked365.blog/2019/05/04/ifttt-flow-d365/" >previous&lt;/a> &lt;a class="link" href="https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/" >posts&lt;/a> to interact with the D365 API directly. I am not going to go through the method of creating the connector, just this custom action. Again, PostMan is your friend. Using this tool, I generated a JSON template to post against the Annotations entity. Firstly, add an action to the connector. &lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>Next, select Import from sample, and populate as below, obviously using your own instance API endpoint.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Couple of things here, Annotation is the name of the table that Notes are stored in. &amp;ldquo;objectid_contact@odata.bind&amp;rdquo; is the single value navigation for linking Contact to the note. In the CDS connector, this field is not visible, you are expected to enter a pair of _objectid_value and objecttypecode, which doesn&amp;rsquo;t work, hence this blog post (I hope they fix it, but not too soon now I have worked it out). Finally, documentbody is the field where the attachment is stored, as a Base64 string. This is weirdly different than the binary data store used by Sharepoint.&lt;/p>
&lt;p>Select Import and the first connector is done.&lt;/p>
&lt;h2 id="the-flow">The Flow&lt;/h2>
&lt;p>The flow is pretty simple, a HTTP trigger, messing around with the inputs and sending the information to the D365 connector. Simple, but I needed the video by Paul Culmsee to guide me through. The premise being, rather than the usual approach of looking at the body of the web call, we need to take out parts from the query string and the content of the call would be a file. He does a much better job at explaining it that I do, so head over to the &lt;a class="link" href="https://www.youtube.com/watch?v=mp-8B1fLrqs&amp;amp;feature=youtu.be" target="_blank" rel="noopener"
>video&lt;/a> to actually learn.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>A standard HTTP trigger. I then use a Compose data operation to take data from the trigger using a formula based on the query parameters passed.&lt;/p>
&lt;p>trigger()[&amp;lsquo;outputs&amp;rsquo;][&amp;lsquo;queries&amp;rsquo;][&amp;lsquo;filename&amp;rsquo;]&lt;/p>
&lt;p>This states that I want find and store the filename parameter passed in the url when the trigger was triggered&lt;/p>
&lt;p>The Get File Body does the same but looks at the content of the body that was passed in.&lt;/p>
&lt;p>triggerMultipartBody(0)[&amp;rsquo;$content&amp;rsquo;]&lt;/p>
&lt;p>The final part is a call to the D365 custom connector, passing in the compose operation outputs&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-11.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="another-custom-connector">Another Custom Connector&lt;/h2>
&lt;p>You can&amp;rsquo;t call a webservice triggered flow from a PowerApp directly. You can call a Flow, but the flow doesn&amp;rsquo;t pass the appropriate parameters. It only deals with strings. You can&amp;rsquo;t convert your file to a string in PowerApps. I am obviously going to be proved wrong here, but I will learn. That&amp;rsquo;s one of the reasons I blog.&lt;/p>
&lt;p>Hence, why you need to create a custom connector to pass from PowerApps to the Flow above.&lt;/p>
&lt;p>Connectors can be created by uploading a swagger definition. &lt;a class="link" href="https://en.wikipedia.org/wiki/Swagger_%28software%29" target="_blank" rel="noopener"
>Swagger&lt;/a> is an open-source framework to document APIs and has been recently converted to the OpenAPI specification. Obviously connectors can be built from scratch, but because of the file upload that is required, a definition of the API is required.&lt;/p>
&lt;p>Paul again comes to my rescue, he has a great &lt;a class="link" href="http://www.cleverworkarounds.com/2017/11/13/a-sample-openapiswagger-file-for-powerapps/" target="_blank" rel="noopener"
>blog&lt;/a> post that he goes through in detail the file that was produced to support his video. In the Youtube post, he uses a tool that I can not find, but this file walkthrough was enough for me to produce my own &lt;a class="link" href="https://1drv.ms/u/s!AueNWhtMOmpUiqszYVB8owfI-DLujA" target="_blank" rel="noopener"
>file&lt;/a>. I am not going to go through the detail here, Paul does a much better job.&lt;/p>
&lt;p>In custom connectors, hit the +, then select Import an OpenAPI file.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>Give your new connector a name and select your newly created file definition. If your file is correct, you are now presented with a pre-populated definition of your connector. The query parameters displayed include lots of configuration items that should be pre-populated from your Swagger file.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>You can see the connector is not expecting a Body.&lt;/p>
&lt;p>If you test the connector action there is also an extra parameter it is expecting&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>This File parameter is essential. Now it&amp;rsquo;s reading for use!&lt;/p>
&lt;h2 id="the-powerapp">The PowerApp&lt;/h2>
&lt;p>To demonstrate the connector, create a new PowerApp. Because this is for the contact entity, use a drop down to get a list of Contacts to attach the note to from D365.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>Associate this with D365 using the Common Data Service&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>Select the Contacts Entity, back in the properties of the control, use Full Name as the Value. Next, add a &amp;ldquo;Add Picture&amp;rdquo; control.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>Also add a datatable. This time connect to the Annotation (Notes) entity in D365. Make sure you use the D365 connector though. For some reason, the Common Data Service connector does not return the Regarding as a field you can use. Select a few relevant fields, Title, Note, File Name and Document.&lt;/p>
&lt;p>In the Values field, filter the datatable by the Contact that is selected in the dropdown and only show those where there is an attachment.&lt;/p>
&lt;p>Filter(Notes, Regarding = GUID(ContactDD.Selected.Contact) &amp;amp;&amp;amp; !IsBlank(Document))&lt;/p>
&lt;p>Selecting a contact now should deliver a list of notes that are attached to that record.&lt;/p>
&lt;p>To Upload a document, add a button. This will trigger the custom connector, so this needs to be added to the PowerApp. Select Data sources, add data source&lt;/p>
&lt;p>The custom connector that was created earlier should appear. Select it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>In the button OnSelect action, if all is well, enter the name of the connector and action and it should give you a list of parameters you need.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>The final call to the connector looks like this&lt;/p>
&lt;p>FileUploader.UploadFile(
AddMediaButton1.FileName,
ContactDD.Selected.Contact,
&amp;ldquo;Added from PowerApps&amp;rdquo;,
&amp;ldquo;Added from PowerApps&amp;rdquo;,
UploadedImage1.Image
);
Refresh(Notes)&lt;/p>
&lt;p>The filename comes from the control within the Image upload control, the contact Id is from the selected contact, some text stuff to fill out (you could add a text control to take that input obviously) and then the image.&lt;/p>
&lt;p>I refresh the notes data set after I am done so that the list has got the data.&lt;/p>
&lt;p>So that&amp;rsquo;s it, a complicated solution to a &amp;ldquo;bug/feature&amp;rdquo; currently in Powerapps.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>A screenshot of that squirrel note against the contact in D365, just so you know I am not bluffing.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>BTW, squirrels are evil, rats with marketing, don&amp;rsquo;t believe everything &lt;a class="link" href="https://twitter.com/dynamiccrmcat" target="_blank" rel="noopener"
>@dynamiccrmcat&lt;/a> says, though it is probably just squirrels she is wrong about.&lt;/p></description></item><item><title>IFTTT Flow D365</title><link>https://linked365.blog/2019/05/04/ifttt-flow-d365/</link><pubDate>Sat, 04 May 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/05/04/ifttt-flow-d365/</guid><description>&lt;img src="https://linked365.blog/images/2019/05-image-67.png" alt="Featured image of post IFTTT Flow D365" />&lt;p>This will be a quick post, as the connector doesn&amp;rsquo;t take a lot of configuration.&lt;/p>
&lt;h2 id="the-business-scenario">The Business Scenario&lt;/h2>
&lt;p>Big Energy has a lot of sales people, all over the country, which make a lot of calls, usually on their mobiles, to potential or current customers, arranging opportunities and resolving any issues.&lt;/p>
&lt;p>The Sales Director at Big Energy is concerned about the number of calls that the sales people don&amp;rsquo;t always log those calls, only when they deem it important and have no traceability about how many calls an individual has made.&lt;/p>
&lt;p>Could a solution be found that would log every call a sales person makes to a number D365 knows about?&lt;/p>
&lt;h2 id="ifttt">IFTTT&lt;/h2>
&lt;p>&lt;a class="link" href="https://ifttt.com" target="_blank" rel="noopener"
>IFTTT&lt;/a> (IF This Then That) is a free web service that allows users to create applets to connect their devices with their services. There are lots of sample applets to automate tasks, my favourite is linking Alexa&amp;rsquo;s shopping list with Tesco to add everything I add to Alexa to my Tesco order. Simples.&lt;/p>
&lt;p>IFTTT works with a lot of devices and it has a stand alone app for smart phones, allowing interaction with the device.&lt;/p>
&lt;h3 id="getting-started">Getting Started&lt;/h3>
&lt;p>Log in to IFTTT and go to My Applets, then New Applet. Hit the big blue this&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-64.png"
loading="lazy"
>&lt;/p>
&lt;p>Search for phone, and select Android Phone Call (sorry think this is only Android users)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-65.png"
loading="lazy"
>&lt;/p>
&lt;p>This presents you with several triggers, the IF part. Select Any Phone Call placed. You will have to make another App for received, but same logic.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-66.png"
loading="lazy"
>&lt;/p>
&lt;p>The next step is to tell IFTTT what you want to do, select the big That button&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-67.png"
loading="lazy"
>&lt;/p>
&lt;p>IFTTT lets you search for all the available services that you can trigger from your data. Search for Web and select Webhooks.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-68.png"
loading="lazy"
>&lt;/p>
&lt;p>The only option here is to make a web request.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-69.png"
loading="lazy"
>&lt;/p>
&lt;p>If you have read my previous articles (if not go &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/" >here&lt;/a> or &lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >here&lt;/a> now and shame on you), creating a Flow trigger from a web request should be straight forward.&lt;/p>
&lt;h2 id="create-the-flow">Create the Flow&lt;/h2>
&lt;p>As in the previous articles, start with a generic http trigger in Flow. Firstly, select HTTP trigger, and enter a default body for the JSON. This is generic enough to allow the call so the schema passed from IFTTT can be created.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-70.png"
loading="lazy"
>&lt;/p>
&lt;p>As the action, send yourself an email, with the Body of the email being the body of the request.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-71.png"
loading="lazy"
>&lt;/p>
&lt;p>Hit save and go back to the trigger. This URL is the bit you need to pop back into IFTTT.&lt;/p>
&lt;h2 id="connecting-flow-and-ifttt">Connecting Flow and IFTTT&lt;/h2>
&lt;p>Back in the IFTTT Web Request, paste in the URL. I have changed the Method to Post, content type to json and included in the Body 3 ingredients (data returned by the call placed method trigger into the body. This is formatted appropriately to become a valid JSON Request&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-72.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-74.png"
loading="lazy"
>&lt;/p>
&lt;p>This is now ready for testing.&lt;/p>
&lt;h2 id="testing">Testing&lt;/h2>
&lt;p>For testing to commence, a call needs to be logged. This means you need to install the IFTTT app on your phone, log in and check the app you created is available.&lt;/p>
&lt;p>Once this is done, make a call.&lt;/p>
&lt;p>If successfully, your Flow should run, sending you an email. If not, you can look in the IFTTT log by checking the activity log.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-75.png"
loading="lazy"
>&lt;/p>
&lt;p>The log highlights what happened for each run, when it was updated etc. Not as user friendly as Flow, but at least you get an error code. I found I was getting 400 errors, as the format for the JSON wasn&amp;rsquo;t correct.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-77.png"
loading="lazy"
>&lt;/p>
&lt;p>My email also has the information sent from the request, this is used to tell Flow properly what is expected, allowing access to the properties.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-79.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="is-the-contact-known">Is the Contact known?&lt;/h2>
&lt;p>The assumption is that not all calls made by the user will be to known contacts. Either unknown to D365 or personal calls. The first thing that is required is to find the contact. Using the List Records component, use a filter query to return all contacts that match the data coming from IFTTT with any of the phone numbers held against contact. Be careful here, as the number as entered by the user in the contact on their phone or as dialed is used here.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-80.png"
loading="lazy"
>&lt;/p>
&lt;p>The next step is to check if any contacts were found. As previously, check the length of the return from the previous step has one or more contacts in it. Add the contact id to a variable if contacts were returned, terminate with grace if not.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-83.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="create-the-phone-call">Create the Phone Call&lt;/h2>
&lt;p>Creating the phone call is a straight forward call to the CDS Create Record action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image.png"
loading="lazy"
>&lt;/p>
&lt;p>Couple of formulas here, firstly the timestamp that comes from IFTTT looks like&lt;/p>
&lt;p>May 01, 2019 at 05:50PM&lt;/p>
&lt;p>Flow doesn&amp;rsquo;t like this, so the expression for Due is&lt;/p>
&lt;p>replace(triggerBody()?[&amp;lsquo;occuredat&amp;rsquo;], &amp;rsquo; at &amp;lsquo;,&amp;rsquo; &amp;lsquo;)&lt;/p>
&lt;p>Duration from IFTTT is in seconds, in D365 is minutes. A simple divide by 60 puts in the right value&lt;/p>
&lt;p>div(int(triggerBody()?[&amp;lsquo;callLength&amp;rsquo;]),60)&lt;/p>
&lt;p>Flow is complete.&lt;/p>
&lt;h2 id="can-it-be-be-recorded-better">Can it be be recorded better?&lt;/h2>
&lt;p>The call that Flow creates is missing 2 key components, the From and To&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>The CDS connector doesn&amp;rsquo;t support &lt;a class="link" href="https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/activity-entities" target="_blank" rel="noopener"
>activity parties&lt;/a> (these fields are both party fields, the user can type and search for multiple contacts, users, leads etc to populate this normally). You can get at these via standard API calls, so back to the custom connector.&lt;/p>
&lt;p>My previous &lt;a class="link" href="https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/" >post&lt;/a> on LUIS used a custom connector to close the incident using an action. This walks through creating the connector, so I won&amp;rsquo;t repeat myself.&lt;/p>
&lt;p>I will step through the specific action for creating the call, as it isn&amp;rsquo;t straight forward. Further, Postman is still your friend. The only way I managed to get this configured is relying on this great tool.&lt;/p>
&lt;p>Using Postman, the format of the JSON can be defined, based on the API reference for &lt;a class="link" href="https://docs.microsoft.com/en-us/dynamics365/customer-engagement/web-api/phonecall?view=dynamics-ce-odata-9" target="_blank" rel="noopener"
>Phonecalls&lt;/a>. This highlights that activity parties are created, and associated with the call to create the phonecall.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;span class="lnt">15
&lt;/span>&lt;span class="lnt">16
&lt;/span>&lt;span class="lnt">17
&lt;/span>&lt;span class="lnt">18
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-json" data-lang="json">&lt;span class="line">&lt;span class="cl">&lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;subject&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;CC Test&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;scheduledend&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2019-05-01 12:00&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;regardingobjectid\_contact@odata.bind&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/contacts(A651968A-5660-E911-A973-000D3A3ACAF8)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;directioncode&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="kc">true&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;scheduleddurationminutes&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="mi">6&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;phonenumber&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;test&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;phonecall\_activity\_parties&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="err">\&lt;/span>&lt;span class="p">[&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;partyid\_contact@odata.bind&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/contacts(A651968A-5660-E911-A973-000D3A3ACAF8)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;participationtypemask&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;2&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">},&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">{&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;partyid\_systemuser@odata.bind&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;/systemusers(C3AE1146-AD6D-E911-A984-000D3A3AC0C2)&amp;#34;&lt;/span>&lt;span class="p">,&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="nt">&amp;#34;participationtypemask&amp;#34;&lt;/span>&lt;span class="p">:&lt;/span> &lt;span class="s2">&amp;#34;1&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="err">\&lt;/span>&lt;span class="p">]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="p">}&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Take this JSON body and copy into a new action in your custom connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-2.png"
loading="lazy"
>&lt;/p>
&lt;p>Enter details in the general page, just enough to uniquely identify your action. Of course, you need to be a bit more descriptive if you plan on shipping out the connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Import from Sample, Select Post, the URL should be just PhoneCalls, paste the JSON above into the body&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Flow does some magic and now you can update your connector. I tried testing this, but got a little confused (me of little brain) so I assumed that Flow is good and would handle it and went straight to using the connector in Flow.&lt;/p>
&lt;p>Back in Flow, select a new action, custom connector, the new one you just created and the action established.&lt;/p>
&lt;p>The populate as below. I know the parameters are not the best names, someone with a bit more time would have tidied this up.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>These are the same formulas that were used earlier. You need to add the &amp;ldquo;/contacts(&amp;rdquo; etc to each GUID as the data bind requires it.&lt;/p>
&lt;p>Run the Flow and just like that, the Phone Call is created in D365 with a Call To correctly established.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/05-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>Call From is missing, IFTTT doesn&amp;rsquo;t let the Web call know who called it. I have searched, but IFTTT is meant for home grown activity, so if you have registered the app, you should know the call. The easiest way around this is to pass in a hardcoded value (email) specific to the end user so a System user can be looked up and populated in the parties field.&lt;/p></description></item><item><title>Alexa, Field Service and Me (Part 3) - Creating Work Orders</title><link>https://linked365.blog/2019/04/25/alexa-field-service-and-me-part-3-creating-work-orders/</link><pubDate>Thu, 25 Apr 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/04/25/alexa-field-service-and-me-part-3-creating-work-orders/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-image-31.png" alt="Featured image of post Alexa, Field Service and Me (Part 3) - Creating Work Orders" />&lt;p>This is a continuation of my series on a proof of concept to allow Alexa to interact with D365 Field Service&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Business scenario (&lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >Part 1&lt;/a>&lt;/li>
&lt;li>Create an Alexa Skill (&lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>Connect the Skill to D365 (&lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" >Part 2&lt;/a>)&lt;/li>
&lt;li>Use Field Service to book an appointment (This Part)&lt;/li>
&lt;li>Return the information to Alexa (&lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" >Part 2&lt;/a>)&lt;/li>
&lt;/ul>
&lt;p>In this final (unless I need to expand on the scenarios) part of the story, Flow will be used to take the information garnered from the user and create a work order.&lt;/p>
&lt;h2 id="calling-a-sub-flow">Calling a Sub-flow&lt;/h2>
&lt;p>The original flow was all about Alexa, but what about other voice assistants? Flow is no different that any other programming languages and as such we can use the same concepts to writing decent flows, one of them being re-usability. If the code to write the Work order and book it is generic, it can be re-used when Google or Siri is connected to the application.&lt;/p>
&lt;p>To this end, the Flow starts with another HTTP trigger, which is called from the previous flow.&lt;/p>
&lt;p>Just like when connection Flow to Alexa, the URL is required in the child to update the caller. Create a new Flow, using the When a HTTP request is received. As content to the JSON Schema, add just enough to get you going and use the output to send an email so that the schema coming from the parent flow can be seen. This is a repart of the logic used to start our parent flow.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Once saved, the URL will be generated in the trigger step. Use this to call the child Flow from the parent. This is the HTTP action. The Method is a POST, the URI is the trigger URL defined in the child Flow. No headers are required. In the body, add in the things that are already known, just to ensure repeat calls to D365 are made. The Intent is also passed in, which has all the details about what the user wanted.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-55.png"
loading="lazy"
>&lt;/p>
&lt;p>Now ready for testing, ensure both Flows are in Test mode and trigger Alexa. After a little delay, an email should be sent in the child Flow detailing enough information to create a Work Item.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-56.png"
loading="lazy"
>&lt;/p>
&lt;p>Use this email to populate the JSON as previously, easily creating the schema that is required.&lt;/p>
&lt;h2 id="creating-a-work-order">Creating a Work Order&lt;/h2>
&lt;p>Next, get the Account the contact is associated with. This is done with a call to the D365 Instance using the Common Data Service Connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-57.png"
loading="lazy"
>&lt;/p>
&lt;p>A Work Order needs some fields to be set before it can be save, Work Order Type is one of them. This could be hard coded, but Alexa has supplied the intent. To match the Work order type with the intention in Alexa, a field on the Work Order Type was added, Alexa Intent, which is searched for in the CDS List Records action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-58.png"
loading="lazy"
>&lt;/p>
&lt;p>To make the Flow easier to manage and reduce the dual looping, the Work Order Type is returned to a variable&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-60.png"
loading="lazy"
>&lt;/p>
&lt;p>Once the data for the new Work Order is available, create the Work Order using the CDS Create Record connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-61.png"
loading="lazy"
>&lt;/p>
&lt;p>Most of these are obvious, but the one that is not is the Work Order Number. In Field Service, this is automated, with a prefix and a number range. As this doesn&amp;rsquo;t work in Flow, a work number is generated using a random number, using an expression.&lt;/p>
&lt;p>rand(10000,100000)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-62.png"
loading="lazy"
>&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-63.png"
loading="lazy"
>&lt;/p>
&lt;p>A few other parts of the work order are populated, helping the service manager to match the time as appropriate.&lt;/p></description></item><item><title>Alexa, Field Service and Me (Part 2) - Linking to Flow</title><link>https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/</link><pubDate>Sat, 20 Apr 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-image-31.png" alt="Featured image of post Alexa, Field Service and Me (Part 2) - Linking to Flow" />&lt;p>This is a continuation of my series on a proof of concept to allow Alexa to interact with D365 Field Service&lt;/p>
&lt;h2 id="objectives">Objectives&lt;/h2>
&lt;ul>
&lt;li>The Business scenario (&lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>Create an Alexa Skill (&lt;a class="link" href="https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/" >Part 1&lt;/a>)&lt;/li>
&lt;li>Connect the Skill to D365 (This part)&lt;/li>
&lt;li>Use Field Service to book an appointment (&lt;a class="link" href="https://linked365.blog/2019/04/25/alexa-field-service-and-me-part-3-creating-work-orders/" >Part 3&lt;/a>)&lt;/li>
&lt;li>Return the information to Alexa (This part)&lt;/li>
&lt;/ul>
&lt;p>In this post I will be linking Alexa to D365 and returning some information back to the end user.&lt;/p>
&lt;h2 id="receiving-information-from-alexa">Receiving information from Alexa&lt;/h2>
&lt;p>Alexa interacts with the outside world with a HTTPS request. Once Alexa has determined that it understands the user and they have asked for something of your skill, it posts to the web service you have configured.&lt;/p>
&lt;p>That API Guy had a great &lt;a class="link" href="https://thatapiguy.tech/2019/03/11/alexa-ask-microsoft-flow-to-read-out-my-latest-e-mail/" target="_blank" rel="noopener"
>post&lt;/a> where he links his Alexa to his O365 email account and has Alexa read out his new email. This article steps through linking Alexa and Flow, and it showed me how simple that part of the integration is. Microsoft has done the hard work by certifying it&amp;rsquo;s connections, you just need to create one.&lt;/p>
&lt;p>Flow provides several methods of subscribing to HTTP events, but the one we are interested in is at the bottom&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-33.png"
loading="lazy"
>&lt;/p>
&lt;p>The URL is generated for you, and is the bit you need to post into Alexa Skill configuration once we have created the Flow. In the JSON schema, we just want a stub for now. The schema is defined by Alexa and how you configure the skill. It is best to get the connection up and running and use the initial call to substitute the schema later.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-34.png"
loading="lazy"
>&lt;/p>
&lt;p>Every Flow needs at least one action to be able to save, so to aid testing and understand the JSON sent by Alexa, the first step is to send an email to myself with the content of the call.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-35.png"
loading="lazy"
>&lt;/p>
&lt;p>Saving the flow and go back to the trigger&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-36.png"
loading="lazy"
>&lt;/p>
&lt;p>A specific trigger URL for our Flow is now generated.&lt;/p>
&lt;h3 id="back-in-alexa">Back in Alexa&lt;/h3>
&lt;p>In Alexa, on the left in the Skill is Endpoints. Alexa allows different endpoints to the skill depending on the Alexa region as well as a fall back. As this is a POC, using the default is appropriate.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-37.png"
loading="lazy"
>&lt;/p>
&lt;p>The important part of this is the drop down below the URL copied from Flow, this needs to be the second option &amp;ldquo;&lt;em>My development endpoint is a sub-domain of a domain that has a wild card certificate from a certificate authority&lt;/em>&amp;rdquo;. Basically, Microsoft has certified all their Flow endpoints with wild card certificates, allowing Amazon to trust that it is genuine.&lt;/p>
&lt;p>One saved, Build your skill again. I found every time I touched any configuration or indeed anything in Alexa, I needed to rebuild.&lt;/p>
&lt;h2 id="testing">Testing&lt;/h2>
&lt;p>Ready to test. Alexa allows you to test your connection via the Test tab within your skill.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-38.png"
loading="lazy"
>&lt;/p>
&lt;p>You have to select Development from the drop down. You can also use this interface to check Production skills.&lt;/p>
&lt;p>A word of warning, everytime you build, to test that new build, I found I had to re-select Development in this window by toggling between &amp;ldquo;Off&amp;rdquo; and &amp;ldquo;Development&amp;rdquo;.&lt;/p>
&lt;p>Back in Flow, test your flow by confirming that you will conduct the action.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-39.png"
loading="lazy"
>&lt;/p>
&lt;p>In the Test panel in Alexa, enter a phrase with your Invocation and Utterance in Alexa entry and if Alexa understands it is for your invocation, your flow should be triggered! Alexa will complain, as our simple flow hasn&amp;rsquo;t returned anything to it. We&amp;rsquo;ll worry about that later.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-40.png"
loading="lazy"
>&lt;/p>
&lt;p>In our simple Flow, I used email as the action, as can be seen below.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-41.png"
loading="lazy"
>&lt;/p>
&lt;p>This is the raw JSON output of the Alexa skill and this is used to tell Flow what to expect. This way it will provide the rest of the Flow with properties that are more appropriate.&lt;/p>
&lt;p>Back in the Flow trigger, select Use sample payload to generate schema, which presents the text entry, where you paste in the email body.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-42.png"
loading="lazy"
>&lt;/p>
&lt;p>Flow does the hard work now and presents you with a schema for what Alexa is sending your Flow&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-43.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="authenticating-the-user">Authenticating the user&lt;/h2>
&lt;p>Taking triggers from Alexa, hence a user is all well and good, but they expect a rapid response. Alexa Skills are public domain once you publish it, anyone can enable your skill, hence a little work needs to be done to understand who is calling our skill and whether Big Energy Co supports them.&lt;/p>
&lt;h3 id="which-user-is-it">Which User is it?&lt;/h3>
&lt;p>The request from Alexa does include a unique reference of the user, but normally businesses like Big Energy Co work on email addresses, which you can get from Alexa, but the user has to give you permission. This can be pre-approved when the end user installs the skill or you can ask for approval.&lt;/p>
&lt;p>Alexa needs to be told that your skill would like this permission. This allows Alexa to request this permission for you when your skill is enabled by the user&lt;/p>
&lt;p>On the left hand menu, there is a Permissions link, where our skill asks for the email address&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-45.png"
loading="lazy"
>&lt;/p>
&lt;p>To ask Alexa for an users email address is a seperate web call with properties from original message sent from Alexa in the trigger.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-44.png"
loading="lazy"
>&lt;/p>
&lt;p>Alexa provides each session an access token so that Flow can ask for more information from Alexa in the context of the users session, location, names, email etc. As this is a globally distributed system, the api End point can vary depending on where the user started their session. The URI at the end asks for the email address of the user of the session.&lt;/p>
&lt;p>Alexa may refuse to return the email address, because the end user has not given permission for our skill to share this information. If the call to get the email was a success, it means that Alexa has returned the value and the Flow can continue&lt;/p>
&lt;p>Without the permission, the call fails and so the Flow captures this. Remember to set a run after for this step to ensure it still runs on failure. Otherwise the flow will fail not so gracefully.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-46.png"
loading="lazy"
>&lt;/p>
&lt;p>Alexa provides standard permission request functionality, the Flow responds to the original call with this detail in a JSON formatted string, with the permissions the Skill wants listed. Finally, for this failure, let the Flow terminate successfully. The Flow can&amp;rsquo;t continue without the information.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-47.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="does-big-energy-co-support-the-user">Does Big Energy Co support the user?&lt;/h3>
&lt;p>It is not enough that the user has asked us for help, they need to be known to Big Energy, as a contact. Querying D365 for this data is the next step&lt;/p>
&lt;p>Using the D365 connector, query the contact entity for the email address that Alexa has given us.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-48.png"
loading="lazy"
>&lt;/p>
&lt;p>A conditional flow checks to see if the return from the Retrieve Contact step has a single record using an expression below&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-54.png"
loading="lazy"
>&lt;/p>
&lt;p>length(body(&amp;lsquo;Retrieve_Contact&amp;rsquo;)?[&amp;lsquo;value&amp;rsquo;])&lt;/p>
&lt;h2 id="responding-to-the-user-quickly">Responding to the user, quickly&lt;/h2>
&lt;p>Like any Alexa Skill, the user expects an immediate response. Flow in itself is quick, but when it comes to updating or creating records, it can take seconds. The timeout for your response to Alexa is 10 seconds, which isn&amp;rsquo;t a lot when you want to look up several things to create the appropriate work order.&lt;/p>
&lt;p>To get around this, respond to the user once you know you have all the information you need to create the appropriate records in D365. Here, the Flow responds if the contact is in our database. In production, you could do some more checks or just assume that if the contact is known, the logic could create an opportunity to sell them a contract if nothing else. Equally, terminate gracefully after responding that Big Energy Co doesnt know the customer, prompting them to ring the service desk.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-51.png"
loading="lazy"
>&lt;/p>
&lt;p>In the switch statement, a response to the user is built up. Specific, personalised responses using the data you have retrieved is essential to give the customer an understanding that you have received the request and will respond.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-50.png"
loading="lazy"
>&lt;/p>
&lt;p>The responses are short and to the point but personalised to the customer and what they asked for with some expressions to add more information if they told Alexa.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-52.png"
loading="lazy"
>&lt;/p>
&lt;p>This snippet adds after &amp;ldquo;request for a Service&amp;rdquo; what the user asked for a service on, relying on the JSON formatted values.&lt;/p>
&lt;p>if(equals(triggerBody()?[&amp;lsquo;request&amp;rsquo;]?[&amp;lsquo;intent&amp;rsquo;]?[&amp;lsquo;slots&amp;rsquo;]?[&amp;lsquo;device&amp;rsquo;]?[&amp;lsquo;value&amp;rsquo;], &amp;lsquo;&amp;rsquo;), &amp;lsquo;&amp;rsquo;, concat(&amp;rsquo; for your &amp;lsquo;,triggerBody()?[&amp;lsquo;request&amp;rsquo;]?[&amp;lsquo;intent&amp;rsquo;]?[&amp;lsquo;slots&amp;rsquo;]?[&amp;lsquo;device&amp;rsquo;]?[&amp;lsquo;value&amp;rsquo;]))&lt;/p>
&lt;p>This snippet adds to the end a sentence including the date that the user asked for.&lt;/p>
&lt;p>if(equals(triggerBody()?[&amp;lsquo;request&amp;rsquo;]?[&amp;lsquo;intent&amp;rsquo;]?[&amp;lsquo;slots&amp;rsquo;]?[&amp;lsquo;date&amp;rsquo;]?[&amp;lsquo;value&amp;rsquo;],&amp;rsquo;&amp;rsquo;),&amp;rsquo;&amp;rsquo;,concat( &amp;lsquo;We will endeavour to send an engineer on &amp;lsquo;,triggerBody()?[&amp;lsquo;request&amp;rsquo;]?[&amp;lsquo;intent&amp;rsquo;]?[&amp;lsquo;slots&amp;rsquo;]?[&amp;lsquo;date&amp;rsquo;]?[&amp;lsquo;value&amp;rsquo;]))&lt;/p>
&lt;p>Finally, for the Alexa response part, the Flow returns a response to the user. This combines the body with a little standard text. This is what Alexa will say. You can also add a response to the screen for those devices able to do that.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-53.png"
loading="lazy"
>&lt;/p>
&lt;p>The final part of this flow goes on and creates the work order. I seperated out the flows using a sub flow, which is discussed in the next part of the blog.&lt;/p></description></item><item><title>Alexa, Field Service and Me (Part 1)</title><link>https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/</link><pubDate>Fri, 19 Apr 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/04/19/alexa-field-service-and-me-part-1/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-image-31.png" alt="Featured image of post Alexa, Field Service and Me (Part 1)" />&lt;p>As we all now have smart devices in our home, linking them to business applications could be a key differentiator between winners and the also rans. This series of posts will demonstrate how I connected Alexa to D365 Field service.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-31.png"
loading="lazy"
>&lt;/p>
&lt;h4 id="objectives">Objectives&lt;/h4>
&lt;ul>
&lt;li>The Business scenario (this part)&lt;/li>
&lt;li>Create an Alexa Skill (this part)&lt;/li>
&lt;li>Connect the Skill to D365 (&lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" target="_blank" rel="noopener"
>Part 2&lt;/a>)&lt;/li>
&lt;li>Use Field Service to book an appointment (&lt;a class="link" href="https://linked365.blog/2019/04/25/alexa-field-service-and-me-part-3-creating-work-orders/" target="_blank" rel="noopener"
>Part 3&lt;/a>)&lt;/li>
&lt;li>Return the information to Alexa (&lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" target="_blank" rel="noopener"
>Part 2&lt;/a>)&lt;/li>
&lt;/ul>
&lt;h2 id="our-scenario---big-energy-co">Our Scenario - Big Energy Co&lt;/h2>
&lt;p>Our generic big energy company is diversifying into support and maintenance of home energy products, boilers, central heating, plumbing, electricals and numerous other aspects of a consumer&amp;rsquo;s home life. A client will ring up, tell the support desk that they have an issue with the appliance and the employee will book a suitable engineer in to come out to their home. This is all done via Field Service in D365. Big Energy also have scheduled servicing of Boilers on an annual basis.&lt;/p>
&lt;p>What the CTO wants to do is embrace the in home virtual assistant to promote Big Energy as a forward thinking organisation which is at the forefront of technology to allow Big Energy&amp;rsquo;s customers to book an engineers visit via their smart device. Her expectation is that Alexa, Google Home or Siri will allow a service call to be booked without talking to the support desk. This will allow meaningful interactions with their customers 24/7.&lt;/p>
&lt;p>The proof of concept will start with the front runner in the war of virtual assistance, mostly because I have one.&lt;/p>
&lt;h2 id="alexa">Alexa&lt;/h2>
&lt;p>If you have read my introduction to &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365/" target="_blank" rel="noopener"
>LUIS&lt;/a> in Alexa Skill concepts are a mirror of the concepts introduced in LUIS. Alexa has Utterances &amp;amp; Intents. Entities are called Intent Slots for Alexa. Alexa has also got another concept, that being the Invocation.&lt;/p>
&lt;p>First off, get yourself an Amazon account &amp;amp; sign up for the developer program at &lt;a class="link" href="https://developer.amazon.com/" target="_blank" rel="noopener"
>developer.amazon.com.&lt;/a> This is all free. People can buy skills, but not sure Big Energy&amp;rsquo;s customers would think this is appropriate.&lt;/p>
&lt;p>Use the Create Skill button, enter a name &amp;amp; select a language. I also choose Custom &amp;amp; Provision your own to allow us to send data to Flow which is hosting our integration.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>Then I select Start from scratch, none of the others seem to match our scenario&lt;/p>
&lt;h3 id="invocation">Invocation&lt;/h3>
&lt;p>An Invocation is the starting point and is the differentiator between you and every other Alexa skill out there. It is effectively a name for your skill, what the user would say to call your skill. I have slightly altered my invocation to put some spaces in there so it is more natural to the end user.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-24.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="intents">Intents&lt;/h3>
&lt;p>Like in LUIS, intents are a category or what the user is looking for or asking. You can have many intents per skill. In our scenario around home appliances the user can ask for a service, a repair or an emergency as a starting point. Let&amp;rsquo;s start with a request for service.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-25.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="utterances">Utterances&lt;/h3>
&lt;p>Utterances are samples to train Alex to understand the intent in natural language. Add as many utterances as you like as samples of how a person would ask for a service or repair, but ensure they are different.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-26.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="slots">Slots&lt;/h3>
&lt;p>In my sample utterances above you can see I have added Slots. Slots are the same as entities in LUIS, data that the user gives us when they are saying their utterance in addition to the type of thing they want.&lt;/p>
&lt;p>Each Slot has a type, and I have used the default Amazon types except for device, which is a custom one.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-28.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="slot-types">Slot Types&lt;/h3>
&lt;p>Amazon has 43 of it&amp;rsquo;s own list types or 6 built in types for numbers &amp;amp; dates, but devices are not in the list. I want to know what type of thing the engineer is going out to fix, not sure I need to be that specific, but would be good to know if I need to send an electrician, gas engineer or plumber. I have added my own Slot Type, called it device and I now list the values I expect.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-29.png"
loading="lazy"
>&lt;/p>
&lt;p>You also should also enter synonyms, not everyone calls it a telly, just us northeners.&lt;/p>
&lt;p>Once you have entered enough intents &amp;amp; utterances, time to build and test. A nice message lets you know when it is done building. Ready for the utterance profiler or testing&lt;/p>
&lt;h2 id="utterance-profiler">Utterance Profiler&lt;/h2>
&lt;p>In the top right, is a pop out to test your utterances. Enter an utterance you haven&amp;rsquo;t used before to check you are getting the expected results.&lt;/p>
&lt;p>The text I wrote is in blue, it has decided that this is a service intent, with a device of boiler &amp;amp; the day of wednesday.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-30.png"
loading="lazy"
>&lt;/p>
&lt;p>You can carry on fine tuning your utterances, intents and slots to get the most accurate model. Like any language understanding, this will be an ongoing model.&lt;/p>
&lt;p>This is Alexa done, we have configured everything we need to in Alexa, apart from our link to Flow. This needs a bit of pre-work in Flow to activate, in the next &lt;a class="link" href="https://linked365.blog/2019/04/20/alexa-field-service-and-me-part-2-linking-to-flow/" target="_blank" rel="noopener"
>post&lt;/a>.&lt;/p></description></item><item><title>Connecting LUIS &amp; D365 (part 4) - Custom Connector</title><link>https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/</link><pubDate>Wed, 03 Apr 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/04/03/connecting-luis-d365-part-4-custom-connector/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-luisd365-e1554192911124.jpg" alt="Featured image of post Connecting LUIS &amp; D365 (part 4) - Custom Connector" />&lt;p>In my previous &lt;a class="link" href="https://linked365.blog/2019/04/02/connecting-luis-to-d365-part-3/" >post&lt;/a>, the fact that I had to &amp;ldquo;fudge&amp;rdquo; the routing and closure of the case irked me. Whilst at D365 EU Summit in Amsterdam, I spent an hour listening to Serge Luca (his excellent blog is &lt;a class="link" href="https://sergeluca.wordpress.com/" target="_blank" rel="noopener"
>here)&lt;/a>. He inspired me to think that we could close this loop using a Custom Connector in Flow connected to our D365 instance, allowing an API call directly to the closure action.&lt;/p>
&lt;p>Back in the UK, I did some digging, found another excellent blog from Andrew Butenko which steps through doing this for Won Opportunity &lt;a class="link" href="https://butenko.pro/2018/11/30/calling-d365-actions-functions-from-flow/" target="_blank" rel="noopener"
>here&lt;/a>, so just to complete the circle I will step through how I did this.&lt;/p>
&lt;h2 id="create-the-app-in-azure">Create the App in Azure&lt;/h2>
&lt;p>This is a bit heavy for a citizen developer &amp;amp; in the real world you will have to ask your O365 admin to do this, but in my trail I have the appropriate access.&lt;/p>
&lt;p>Go to &lt;a class="link" href="http://portal.azure.com" target="_blank" rel="noopener"
>portal.azure.com&lt;/a> &amp;amp; log in using your CRM Admin credentials.&lt;/p>
&lt;p>In the left pane, select Azure Active Directory, then App Registrations (Preview) then New registration. Give it a name, select Accounts in this organizational directory only &amp;amp; enter localhost as a temporary redirect URL, this will change later. Select Register &amp;amp; allow Azure to do it&amp;rsquo;s stuff&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>On the next screen, select API Permissions, then Add a permission&lt;/p>
&lt;p>The one we are interested in is Dynamics CRM. Select it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Check the box next to user_impersonation. Select Add permissions &amp;amp; now you should have 2 permissions for your new application. Now we need to ensure only we can access it.&lt;/p>
&lt;p>In Certificates &amp;amp; secrets, select New client secret. Give it a Description and decide how long you want to wait before it expires. Not an issue for our demo, our trial wont last as long as this expiry. Once created, make sure you copy the value information, you won&amp;rsquo;t be able to retrieve this at a later stage.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>We also need the application id, this is available on the Overview tab&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-6.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="create-a-custom-connector">Create a Custom Connector&lt;/h2>
&lt;p>Back in flow, under Data &amp;amp; then Custom Connectors there is a Create custom connector drop down, select Create from blank and give it a name.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>On the next screen, you can customise the description &amp;amp; logo if you want, but the important bit is the Host, which is your instance url, and the Base URL which is the api access path.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Security next &amp;amp; choose OAuth 2.0. Identity Provider should be Azure Active Directory, Client Id is the Application Id from previous &amp;amp; Client Secret is also from the previous step. Login URL, Tenant ID &amp;amp; Scope should be left to their default. Resource URL is the url to your environment.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Save the connector by using the Update Connector now. There is an important piece of information, the Redirect URL, which we have to copy &amp;amp; add to our connector back in Azure.&lt;/p>
&lt;p>Select the App Registration in Azure, select Redirect URIs&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>Add a new one from your copied redirect (I think it is standard, as I have only seen one, but just to be sure)&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>The next screen allows you to add Actions &amp;amp; triggers. I think there could be a whole new blog post on using triggers this way. As custom connector is generic across all apis, the flexibility is great. Select New Action.&lt;/p>
&lt;p>The General section describes the connector in Flow, so useful but nothing special is required apart from the Operation Id, which is what api action you want to call &amp;amp; must be unique within each connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Import from sample. This would usually be a sample JSON function. I built mine using Postman, and this is a bit more than a citizen developer would be able to handle without experience. Federico Jousset has a great &lt;a class="link" href="http://www.fedejousset.com/2018/10/03/dynamics-365-web-api-postman-collection/" target="_blank" rel="noopener"
>blog pos&lt;/a>t on using Postman to &amp;ldquo;play&amp;rdquo; with D365 end points, including a link to an extensive Postman collection with lots of examples which were the key to understanding the call, particularly the parameters.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>When you hit import, you will get this section under Request. The bit we are interested in is at the bottom, the body.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-17.png"
loading="lazy"
>&lt;/p>
&lt;p>Click on body, then edit you will see a list of the parameters that Flow inferred from the sample body we gave it.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>Select Incident Id for example, we can now give it a little more information &amp;amp; more importantly give the end user of the low more information with the Title &amp;amp; default value &amp;amp; whether it is required&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>We are now ready to Test. Select the test button, choose New Connection &amp;amp; connect to your D365 system. Enter the appropriate values, but be careful over the incident Id, as it is expecting a odata conversion. Someone better at connectors could tell me why.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>If everything is good, you will get a blank body response back, as this is how the CloseIncident works&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-20.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="using-the-connector-in-flow">Using the connector in Flow&lt;/h2>
&lt;p>In the previous article, I showed you how we had to use a custom field &amp;amp; workflow in D365 to close the incident. I can now replace that with my custom connector call&lt;/p>
&lt;p>Where I was updating a record because they were asking for their next bill, I remove the change to the CloseByFlow field and replace it with a seperate call&lt;/p>
&lt;p>In Flow, I add a new action, select the Custom Tab, my connector &amp;amp; the action I want, this case the CloseIncident. We need to mimic how the api is expceting the Case Id to be passed, which is why we send with the &amp;lsquo;/incidents(&amp;rsquo; prefix &amp;amp; &amp;lsquo;)&amp;rsquo; suffix.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>Test the flow &amp;amp; we have now completed the scenario. Case closure is now part of the flow.&lt;/p>
&lt;p>Custom connectors are new for Flow &amp;amp; give the Flow creator that step extra of functionality where the OOTB solutions don&amp;rsquo;t work.&lt;/p>
&lt;p>There is a word of caution about licensing here, I have been using a trial of E5, which gives you Flow for Office 365 License. I can create a custom connector to a standard application but not a custom application with it. This is the same for Flow for Dynamics 365, so I don&amp;rsquo;t need an extra license, but be warned.&lt;/p></description></item><item><title>Connecting LUIS to D365 (part 3)</title><link>https://linked365.blog/2019/04/02/connecting-luis-to-d365-part-3/</link><pubDate>Tue, 02 Apr 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/04/02/connecting-luis-to-d365-part-3/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-luisd365-e1554192911124.jpg" alt="Featured image of post Connecting LUIS to D365 (part 3)" />&lt;p>In this 3rd installment of the series devoted to using Language Understanding (LUIS) to categorise emails via Flow, I will describe some of the parts of the D365 solution and walk through a final version of the Flow to extend its capabilities.&lt;/p>
&lt;p>This blog has at least 3 parts, but overall the posts objectives are&lt;/p>
&lt;ul>
&lt;li>Give you an understanding of a real-life scenario where we could implement LUIS – (&lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1" >Part 1&lt;/a>)&lt;/li>
&lt;li>Introduce you to the concepts of LUIS (&lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1" >Part 1&lt;/a>)&lt;/li>
&lt;li>Discuss the Microsoft Flow to connect LUIS to D365 (&lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-to-d365-part-2/" >Part 2&lt;/a>)&lt;/li>
&lt;li>Give you some next steps on how you can try to bring LUIS into your organisation&lt;/li>
&lt;/ul>
&lt;h2 id="routing-the-case">Routing the case&lt;/h2>
&lt;p>Standard Save and Route functionality only fires automatically on case creation, or when a user manually hits the button. This action is available in workflow, but not in the CRUD actions of the D365 or CDS connectors. To get around this there is a workflow triggered of the change of the subject field which calls the OOTB action ApplyRoutingRule. This effectively is the same as the user clicking the button.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-16.png"
loading="lazy"
>&lt;/p>
&lt;p>The routing rules are very simple, routing the case based on the subject selected.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-17.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="adding-information-from-the-case">Adding information from the case&lt;/h2>
&lt;p>In our scenario, based around a support desk for a large power company, one of the common requests is to provide meter readings. This data is invaluable.&lt;/p>
&lt;p>In LUIS, this information is called an Entity. You can configure entities for each of the Intents to denote some parcel of information that the user is telling you on top of the intent of their email.&lt;/p>
&lt;p>As you start typing and enter data, LUIS recognises this and replaces the data with a data type that it will use.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-18.png"
loading="lazy"
>&lt;/p>
&lt;p>In Flow, the return from LUIS will contain a list of all the entities it has found in your utterance. The flow then updates the case with this defined data, in a separate field on the case record.&lt;/p>
&lt;p>The first part of the flow checks the length of the array of entities that LUIS returned. If there are no entities, then just do a normal update of the case record. If there are entities, loop through them&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-19.png"
loading="lazy"
>&lt;/p>
&lt;p>As the entities array is looped through, check that the entity is a number. LUIS could return you a date or name. If it is not a number, just do a normal update of the record.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-20.png"
loading="lazy"
>&lt;/p>
&lt;p>If it is a number, pass the meter reading to the case update in the new field on the Case entity.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-21.png"
loading="lazy"
>&lt;/p>
&lt;p>This approach does lead to duplicate updates, 1 for each entity it finds. You may be better suited to extend the logic in a production system to prevent this.&lt;/p>
&lt;h2 id="auto-reply-for-common-intents">Auto-reply for common intents&lt;/h2>
&lt;p>In our scenario, one of the common requests that the help desk gets is to ask when the end user is due a bill. This again could be dealt with in numerous ways via workflow in D365, but doing it in Flow allows the demonstration of Flow&amp;rsquo;s abilities.&lt;/p>
&lt;p>The first part is to check the Top scoring intent is &amp;ldquo;Next Bill due&amp;rdquo;. The flow goes on to check for meter readings if it isn&amp;rsquo;t.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-22.png"
loading="lazy"
>&lt;/p>
&lt;p>Using D365 connector this time (Microsoft changes so quickly, it is hard to keep up with what the best methods are) I retrieve the contact that created the case then send them a nicely formatted email. This will send the email as the account you attach to run the flow, in our scenario the support desk. I have only hardcoded the content here, but you could easily read the date of the next bill from the users account record or something similar.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-23.png"
loading="lazy"
>&lt;/p>
&lt;p>The next step is close the case as we have provided the end user with the appropriate information. In D365, this is another action not readily available via the CRUD of the CDS or D365 connector.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-24.png"
loading="lazy"
>&lt;/p>
&lt;p>I now realise, after attending the EU D365 User Group Summit that this would be possible via Flow, along with routing the case, if you create your own custom connector and associate that with your D365 API instance, but that&amp;rsquo;s for another post.&lt;/p>
&lt;p>To get round the limitations, a new field is populated on the Case record, Close from Flow.&lt;/p>
&lt;p>A workflow is then triggered when this field changes to call the OOTB action if the value is true.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-25.png"
loading="lazy"
>&lt;/p>
&lt;h2 id="sentiment-analysis">Sentiment analysis&lt;/h2>
&lt;p>One of the big uses for social engagement and monitoring is to assess sentiment in the comments made by customers. LUIS provides this information in a textual (positive, neutral or negative) as well as numeric form if enable it on the application.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/04-image-26.png"
loading="lazy"
>&lt;/p>
&lt;p>Once you have this configured, recording this against the case and maybe setting a priority on it&amp;rsquo;s value would be quite straight forward.&lt;/p></description></item><item><title>Connecting LUIS &amp; D365 (part 1)</title><link>https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/</link><pubDate>Sun, 31 Mar 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/</guid><description>&lt;img src="https://linked365.blog/images/2019/03-luisd365-e1554192911124.jpg" alt="Featured image of post Connecting LUIS &amp; D365 (part 1)" />&lt;p>As Microsoft wants us to consider using AI in all aspects of our developments, I wanted to see if I could use one of the cognitive services available to life in a real life scenaro.&lt;/p>
&lt;p>This post &amp;amp; it&amp;rsquo;s other parts will&lt;/p>
&lt;ul>
&lt;li>Give you an understanding of a real-life scenario where we could implement LUIS&lt;/li>
&lt;li>Introduce you to the concepts of LUIS&lt;/li>
&lt;li>Discuss the Microsoft Flow to connect LUIS to D365&lt;/li>
&lt;li>Give you some next steps on how you can try to bring LUIS into your organisation&lt;/li>
&lt;/ul>
&lt;h2 id="the-scenario---big-energy-co">The Scenario - Big Energy Co&lt;/h2>
&lt;p>Imagine a busy helpdesk or contact centre at one of the big electricity or gas companies. They are inundated with calls, emails &amp;amp; chats from their customer base to request numerous changes or additions to their account, provide meter readings, complain or numerous other concerns.&lt;/p>
&lt;p>Email is one of the biggest mediums for support when the matter is not urgent. The standard email to case conversion is commonaly used to bring these support requests into D365 CE.&lt;/p>
&lt;p>But that is traditionally where it stops. A 1st line support user would have to read the content of the case, decide on the appropriate subject for the new case &amp;amp; select save and route. This takes time, upto a couple of minutes, of invaluable time of an educated, talented member of your team.&lt;/p>
&lt;h2 id="luis---language-understanding">LUIS - Language Understanding&lt;/h2>
&lt;p>&lt;a class="link" href="http://www.luis.ai" target="_blank" rel="noopener"
>LUIS&lt;/a> is Microsoft&amp;rsquo;s cloud-based API which tries to understand the meaning behind phrases. LUIS could take a paragraph of text and categorise it to suggest what the writer of the paragraph is trying to say. Bringing machine learning into your app can drastically reduce the time spent scouring tet for meaning .&lt;/p>
&lt;p>In a 1st line support scenario, an email comes into a support mailbox and D365 will create a case with it&amp;rsquo;s auto-creation rules to allow a 1st line support person to read the email, decide what the email is concerning, then route the case to the relevant team.&lt;/p>
&lt;p>Using Flow and LUIS, we can automate this step, reducing the time taken to get the case to the right people, improving SLAs and reducing costs.&lt;/p>
&lt;h2 id="luis-configuration">LUIS Configuration&lt;/h2>
&lt;p>For all of this, I am using a trial environment, Microsoft makes it easy for you to play with all it&amp;rsquo;s tools, and LUIS is no exception. The free licenses gives you 5 text requests per seconds, definetly adequate for development and trial purposes. It is then £1.11 per 1000 transactions above this, with a max of 50 transactions a second.&lt;/p>
&lt;p>By going to &lt;a class="link" href="http://luis.ai" target="_blank" rel="noopener"
>luis.ai&lt;/a> &amp;amp; logging in, you will be allowed to create an app. This is the starting point. As you can see my app has been created already.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="intents">Intents&lt;/h3>
&lt;p>Intents are the term for meaning within the app. Each app will have several intents, what are the likely short description or categories of why an email would come into the environment?&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-2.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="utterances">Utterances&lt;/h3>
&lt;p>Each intent has several utterances, which are phrases from which LUIS will learn and define the intent of the text passed to it. It is very simple to add utterances and you should aim to get 15 or so for each intent as a starting point.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-3.png"
loading="lazy"
>&lt;/p>
&lt;p>You can add as many utterances as you like, try to keep your utterance count consist between intents as a higher utterance list on one of the intents will lead to it be chosen more, in effective giving you false results. When you get into a near production scenario, you need to keep adding them from feedback from your users. You could enact a process which, when LUIS fails to assocaite an intent to a case or gives a false classification, this is highlighted for a BA to analyse &amp;amp; apply to the model.&lt;/p>
&lt;p>The next thing to do is train LUIS. This brings any changes you have made into the AI so they also can be used to understand the conversation.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>Training is complete when you get a green bar across the top.&lt;/p>
&lt;p>Now we have a model, let&amp;rsquo;s test it, using the inbuilt Test functionality available from the top right.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>If you type a string in the box provided &amp;amp; hit return, you are calling LUIS and the text will be analysed and LUIS will reply with the highest intent &amp;amp; how likely the phrase enters matches it.&lt;/p>
&lt;p>I have entered the phrase &amp;ldquo;can you help me transfer my account&amp;rdquo;, which wasn&amp;rsquo;t part of the utterances I created earlier, but closely matches one of the Account closure utterances.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-6.png"
loading="lazy"
>&lt;/p>
&lt;p>Looking at the response, LUIS is stating that he thinks this phrase is about Account Closure and he is 58% sure that this is correct. If you click on the Inspect link you can use this to train LUIS if the response is not correct by using the Edit link, adding an utterance to one of the other intents or reenforcing the entered text was in the correct intent.&lt;/p>
&lt;h2 id="publishing-luis">Publishing LUIS&lt;/h2>
&lt;p>My LUIS app is ready, it is trained and raring to go. Now we need to allow access from the publicly available API. The Publish button steps you through the process, ensure you go to Production. Don&amp;rsquo;t worry about costs for now, you get 5 requests a second for free, which is great for trialling &amp;amp; developing&lt;/p>
&lt;p>In Application Information, there 2 key bits for connecting LUIS to Flow. Firstly, the Application ID is the key we want later. Secondly, we need to ensure anyone with the Application ID can access our endpoint &amp;amp; use the app we have configured, so ensure the Make this app public is checked.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>This is a little less secure than you would want in production and there are details about LUIS security available to ensure only the proper users can access fully documented &lt;a class="link" href="https://docs.microsoft.com/en-us/azure/cognitive-services/luis/luis-concept-security" target="_blank" rel="noopener"
>here&lt;/a>.&lt;/p>
&lt;p>That&amp;rsquo;s it, ready to go. In the next part, I will configure D365 and Flow to complete the scenario&lt;/p></description></item><item><title>Connecting LUIS to D365 (Part 2)</title><link>https://linked365.blog/2019/03/31/connecting-luis-to-d365-part-2/</link><pubDate>Sun, 31 Mar 2019 00:00:00 +0000</pubDate><guid>https://linked365.blog/2019/03/31/connecting-luis-to-d365-part-2/</guid><description>&lt;img src="https://linked365.blog/images/2019/04-luisd365-e1554192911124.jpg" alt="Featured image of post Connecting LUIS to D365 (Part 2)" />&lt;p>In the first &lt;a class="link" href="https://linked365.blog/2019/03/25/connecting-luis-d365/" target="_blank" rel="noopener"
>part&lt;/a> of this blog post I explained our scenario for Big Energy Co and it&amp;rsquo;s desire to improve efficiency in the support desk, introduced LUIS and the core concepts around utterances and intents, configured LUIS to allow it to understand the intents we need and published the application.&lt;/p>
&lt;p>Now I need to connect LUIS and D365 to allow automatic classification and routing of cases based on Natural Language inspection of the body of the case.&lt;/p>
&lt;p>This blog has at least 3 parts, but overall the posts objectives are&lt;/p>
&lt;ul>
&lt;li>Give you an understanding of a real-life scenario where we could implement LUIS (&lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365/" target="_blank" rel="noopener"
>Part 1&lt;/a>)&lt;/li>
&lt;li>Introduce you to the concepts of LUIS (&lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365/" target="_blank" rel="noopener"
>Part 1&lt;/a>)&lt;/li>
&lt;li>Discuss the Microsoft Flow to connect LUIS to D365&lt;/li>
&lt;li>Give you some next steps on how you can try to bring LUIS into your organisation&lt;/li>
&lt;/ul>
&lt;p>Nowadays, Microsoft &lt;a class="link" href="https://flow.microsoft.com/" target="_blank" rel="noopener"
>Flow&lt;/a> doesn&amp;rsquo;t need an introduction - it is the cornerstone for the whole of Microsoft Power suite (not sure why it doesn&amp;rsquo;t get the Power prefix) and allow &lt;em>spot&lt;/em> integrations between one or more disparate applications. It also allows you to &amp;ldquo;program&amp;rdquo; some data transformation or logic to control how data flows between applications or actions to take in specific circumstances. Flow is a complex beast, but simple to use in a lot of cases.&lt;/p>
&lt;h2 id="the-flow">The Flow&lt;/h2>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image.png"
loading="lazy"
>&lt;/p>
&lt;p>As you can see, the flow is pretty simple. We get a trigger from D365, strip the body of the case down to raw text, check to see if have anything left, ask LUIS to predict what it is, check how confident LUIS is, then update the case again. This is a simple flow which isn&amp;rsquo;t production ready by any means, but shows you the power of Flow and is enough for you to get started&lt;/p>
&lt;h3 id="triggering-from-d365">Triggering from D365&lt;/h3>
&lt;p>Our first step the trigger from D365&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-1.png"
loading="lazy"
>&lt;/p>
&lt;p>I am using the Common Data Service connectors here, which are the future, so why not? We have to connect to our D365 environment, chose the Cases entity and give it a scope. This is new for the CDS connector and allows a lot more flexibility around what data runs through a flow. You could keep the data to one business unit in an organisation, useful if you have country specific flows for example.&lt;/p>
&lt;h3 id="stripping-that-nasty-html">Stripping that nasty HTML&lt;/h3>
&lt;p>Email contains lots of formatting information that LUIS doesn&amp;rsquo;t understand. CSS, html tags, that heading etc will really upset LUIS, but handly there is an action to return just the actual words. Pass the body of the email, the case description to it.&lt;/p>
&lt;p>Also in this snippet, I am setting up a variable for use later on, to store the Subject ID.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-2.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="checking-for-empty-email">Checking for empty email&lt;/h3>
&lt;p>Another thing that LUIS doesnt handle is sending it an empty request. Just for a bit of house keeping, if, after stripping out all the html tags, the content is empty, rather than calling LUIS, exit gracefully. Always have in mind when running any flow that someone will be bombarded with error alerts if you don&amp;rsquo;t check&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-3.png"
loading="lazy"
>&lt;/p>
&lt;h3 id="passing-to-luis">Passing to LUIS&lt;/h3>
&lt;p>In the previous &lt;a class="link" href="https://linked365.blog/2019/03/31/connecting-luis-d365-part-1/#publishing-luis" >post&lt;/a>, when your LUIS app is published, you get a GUID representing the Application key. When you first connect to LUIS in Flow, this is what you need. If you have many applications in LUIS on that key, Flow wants to know which one, and also which version. This is handy if you are training LUIS and the new version isn&amp;rsquo;t quite ready, stick with a previous version of your app.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-4.png"
loading="lazy"
>&lt;/p>
&lt;p>The Utterance text is the email body, stripped of the html, which LUIS is to analyse.&lt;/p>
&lt;h3 id="is-luis-confident">Is LUIS confident?&lt;/h3>
&lt;p>Like any AI product, LUIS can only predict what it thinks is the likely intent of anything you pass to it. It provides you with a score, 0 being not confident, 1 being overly confident that matches each intent. We basically use this as a percentage. When this returns to flow, LUIS provides the top scoring intent as well as the top scoring intent score. If LUIS isn&amp;rsquo;t confident that what you have sent it, then Flow shouldn&amp;rsquo;t update the case. This case should stay with the 1st line queue for them to resolve.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-5.png"
loading="lazy"
>&lt;/p>
&lt;p>Again, this is about making your code production ready. It would be quite easy to trigger additional steps here to ensure this case is looked at and maybe a training point for LUIS after a human decides on the best route for the case.&lt;/p>
&lt;h3 id="retrieve-the-subject">Retrieve the subject&lt;/h3>
&lt;p>The subject tree in D365 matches the intents. This is a key point for our process to work. You could use other factors or matching, but this is pretty simple.&lt;/p>
&lt;p>Using the CDS link, we use the List Records feature to query the Subject entity. The filter query is the key here, using a piece of OData query notation to find the subject with a title that matches our top scoring intent.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-7.png"
loading="lazy"
>&lt;/p>
&lt;p>Though we will only retrieve one record, the List Records action will always return an array or records, an array of one. To keep your flow in one column, you can set a variable with the value of the subject Id you have retrieved and use this going forward. If not, you will have to do the remainder of these steps within the Apply to each action.&lt;/p>
&lt;h3 id="updating-the-case">Updating the Case&lt;/h3>
&lt;p>The last part of this simple flow is to update the case back in D365. Using the Id from the originally triggered case, we update parts of the case.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-8.png"
loading="lazy"
>&lt;/p>
&lt;p>The description is updated with the html stripped text. There are lots of ways to do this in D365, but seeing as we have done it already, it is neat to use it again. I have also added a new field on the case to log how confident LUIS is. This could be used as a summary later or for managing the training of LUIS.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-9.png"
loading="lazy"
>&lt;/p>
&lt;p>Finally, the subject Id is passed to the Subject field.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-10.png"
loading="lazy"
>&lt;/p>
&lt;p>So that is our flow complete. Now for some testing.&lt;/p>
&lt;h2 id="testing-our-flow">Testing our Flow&lt;/h2>
&lt;p>Flow has some really neat tools to ease testing. In the right corner, is the Test button which gives us this panel. The first time you run a flow, you will have to perform the trigger action, sending in an email to convert to a case or creating a case in our scenario, but after that, we can use previous data. Great for tweaking &amp;amp; checking&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-11.png"
loading="lazy"
>&lt;/p>
&lt;p>If you run a test, you will hopefully get a screen with lots of green ticks next to the parts that ran successfully as well as some crosses against those that didn&amp;rsquo;t.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-12.png"
loading="lazy"
>&lt;/p>
&lt;p>If you drill down to each step, you can see the input and the output from that action.&lt;/p>
&lt;p>In this example, you can see the original html formatted input from an email as well as the output of just the text.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-13.png"
loading="lazy"
>&lt;/p>
&lt;p>The call to LUIS shows the JSON return from LUIS. The LUIS connector gives a lot of properties transformed out of this content.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-14.png"
loading="lazy"
>&lt;/p>
&lt;p>The CDS record update shows only the fields that we update, a standard D365 API call. You can see the Subject ID being set, as well as the html stripped description and the Intent score.&lt;/p>
&lt;p>&lt;img src="https://linked365.blog/images/2019/03-image-15.png"
loading="lazy"
>&lt;/p>
&lt;p>So, flow done. In the next installment, I will show the D365 implementation, how we bring it all together. I also take LUIS and flow a little bit further, to add more complexity and functionality to the both to improve the scenario.&lt;/p></description></item><item><title>About</title><link>https://linked365.blog/about/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://linked365.blog/about/</guid><description>&lt;style>
* {
box-sizing: border-box;
}
/* Create two equal columns that floats next to each other */
.column {
float: left;
width: 50%;
padding: 10px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
&lt;/style>
&lt;div class="row">
&lt;div class="column">I am a seasoned professional developer who has experience of Dynamics 365 as well as other CRMs over 20 years.
&lt;p>The realisation that it is mostly about configuration now is hard for my development mind to take, so I want to utilise my experience to ensure others know about the various ways we can expand the Dynamics 365 borders to other applications. Highlighting business cases and neat tricks along the way (hopefully)&lt;/p>
&lt;p>I was awarded as a Microsoft MVP in December 2020, which has filled me with pride and pushes me to continue to develop my tools and provide insights to continue my educational journey in the Power Platform&lt;/p>
&lt;p>I am an independent consulting working across various enterprise projects. I am always open to convrssations around how I can support you.&lt;/p>
&lt;/div>
&lt;div class="column">
&lt;img id="myImg" src="https://linked365.blog/images/MVP_Logo_Preferred_Cyan300_RGB_300ppi.webp" alt="MVP Logo" style="width:100%">
&lt;/div>
&lt;/div></description></item><item><title>Contact Me</title><link>https://linked365.blog/contact-me/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://linked365.blog/contact-me/</guid><description>&lt;p>Please reach out on &lt;a class="link" href="https://twitter.com/linked365" target="_blank" rel="noopener"
>Twitter&lt;/a> or &lt;a class="link" href="https://www.linkedin.com/in/carlcookson/" target="_blank" rel="noopener"
>LinkedIn&lt;/a> or send me a message below.&lt;/p>
&lt;form id="fs-frm" name="simple-contact-form" accept-charset="utf-8" action="https://formspree.io/f/mbjeojgv" method="post">
&lt;fieldset id="fs-frm-inputs">
&lt;label for="full-name">Full Name&lt;/label>
&lt;input type="text" name="name" id="full-name" placeholder="What do I call you" required="">
&lt;label for="email-address">Email Address&lt;/label>
&lt;input type="email" name="_replyto" id="email-address" placeholder="Your Email" required="">
&lt;label for="message">Message&lt;/label>
&lt;textarea rows="5" name="message" id="message" placeholder="What do you want to chat about?" required="">&lt;/textarea>
&lt;input type="hidden" name="_subject" id="email-subject" value="Contact Form Submission">
&lt;input type="submit" value="Email Me">
&lt;/fieldset>
&lt;/form>
&lt;style>/* reset */
#fs-frm fieldset,
#fs-frm optgroup,
#fs-frm label,
#fs-frm #card-element:disabled {
font-family: var(--base-font-family);
color: inherit;
border: none;
border-radius: 0;
display: block;
width: 100%;
padding: 0;
margin: 0;
-webkit-appearance: none;
-moz-appearance: none;
}
#fs-frm input,
#fs-frm textarea{
font-family: var(--base-font-family);
color: black;
border: none;
border-radius: 0;
display: block;
width: 100%;
padding: 0;
margin: 0;
-webkit-appearance: none;
-moz-appearance: none;
}
#fs-frm [type="submit"]
{
font-family: var(--base-font-family);
color: var(--accent-color-text);
border-radius: 0;
-webkit-appearance: none;
-moz-appearance: none;
background-color: var(--accent-color);
width: 100px;
position: relative;
display: grid;
margin-top: 6px;
}
#fs-frm label,
#fs-frm legend,
#fs-frm ::placeholder {
margin-bottom: .5rem;
padding-top: .2rem;
display: flex;
align-items: baseline;
}
&lt;p>/* border, padding, margin, width */
#fs-frm input,
#fs-frm select,
#fs-frm textarea,
#fs-frm #card-element {
border: 1px solid rgba(0,0,0,0.2);
background-color: rgba(255,255,255,0.9);
padding: .75em 1rem;
margin-bottom: 1.5rem;
}
#fs-frm input:focus,
#fs-frm select:focus,
#fs-frm textarea:focus {
background-color: white;
outline-style: solid;
outline-width: thin;
outline-color: gray;
outline-offset: -1px;
}
#fs-frm [type=&amp;ldquo;text&amp;rdquo;],
#fs-frm [type=&amp;ldquo;email&amp;rdquo;] {
width: 100%;
}
#fs-frm [type=&amp;ldquo;button&amp;rdquo;],
#fs-frm [type=&amp;ldquo;submit&amp;rdquo;],
#fs-frm [type=&amp;ldquo;reset&amp;rdquo;] {
width: 100;
cursor: pointer;
-webkit-appearance: button;
-moz-appearance: button;
appearance: button;
}
#fs-frm [type=&amp;ldquo;button&amp;rdquo;]:focus,
#fs-frm [type=&amp;ldquo;submit&amp;rdquo;]:focus,
#fs-frm [type=&amp;ldquo;reset&amp;rdquo;]:focus {
outline: none;
}
#fs-frm [type=&amp;ldquo;submit&amp;rdquo;],
#fs-frm [type=&amp;ldquo;reset&amp;rdquo;] {
margin-bottom: 0;
}
#fs-frm select {
text-transform: none;
}&lt;/p>
&lt;p>#fs-frm [type=&amp;ldquo;checkbox&amp;rdquo;] {
-webkit-appearance: checkbox;
-moz-appearance: checkbox;
appearance: checkbox;
display: inline-block;
width: auto;
margin: 0 .5em 0 0 !important;
}&lt;/p>
&lt;p>#fs-frm [type=&amp;ldquo;radio&amp;rdquo;] {
-webkit-appearance: radio;
-moz-appearance: radio;
appearance: radio;
}&lt;/p>
&lt;p>/* address, locale */
#fs-frm fieldset.locale input[name=&amp;ldquo;city&amp;rdquo;],
#fs-frm fieldset.locale select[name=&amp;ldquo;state&amp;rdquo;],
#fs-frm fieldset.locale input[name=&amp;ldquo;postal-code&amp;rdquo;] {
display: inline;
}
#fs-frm fieldset.locale input[name=&amp;ldquo;city&amp;rdquo;] {
width: 52%;
}
#fs-frm fieldset.locale select[name=&amp;ldquo;state&amp;rdquo;],
#fs-frm fieldset.locale input[name=&amp;ldquo;postal-code&amp;rdquo;] {
width: 20%;
}
#fs-frm fieldset.locale input[name=&amp;ldquo;city&amp;rdquo;],
#fs-frm fieldset.locale select[name=&amp;ldquo;state&amp;rdquo;] {
margin-right: 3%;
}
&lt;/style>&lt;/p></description></item><item><title>Search</title><link>https://linked365.blog/search/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://linked365.blog/search/</guid><description/></item><item><title>Tools</title><link>https://linked365.blog/tools/</link><pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate><guid>https://linked365.blog/tools/</guid><description>&lt;p>To use this feature, add &lt;code>links&lt;/code> section to frontmatter.&lt;/p>
&lt;p>This page&amp;rsquo;s frontmatter:&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-yaml" data-lang="yaml">&lt;span class="line">&lt;span class="cl">&lt;span class="nt">links&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">GitHub&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">GitHub is the world&amp;#39;s largest software development platform.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">website&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://github.com&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>- &lt;span class="nt">title&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">TypeScript&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">description&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">TypeScript is a typed superset of JavaScript that compiles to plain JavaScript.&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">website&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">https://www.typescriptlang.org&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="w"> &lt;/span>&lt;span class="nt">image&lt;/span>&lt;span class="p">:&lt;/span>&lt;span class="w"> &lt;/span>&lt;span class="l">ts-logo-128.jpg&lt;/span>&lt;span class="w">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>image&lt;/code> field accepts both local and external images.&lt;/p></description></item></channel></rss>