<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Graph on Nicola Suter</title><link>https://nicolasuter.ch/tags/graph/</link><description>Recent content in Graph on Nicola Suter</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><copyright>© 2026 Nicola Suter</copyright><lastBuildDate>Fri, 19 Mar 2021 00:00:00 +0000</lastBuildDate><atom:link href="https://nicolasuter.ch/tags/graph/rss.xml" rel="self" type="application/rss+xml"/><item><title>Securely sending emails from PowerShell scripts with modern authentication enforced</title><link>https://nicolasuter.ch/sending-emails-with-modern-auth/</link><pubDate>Fri, 19 Mar 2021 00:00:00 +0000</pubDate><guid>https://nicolasuter.ch/sending-emails-with-modern-auth/</guid><description>&lt;p&gt;The &lt;code&gt;Send-MailMessage&lt;/code&gt; cmdlet has been around for a couple of years and is mostly used to send email messages from PowerShell. But with the deprecation and security flaws of legacy authentication it&amp;rsquo;s time for a better option which actually supports modern authentication. For this purpose we can use the Microsoft Graph API and the Microsoft Graph PowerShell SDK. The best thing is that this solution works without any service account and does not need any exclusions from conditional access.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Microsoft Graph resource
 &lt;div id="microsoft-graph-resource" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#microsoft-graph-resource" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;To send a mail we simply specify the user account from which we want to send the email:&lt;/p&gt;
&lt;div class="highlight-wrapper"&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;POST: https://graph.microsoft.com/v1.0/users/sean.connery@dev.nicolonsky.ch/sendMail&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 class="relative group"&gt;Create an app registration
 &lt;div id="create-an-app-registration" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#create-an-app-registration" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Simply create a new app registration with the &lt;code&gt;Mail.Send&lt;/code&gt; permissions and use a certificate for the authentication.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="New App registration"
 src="https://nicolasuter.ch/content/images/2021/03/App-Permissions.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;We need to take additional steps to limit the permissions of the app registration. Otherwise the app can send mails on behalf of &lt;strong&gt;any user&lt;/strong&gt; in your tenant. To limit the permissions we leverage &lt;a href="https://docs.microsoft.com/en-us/powershell/module/exchange/new-applicationaccesspolicy?view=exchange-ps" target="_blank" rel="noreferrer"&gt;exchange application access policies&lt;/a&gt;.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Connect to Exchange Online with the ExchangeOnlineManagement PowerShell module
&lt;code&gt;Connect-ExchangeOnline&lt;/code&gt;&lt;/p&gt;</description></item><item><title>Dealing with Intune OMA-URI encoding and applocker rules</title><link>https://nicolasuter.ch/intune-oma-uri-encoding/</link><pubDate>Tue, 16 Feb 2021 00:00:00 +0000</pubDate><guid>https://nicolasuter.ch/intune-oma-uri-encoding/</guid><description>&lt;p&gt;While fine-tuning and adjusting applocker policies for co-managed Windows 10 clients I got really annoyed by special characters commonly used in the German/Swiss language. The Intune portal seemed to use different encoding and didn&amp;rsquo;t allow me to just copy/paste the currently deployed policy and extend it with a new rule. I needed to request the original file that was uploaded to the tenant in order to adjust the rule. Instead of just accepting this I decided that it is time for an easier approach which I will share with you.&lt;/p&gt;

&lt;h2 class="relative group"&gt;The actual issue
 &lt;div id="the-actual-issue" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#the-actual-issue" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;After uploading the XML with the applocker policies (in my case EXE rules), special characters like &amp;lsquo;ö&amp;rsquo; or &amp;lsquo;ü&amp;rsquo; have a weird encoding displayed in the portal. The next person that wants to edit the policy needs to take care to fix the unrecognized characters otherwise the publisher rule won&amp;rsquo;t work anymore.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nicolasuter.ch/content/images/2021/02/Applocker-OMA-URI.png" &gt;&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="OMA-URI"
 src="https://nicolasuter.ch/content/images/2021/02/Applocker-OMA-URI.png"
 &gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Top: Portal view of the special characters, bottom: original file.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nicolasuter.ch/content/images/2021/02/Encoding-Issue.png" &gt;&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Encoding issue"
 src="https://nicolasuter.ch/content/images/2021/02/Encoding-Issue.png"
 &gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;Fixing things
 &lt;div id="fixing-things" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#fixing-things" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;

&lt;h3 class="relative group"&gt;Save file with UTF-8 encoding
 &lt;div id="save-file-with-utf-8-encoding" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#save-file-with-utf-8-encoding" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;First, make sure that you saved an uploaded the file with UTF-8 encoding as this introduces support for most character sets. You can do this by selecting the encoding box in the right bottom of Visual Studio Code:&lt;/p&gt;</description></item><item><title>Microsoft Graph Access Token Acquisition with PowerShell explained in depth</title><link>https://nicolasuter.ch/explaining-microsoft-graph-access-token-acquisition/</link><pubDate>Mon, 04 Jan 2021 00:00:00 +0000</pubDate><guid>https://nicolasuter.ch/explaining-microsoft-graph-access-token-acquisition/</guid><description>&lt;p&gt;When working with the Microsoft Graph API or introducing the API to colleagues I often get asked about the steps required to obtain an access token for the API with PowerShell. Out in the wild, I&amp;rsquo;ve spotted many different ways and lots of implementations still relying on the ADAL (Active Directory Authentication Library) despite the fact that this client library is superseded by MSAL (Microsoft Authentication Library). So let&amp;rsquo;s talk about acquiring access token &amp;ldquo;in stile&amp;rdquo; with the most simple method available.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Why do we need an access token?
 &lt;div id="why-do-we-need-an-access-token" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#why-do-we-need-an-access-token" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;When talking about the Microsoft Graph API an access token fulfills two roles, first: prove authentication (proof of identity) second prove authorization (permissions). Each request needs to submit a request-header that contains the access token.&lt;/p&gt;
&lt;p&gt;For an API it&amp;rsquo;s crucial to validate the authentication and authorization for every request. Otherwise, requests could be made to resources the actor has no access to.&lt;/p&gt;

&lt;h2 class="relative group"&gt;What&amp;rsquo;s inside the access token
 &lt;div id="whats-inside-the-access-token" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#whats-inside-the-access-token" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;You did probably stumble over the terms &amp;ldquo;bearer authentication&amp;rdquo; or &amp;ldquo;bearer token&amp;rdquo; these describe a mechanism within the OAuth 2.0 Authorization framework to authenticate requests with access tokens. Tokens are issued by the authorization server (Azure AD) and contain a server-generated string in the format of a JSON Web Token (JWT) with the following information (the list is not exhaustive and truncated to only contain the most interesting parts):&lt;/p&gt;</description></item><item><title>Discover the Microsoft Graph API with the Microsoft Endpoint Manager Portal</title><link>https://nicolasuter.ch/discover-mem-graph-urls/</link><pubDate>Tue, 08 Sep 2020 00:00:00 +0000</pubDate><guid>https://nicolasuter.ch/discover-mem-graph-urls/</guid><description>&lt;p&gt;You always wanted to automate a specific action within Intune / the Microsoft Endpoint Manager Portal (MEM) but were afraid of the complexity? The Microsoft Graph API docs deliver you more questions instead of answers? Automating tasks within the MEM portal could be very easy, couldn&amp;rsquo;t it? I promise it will be much simpler with this magician trick.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Microsoft Endpoint Manager Portal
 &lt;div id="microsoft-endpoint-manager-portal" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#microsoft-endpoint-manager-portal" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The MEM Portal UI relies on the Microsoft Graph API. This means that the UI where you create new settings and policies and the Intune backend are encapsulated with different layers. Communication between the UI and the backend happens with the Microsoft Graph API. With the developer tools we can trace network traffic and discover the request URLs and request body payload which are required to interact with the API.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Architecture"
 src="https://nicolasuter.ch/content/images/2020/09/MEM-Portal-Automation.svg"
 &gt;&lt;/figure&gt;
{: .align-center}&lt;/p&gt;

&lt;h2 class="relative group"&gt;Example about how to capture URLs and build a PowerShell script
 &lt;div id="example-about-how-to-capture-urls-and-build-a-powershell-script" class="anchor"&gt;&lt;/div&gt;
 
 &lt;span
 class="absolute top-0 w-6 transition-opacity opacity-0 -start-6 not-prose group-hover:opacity-100 select-none"&gt;
 &lt;a class="text-primary-300 dark:text-neutral-700 !no-underline" href="#example-about-how-to-capture-urls-and-build-a-powershell-script" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;"&gt;
 &lt;iframe allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen" loading="eager" referrerpolicy="strict-origin-when-cross-origin" src="https://www.youtube.com/embed/k6ZCSJVXaOI?autoplay=0&amp;amp;controls=1&amp;amp;end=0&amp;amp;loop=0&amp;amp;mute=0&amp;amp;start=0" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;" title="YouTube video"&gt;&lt;/iframe&gt;
 &lt;/div&gt;

&lt;p&gt;Original request body:&lt;/p&gt;</description></item></channel></rss>