<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Azure AD on Nicola Suter</title><link>https://tech.nicolonsky.ch/tags/azure-ad/</link><description>Recent content in Azure AD on Nicola Suter</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><copyright>© 2026 Nicola Suter</copyright><lastBuildDate>Mon, 23 Jan 2023 17:03:47 +0000</lastBuildDate><atom:link href="https://tech.nicolonsky.ch/tags/azure-ad/rss.xml" rel="self" type="application/rss+xml"/><item><title>GitHub Actions with Entra Workload Identity Federation</title><link>https://tech.nicolonsky.ch/github-actions-entra-workload-identity-federation/</link><pubDate>Mon, 23 Jan 2023 17:03:47 +0000</pubDate><guid>https://tech.nicolonsky.ch/github-actions-entra-workload-identity-federation/</guid><description>&lt;p&gt;Workload Identity Federation (let’s just call this WIF) allows app principals not residing within Azure to request short lived access tokens. This removes the need of storing client secrets or certificates within GitHub as Action secrets. One drawback ist that currently only the Azure modules support the usage of WIF.&lt;/p&gt;

&lt;h2 class="relative group"&gt;How it works
 &lt;div id="how-itworks" 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="#how-itworks" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;WIF relies on trust. This trust is directly configured on the Azure AD app registration and scoped to an individual GitHub repository and optionally fine grained by limiting the usage to single git refs, specifically branches and tags. By trusting GitHub as external identity provider (IdP), a GitHub Action can request an identity token from the GitHub IdP and exchange this one against an access token within Azure AD.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Entra Workload Identity Federation"
 src="https://cdn-images-1.medium.com/max/800/1*r7XrBMrGtQ1M-Kd0biGjVA.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;A GitHub IdP issued token (decoded) contains the following information:&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-json" data-lang="json"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;jti&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;1a9fe224-c936-46f6-a38b-3300e76251b0&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sub&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;repo:nicolonsky/musical-octo-telegram:ref:refs/heads/main&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;aud&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;api://AzureADTokenExchange&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;refs/heads/main&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;sha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;9f112c0b82547e35b10250d7f3165789bf97862f&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repository&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nicolonsky/musical-octo-telegram&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repository_owner&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nicolonsky&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repository_owner_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;32899754&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;run_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;3986560796&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;run_number&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;run_attempt&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repository_visibility&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;private&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;repository_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;592303002&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;actor_id&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;32899754&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;actor&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nicolonsky&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;workflow&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;.github/workflows/wif.yaml&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;head_ref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;base_ref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;event_name&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;push&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;ref_type&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;branch&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;workflow_ref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nicolonsky/musical-octo-telegram/.github/workflows/wif.yaml@refs/heads/main&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;workflow_sha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;9f112c0b82547e35b10250d7f3165789bf97862f&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;job_workflow_ref&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;nicolonsky/musical-octo-telegram/.github/workflows/wif.yaml@refs/heads/main&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;job_workflow_sha&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;9f112c0b82547e35b10250d7f3165789bf97862f&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;iss&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://token.actions.githubusercontent.com&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;nbf&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1674486850&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;exp&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1674487750&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nt"&gt;&amp;#34;iat&amp;#34;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1674487450&lt;/span&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Did you recognize the matching &lt;code&gt;sub&lt;/code&gt; attribute within the GitHub issued token and the Azure AD configuration? For a successful authentication the:&lt;/p&gt;</description></item><item><title>Inside Windows package manager (winget)</title><link>https://tech.nicolonsky.ch/inside-windows-package-manager/</link><pubDate>Fri, 30 Dec 2022 23:11:03 +0000</pubDate><guid>https://tech.nicolonsky.ch/inside-windows-package-manager/</guid><description>&lt;p&gt;Windows Package Manager (winget) provides exciting features to install and upgrade apps on Windows devices. But how does winget actually work and how are new packages integrated? Within this post I want to elaborate on some questions I had when having a closer look into winget.&lt;/p&gt;

&lt;h4 class="relative group"&gt;How does winget find sources?
 &lt;div id="how-does-winget-findsources" 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="#how-does-winget-findsources" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;By default, winget has the following sources configured:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;msstore: Microsoft Store (public)&lt;/li&gt;
&lt;li&gt;winget: Winget Content Delivery Network (CDN)&lt;/li&gt;
&lt;/ol&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt=""
 src="https://cdn-images-1.medium.com/max/800/1*A7BC1sZg0P8h43LvLkvIpw.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;When searching for a particular package, e.g: &lt;code&gt;winget search wireshark&lt;/code&gt; all configured sources are searched for a match.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt=""
 src="https://cdn-images-1.medium.com/max/800/1*Kck4GHmNrkEWRLfkASY39g.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;lesson learned: winget can install packages from the public Microsoft store and the winget CDN.&lt;/p&gt;

&lt;h4 class="relative group"&gt;How are winget CDN packages provided?
 &lt;div id="how-are-winget-cdn-packages-provided" 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="#how-are-winget-cdn-packages-provided" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h4&gt;
&lt;p&gt;Winget CDN packages reside within a public git repository hosted on &lt;a href="https://github.com/microsoft/winget-pkgs" target="_blank" rel="noreferrer"&gt;GitHub&lt;/a&gt;. The repository contains an alphabetic folder structure by vendor and product name holding manifests in YAML format that describe the app details.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt=""
 src="https://cdn-images-1.medium.com/max/800/1*UY1wLURvUmrb-FKFa-Uapw.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;The &lt;code&gt;manifests&lt;/code&gt; folder within the repo is grouped by the app vendor and app name and YAML contents of a manifest look like this:&lt;/p&gt;</description></item><item><title>Setting up a radius server for Azure AD joined devices and 802.1x</title><link>https://tech.nicolonsky.ch/radius-aad-joined-devices/</link><pubDate>Sun, 25 Sep 2022 00:00:00 +0000</pubDate><guid>https://tech.nicolonsky.ch/radius-aad-joined-devices/</guid><description>&lt;p&gt;A common pitfall in environments where Windows server is used for radius authentication is that Microsoft network policy server (NPS) does currently not support device based authentication for Azure AD joined devices. NPS always checks for the existence of a corresponding computer object in AD. For my home setup and lab I wanted to build a radius solution to enable 802.1x authentication on my Wi-Fi network.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Disclaimer
 &lt;div id="disclaimer" 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="#disclaimer" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;This post describes my setup and does not cover prerequisites like certification authority, certificate revocation and client certificate deployment via SCEP. Furthermore you should be familiar with docker, network topics, dns and Intune.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Available solutions
 &lt;div id="available-solutions" 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="#available-solutions" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Well known commercial Network Access Control (NAC) solutions like CISCO ISE or Aruba Clearpass often ship with an integrated RADIUS server and the possibility to configure wheter LDAP lookups for computer accounts should happen. Important is, that the solution supports certificate revocation checks either via CRLs or OCSP to ensure network access is blocked when a client certificate is revoked.&lt;/p&gt;
&lt;p&gt;For my home and lab setup I wanted to leverage a free or open source solution and decided to use freeRADIUS, probably the most popular open source radius server. freeRADIUS supports EAP-TLS for 802.1x authentication out of the box and is well documented.
Additionally, I was looking for a solution that can be deployed to both locallly in my network (e.g. on a raspberry pi) and also to PaaS offerings like Azure.&lt;/p&gt;</description></item><item><title>I said Connect-AzureAD and not sign-out and re-sign-in!</title><link>https://tech.nicolonsky.ch/i-said-connect-azuread-and-not-sign-out-and-re-sign-in/</link><pubDate>Wed, 25 Mar 2020 17:21:25 +0000</pubDate><guid>https://tech.nicolonsky.ch/i-said-connect-azuread-and-not-sign-out-and-re-sign-in/</guid><description>&lt;p&gt;If you are using the &amp;ldquo;AzureAD&amp;rdquo; PowerShell module (also applies to the AzureADPreview) you have probably noticed that the &lt;em&gt;Connect-AzureAD&lt;/em&gt; Cmdlet ignores existing access tokens and initiates a new sign in to Azure AD even if you are already signed in.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2020/03/image.png"&gt;&lt;figcaption&gt;Prompt you get when calling the "Connect-AzureAD" cmdlet&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;Long story short, I got annoyed every time when I accidentally recalled &lt;em&gt;Connect-AzureAD&lt;/em&gt; (mostly when working with Scripts)  until I found this amazing hint on &lt;a href="https://social.msdn.microsoft.com/Forums/sqlserver/en-US/386223c4-8821-415e-acea-68b47586131c/powershell-azuread-check-if-connection-is-established-with-connectazuread?forum=WindowsAzureAD" target="_blank" rel="noreferrer"&gt;technet&lt;/a&gt; and now I want to (re-)share it with you.&lt;/p&gt;
&lt;p&gt;In your PowerShell scripts simply use the following snippet to connect with Azure AD / check your connection and you wont get any sign-in prompts if you are already connected!&lt;/p&gt;
&lt;script src="https://gist.github.com/nicolonsky/798cfc9c0b5543647347cf09de6ef3c8.js"&gt;&lt;/script&gt;

&lt;h3 class="relative group"&gt;Reusing the access token for the MsOnline module
 &lt;div id="reusing-the-access-token-for-the-msonline-module" 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="#reusing-the-access-token-for-the-msonline-module" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The Azure AD PowerShell access token which gets stored can also be used to connect to the MsOnline resources (because certain attributes like strong authentication details are not available with the AzureAD modules):&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-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$token&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="no"&gt;Microsoft.Open.Azure.AD.CommonLibrary.AzureSession&lt;/span&gt;&lt;span class="p"&gt;]::&lt;/span&gt;&lt;span class="n"&gt;AccessTokens&lt;/span&gt; &lt;span class="nb"&gt;Connect-MsolService&lt;/span&gt; &lt;span class="n"&gt;-AccessToken&lt;/span&gt; &lt;span class="nv"&gt;$token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="py"&gt;AccessToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccessToken&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;</description></item><item><title>Generate a report about assigned Azure Active Directory roles</title><link>https://tech.nicolonsky.ch/report-assigned-azure-ad-roles/</link><pubDate>Thu, 19 Mar 2020 20:42:07 +0000</pubDate><guid>https://tech.nicolonsky.ch/report-assigned-azure-ad-roles/</guid><description>&lt;p&gt;The Azure AD portal does not really provide an overview about all directory role assignments in your tenant. If you want to review existing Azure AD Directory roles a csv report will probably better server your needs. Therefore I created a PowerShell script to export the role assignments.&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2020/03/DirectoryRoles.png" class="kg-image"&gt;&lt;figcaption&gt;The Azure AD Portal only displays limited information about the assignments&lt;/figcaption&gt;&lt;/figure&gt;
### PowerShell Script
&lt;p&gt;Find the PowerShell script in my &lt;a href="https://github.com/nicolonsky/Techblog/blob/master/New-AzureADDirectoryRoleReport/New-AzureADDirectoryRoleReport.ps1" target="_blank" rel="noreferrer"&gt;techblog GitHub Repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Make sure that you have the AzureAD PowerShell module installed before running the script. You can install it by running &amp;ldquo;&lt;em&gt;Install-Module AzureAD&amp;rdquo;.&lt;/em&gt;&lt;/p&gt;
&lt;figure&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2020/03/New-AzureADDirectoryRoleReport_RoleReport-2.png"&gt;&lt;figcaption&gt;PowerShell script output&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h3 class="relative group"&gt;Report
 &lt;div id="report" 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="#report" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;The report contains three columns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Role&lt;/strong&gt; (name of the directory role)
&lt;ul&gt;
&lt;li&gt;Note that the Global Administrator Role is represented as Company Administrator&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Member&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;If the role is assigned to a user its the UserPrincipalName&lt;/li&gt;
&lt;li&gt;If the role is assigned to a service principal its the display name with the Azure AD application ID in the brackets&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ObjectType&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Indicates whether the role is assigned to user account or a service principal&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;figure&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2020/03/RoleReport.png"&gt;&lt;figcaption&gt;CSV file containing all assigned directory roles&lt;/figcaption&gt;&lt;/figure&gt;

&lt;h3 class="relative group"&gt;Comparing reports
 &lt;div id="comparing-reports" 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="#comparing-reports" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;You can compare two reports with the following PowerShell code:&lt;/p&gt;</description></item><item><title>Detect Deleted User Accounts in Azure Active Directory</title><link>https://tech.nicolonsky.ch/detect-deleted-user-accounts-in-azure-active-directory/</link><pubDate>Thu, 13 Feb 2020 08:30:46 +0000</pubDate><guid>https://tech.nicolonsky.ch/detect-deleted-user-accounts-in-azure-active-directory/</guid><description>&lt;p&gt;An account in your Azure Active Directory got deleted and you want to examine who initiated the delete action? Sounds very simple but if you do not want to search your logs manually things become a little bit trickier.&lt;/p&gt;

&lt;h3 class="relative group"&gt;The challenge
 &lt;div id="the-challenge" 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-challenge" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;When a user gets deleted and you only remember it&amp;rsquo;s userPrincipalName you wont be able to to search for a match. And I doubt that you memorized the Azure AD object id of that user.&lt;/p&gt;
&lt;p&gt;Here&amp;rsquo;s what the Azure AD Audit log shows us:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://tech.nicolonsky.ch/content/images/2020/02/Azure-AD-Deleted-User.png" &gt;&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Azure AD Audit Logs"
 src="https://tech.nicolonsky.ch/content/images/2020/02/Azure-AD-Deleted-User.png"
 &gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The userPrincipalName attribute will get the Azure AD object ID as prefix:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;userPrincipalName before deletion: &lt;a href="mailto:jane.doe@nicolonsky.ch" &gt;jane.doe@nicolonsky.ch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;userPrincipalName after deletion: &lt;a href="mailto:f5d7e17347594a658d124329b9b025abjane.doe@nicolonsky.ch" &gt;f5d7e17347594a658d124329b9b025abjane.doe@nicolonsky.ch&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By having a closer look to the Azure Active Directory Audit logs you will notice that the filtering or search capabilities are limited in terms of searching for a specific target:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://tech.nicolonsky.ch/content/images/2020/02/Azure-AD-Deleted-User-Audit-Logs-Limited.png" &gt;&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Limited filtering capabilities in Azure AD"
 src="https://tech.nicolonsky.ch/content/images/2020/02/Azure-AD-Deleted-User-Audit-Logs-Limited.png"
 &gt;&lt;/figure&gt;
&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Search is case-sensitive and only supports &amp;lsquo;starts with&amp;rsquo; operator&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;Which means we cannot search for the userPrincipalName. The only option in the Azure AD Audit Logs would be to download the logs and perform a search within a text editor which is not really feasible nor efficient.&lt;/p&gt;</description></item><item><title>Manage Azure AD group based licensing with PowerShell</title><link>https://tech.nicolonsky.ch/manage-azure-ad-group-based-licensing-with-powershell/</link><pubDate>Wed, 04 Dec 2019 14:39:00 +0000</pubDate><guid>https://tech.nicolonsky.ch/manage-azure-ad-group-based-licensing-with-powershell/</guid><description>&lt;p&gt;Recently I needed to assign a lot of Microsoft licenses to different Azure AD groups. Unfortunately Microsoft does currently not offer a solution to do this (yet). Instead of giving up on this I decided to analyze what actually happens when you assign a license to a group in the Azure portal and found some actions going on within the hidden portal API. As an outcome I built a PowerShell module to manage Azure AD group based licensing assignments.&lt;/p&gt;
&lt;!--kg-card-begin: markdown--&gt;
&lt;blockquote&gt;&lt;p&gt;Full functionality for group-based licensing is available through the Azure portal, and currently PowerShell and Microsoft Graph support is limited to read-only operations.&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/licensing-ps-examples" target="_blank" rel="noreferrer"&gt;PowerShell and Graph examples for group-based licensing in Azure AD&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;&lt;!--kg-card-end: markdown--&gt;

&lt;h2 class="relative group"&gt;The PowerShell module
 &lt;div id="the-powershell-module" 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-powershell-module" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The PowerShell module uses the &amp;ldquo;main.iam.ad.ext.azure&amp;rdquo; API for the license operations and the AzureRM module to get an access token for the API. &lt;strong&gt;Please note that the mentioned API is not officially supported or documented&lt;/strong&gt;. Although the API is being used by the Azure Portal for settings you configure via the portal.&lt;/p&gt;
&lt;p&gt;Kudos to &lt;a href="https://www.lieben.nu/liebensraum/2018/03/set-intune-mdm-user-scope-to-all-using-powershell-and-hidden-api/" target="_blank" rel="noreferrer"&gt;Jos Lieben&lt;/a&gt; for his &amp;ldquo;pioneer work&amp;rdquo; documenting on how to get an access token for the API.&lt;/p&gt;</description></item><item><title>Export and import Intune and Conditional Access configuration</title><link>https://tech.nicolonsky.ch/export-and-import-intune-and-conditional-access-configuration/</link><pubDate>Tue, 03 Dec 2019 07:28:18 +0000</pubDate><guid>https://tech.nicolonsky.ch/export-and-import-intune-and-conditional-access-configuration/</guid><description>&lt;p&gt;With Microsoft Graph we have powerful automation and configuration management capabilities. To further simplify this process I built the &amp;ldquo;&lt;a href="https://mwconcierge.azurewebsites.net/" target="_blank" rel="noreferrer"&gt;Modern Workplace Concierge&amp;rdquo;&lt;/a&gt;.  It is an ASP.NET application which uses an Azure AD multi tenant app to access the Microsoft Graph API on behalf to perform export and import tasks. The project uses the Microsoft Graph Beta API to access your tenant&amp;rsquo;s data.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Modern Workplace Concierge
 &lt;div id="modern-workplace-concierge" 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="#modern-workplace-concierge" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://mwconcierge.azurewebsites.net/" target="_blank" rel="noreferrer"&gt;Modern Workplace Concierge&lt;/a&gt; allows you to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Import and export Intune configuration and settings&lt;/li&gt;
&lt;li&gt;Import and export Conditional Access policies&lt;/li&gt;
&lt;li&gt;Download OSD ready offline Autopilot profiles&lt;/li&gt;
&lt;li&gt;Download stored PowerShell scripts in Intune (as PowerShell)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows you to import your existing Intune and Conditional Access configuration in new tenants or demo tenants. The files in JSON format can be used for further processing or documentation.&lt;/p&gt;
&lt;p&gt;And this all via web browser no client side prerequisites or PowerShell code is required!&lt;/p&gt;
&lt;figure class="kg-card kg-image-card kg-card-hascaption"&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2019/12/MwConcierge.png" class="kg-image"&gt;&lt;figcaption&gt;The Modern Workplace Concierge&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The project and more information is &lt;a href="https://github.com/nicolonsky/ModernWorkplaceConcierge" target="_blank" rel="noreferrer"&gt;available on GitHub&lt;/a&gt; feel free to provide feedback there.&lt;/p&gt;
&lt;figure class="kg-card kg-embed-card"&gt;&lt;blockquote class="twitter-tweet"&gt;
&lt;p lang="en" dir="ltr"&gt;That's how I backup my Intune configuration with the &lt;a href="https://twitter.com/hashtag/ModernWorkplaceConcierge?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#ModernWorkplaceConcierge&lt;/a&gt;. Curious? Give it a try. Of course also supporting imports .&lt;a href="https://t.co/30H8b0olLn"&gt;https://t.co/30H8b0olLn&lt;/a&gt; &lt;a href="https://t.co/g5X58l1e1i"&gt;pic.twitter.com/g5X58l1e1i&lt;/a&gt;&lt;/p&gt;— Nicola Suter (@nicolonsky) &lt;a href="https://twitter.com/nicolonsky/status/1201745635545952256?ref_src=twsrc%5Etfw"&gt;December 3, 2019&lt;/a&gt;
&lt;/blockquote&gt;
&lt;script async src="https://platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;
&lt;/figure&gt;
&lt;p&gt;More Information:&lt;/p&gt;</description></item><item><title>Conditional Access and Azure Log Analytics in Harmony</title><link>https://tech.nicolonsky.ch/conditional-access-and-azure-log-analytics-in-harmony/</link><pubDate>Fri, 18 Oct 2019 22:06:04 +0000</pubDate><guid>https://tech.nicolonsky.ch/conditional-access-and-azure-log-analytics-in-harmony/</guid><description>&lt;p&gt;Auditing Conditional Access events and changes is crucial regarding your hygiene in Azure AD for your modern workplace. With the goal that we receive appropriate notifications and alerts if special events occur. Thanks to Azure Log Analytics (also referred to as Azure Monitor) we can easily filter and create alerts based on events. This post starts where most of the others end - giving you practical examples of KUSTO queries to search your Azure AD Audit logs with Log Analytics.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Default log retention in AAD
 &lt;div id="default-log-retention-in-aad" 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="#default-log-retention-in-aad" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;A point which get&amp;rsquo;s raised often is the default log retention in Azure Active Directory (AAD). Azure Active Directory stores all activity reports depending on your license for 7 or 30 days:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Azure AD Free and Basic: 7 days&lt;/li&gt;
&lt;li&gt;Azure AD Premium P1  and P2: 30 days&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/reports-monitoring/reference-reports-data-retention#how-long-does-azure-ad-store-the-data" target="_blank" rel="noreferrer"&gt;Source, more Information.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;To retain and further process Azure Active Directory Audit Logs for a longer time period (because a 30 day audit trail is likely too short for most organizations) we can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stream to an &lt;a href="https://azure.microsoft.com/en-in/services/event-hubs/" target="_blank" rel="noreferrer"&gt;Azure Event Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Archive to Blob Storage&lt;/li&gt;
&lt;li&gt;Forward them to Azure Log Analytics&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With Log Analytics the KUSTO query language can be used to query the forwarded log entries and we can create alert rules based on custom queries.&lt;/p&gt;</description></item><item><title>Unable to reset Windows Hello for Business PIN</title><link>https://tech.nicolonsky.ch/unable-to-reset-windows-hello-for-business-pin/</link><pubDate>Fri, 11 Oct 2019 16:12:14 +0000</pubDate><guid>https://tech.nicolonsky.ch/unable-to-reset-windows-hello-for-business-pin/</guid><description>&lt;p&gt;Recently I have been troubleshooting a nasty Windows Hello for Business problem which prevented all users in a tenant from resetting their Windows Hello for Business PIN&amp;rsquo;s on Azure AD joined devices while getting the error &lt;em&gt;CAA20004&lt;/em&gt;.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Issue
 &lt;div id="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="#issue" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;When clicking on &amp;ldquo;I forgot my PIN&amp;rdquo;:&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="WHFB PIN RESET"
 src="https://tech.nicolonsky.ch/content/images/2019/10/Windows-Hello-forBusiness-ForgotPin.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;After completing the account sign-in and MFA challenge the Error CAA20004 came up:&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Windows Hello for Business Error CAA20004"
 src="https://tech.nicolonsky.ch/content/images/2019/10/Windows-Hello-forBusiness-PIN-Reset-Error.png"
 &gt;&lt;/figure&gt;

&lt;h2 class="relative group"&gt;Troubleshooting
 &lt;div id="troubleshooting" 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="#troubleshooting" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;The Azure AD Portal shows us &amp;ldquo;Failure reason: other&amp;rdquo;.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt=""
 src="https://tech.nicolonsky.ch/content/images/2019/10/Error-AAD.png"
 &gt;&lt;/figure&gt;
&lt;p&gt;While recording all the https traffic to Microsofts oauth2 endpoint with Fiddler this finally unveils usable information:&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt=""
 src="https://tech.nicolonsky.ch/content/images/2019/10/Fiddler.png"
 &gt;&lt;/figure&gt;
&lt;blockquote&gt;&lt;p&gt;AADSTS65001: The user or administrator has not consented to use the application with ID &amp;rsquo; &lt;strong&gt;9115dd05-fad5-4f9c-acc7-305d08b1b04e&lt;/strong&gt;&amp;rsquo; named &amp;rsquo; &lt;strong&gt;Microsoft Pin Reset Client Production&lt;/strong&gt;&amp;rsquo;. Send an interactive authorization request for this user and resource.&lt;/p&gt;
&lt;/blockquote&gt;&lt;p&gt;The error indicates that an application registration is missing in the tenant for the application &amp;ldquo;Microsoft Pin Reset Client Production&amp;rdquo;&lt;/p&gt;

&lt;h2 class="relative group"&gt;Solution
 &lt;div id="solution" 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="#solution" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;After a short search I found a matching &lt;a href="https://docs.microsoft.com/en-us/intune/remote-actions/device-windows-pin-reset" target="_blank" rel="noreferrer"&gt;Microsoft docs article&lt;/a&gt;. Instead of reading through the whole article the only thing I needed to do was consenthing to the: &lt;a href="https://login.windows.net/common/oauth2/authorize?response_type=code&amp;amp;client_id=b8456c59-1230-44c7-a4a2-99b085333e84&amp;amp;resource=https%3A%2F%2Fgraph.windows.net&amp;amp;redirect_uri=https%3A%2F%2Fcred.microsoft.com&amp;amp;state=e9191523-6c2f-4f1d-a4f9-c36f26f89df0&amp;amp;prompt=admin_consent" target="_blank" rel="noreferrer"&gt;Microsoft PIN Reset Service production&lt;/a&gt; application and also for the &lt;a href="https://login.windows.net/common/oauth2/authorize?response_type=code&amp;amp;client_id=9115dd05-fad5-4f9c-acc7-305d08b1b04e&amp;amp;resource=https%3A%2F%2Fcred.microsoft.com%2F&amp;amp;redirect_uri=ms-appx-web%3A%2F%2FMicrosoft.AAD.BrokerPlugin%2F9115dd05-fad5-4f9c-acc7-305d08b1b04e&amp;amp;state=6765f8c5-f4a7-4029-b667-46a6776ad611&amp;amp;prompt=admin_consent" target="_blank" rel="noreferrer"&gt;Microsoft PIN Reset Client production&lt;/a&gt;&lt;/p&gt;</description></item><item><title>5 Ways to Screw Up Conditional Access</title><link>https://tech.nicolonsky.ch/5-ways-to-screw-up-conditional-access/</link><pubDate>Wed, 28 Aug 2019 08:34:02 +0000</pubDate><guid>https://tech.nicolonsky.ch/5-ways-to-screw-up-conditional-access/</guid><description>&lt;p&gt;Nowadays where cloud services are available from all over the world we cannot (only) rely on trusted networks and on identities protected by usernames and passwords. Conditional access allows you to define granular controls whether an identity can access cloud applications. Based on the positive feedback for my &amp;ldquo;&lt;a href="https://tech.nicolonsky.ch/5-ways-to-screw-up-your-intune-tenant/" &gt;5 Ways to Screw up your Intune Tenant&lt;/a&gt;&amp;rdquo; post I felt empowered to get conditional access covered as well.&lt;/p&gt;

&lt;h2 class="relative group"&gt;Chose your platform wisely
 &lt;div id="chose-your-platform-wisely" 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="#chose-your-platform-wisely" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;If you intend to use the device platform filter make sure that you cover all platforms including unknown platforms. Otherwise your might have a lack in your battleship. &lt;a href="https://tech.nicolonsky.ch/bypassing-conditional-access-device-platform-policies/" &gt;Also note that platform detection is based on best effort and can be exploited&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;&lt;img
 class="my-0 rounded-md"
 loading="lazy"
 decoding="async"
 fetchpriority="low"
 alt="Platform"
 src="https://tech.nicolonsky.ch/content/images/2019/08/conditional-access-device-platform.png"
 &gt;&lt;/figure&gt;

&lt;h2 class="relative group"&gt;Long live legacy
 &lt;div id="long-live-legacy" 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="#long-live-legacy" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Mind the client apps configuration to ensure that your conditional access policies also apply to non-modern authentication clients. If you have created your conditional access policies in the early days of the product you didn&amp;rsquo;t have this option available.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;Something that has created some confusion is that conditional access policies don&amp;rsquo;t include legacy authentication clients by default, this means that if you have a conditional access policy enforcing MFA for all users and all cloud apps, it doesn&amp;rsquo;t block legacy authentication clients (or &amp;ldquo;Other clients&amp;rdquo;, as the CA UI refers to them) - Sue Bohn, Microsoft&lt;/p&gt;</description></item><item><title>Bypassing Conditional Access Device Platform Policies</title><link>https://tech.nicolonsky.ch/bypassing-conditional-access-device-platform-policies/</link><pubDate>Tue, 02 Jul 2019 17:12:06 +0000</pubDate><guid>https://tech.nicolonsky.ch/bypassing-conditional-access-device-platform-policies/</guid><description>&lt;p&gt;Recently I read &lt;a href="https://techcommunity.microsoft.com/t5/Azure-Active-Directory-Identity/Azure-AD-Mailbag-Conditional-Access-Q-amp-A/ba-p/566492" target="_blank" rel="noreferrer"&gt;a great article from the Microsoft IAM Director Sue Bohn&lt;/a&gt; concerning a Conditional Access Q&amp;amp;A. One question was about the device platform feature - which let&amp;rsquo;s you apply a policy only to a specific device platform like iOS, Android or Windows 10.&lt;/p&gt;
&lt;p&gt;The detection of the device platform relies on the user agent string sent by the application or web browser. Because this one can be spoofed easily better configure your Conditional Access policies wisely.&lt;/p&gt;

&lt;h2 class="relative group"&gt;The problem
 &lt;div id="the-problem" 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-problem" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;As soon as you enable the device platform selection there&amp;rsquo;s the chance that a user doesn&amp;rsquo;t catch any Conditional Access policy.&lt;/p&gt;
&lt;blockquote&gt;&lt;p&gt;As a result, you should &lt;u&gt;not rely&lt;/u&gt; on the User Agent String to be present or to be accurate. Most browsers have a function to set an arbitrary User Agent String for testing purposes. (Microsoft)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 class="relative group"&gt;Bypass example
 &lt;div id="bypass-example" 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="#bypass-example" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;To give you an example, here&amp;rsquo;s a little walk-through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Conditional Access Policy configured for all cloud apps&lt;/li&gt;
&lt;li&gt;Windows 10 selected as device platform&lt;/li&gt;
&lt;li&gt;Access control: Block&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="kg-card kg-image-card"&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2019/07/conditional-access-policy.png" class="kg-image"&gt;&lt;/figure&gt;
&lt;p&gt;If we now try to access the azure portal with a Windows 10 app or browser we get the following result:&lt;/p&gt;</description></item><item><title>Calling the Microsoft Graph API via PowerShell without a user</title><link>https://tech.nicolonsky.ch/calling-the-microsoft-graph-api/</link><pubDate>Mon, 17 Jun 2019 18:47:47 +0000</pubDate><guid>https://tech.nicolonsky.ch/calling-the-microsoft-graph-api/</guid><description>&lt;p&gt;A colleague recently asked me how to access the Microsoft Graph API using PowerShell without specifying his user account or credentials. So here&amp;rsquo;s a little post about the required configuration to authenticate against the OAuth 2.0 endpoint of Azure AD with an app registration. This is especially useful for automation services like Azure automation.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://tech.nicolonsky.ch/calling-the-microsoft-graph-api/#powershell-template" &gt;At the end of this post you&amp;rsquo;ll find a PowerShell template.&lt;/a&gt;&lt;/p&gt;

&lt;h2 class="relative group"&gt;Gather application information
 &lt;div id="gather-application-information" 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="#gather-application-information" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;Create a new client secret for your app and note down the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Client Secret&lt;/li&gt;
&lt;li&gt;Application ID (client ID)&lt;/li&gt;
&lt;li&gt;Directory ID (tenant ID)&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class="kg-card kg-image-card kg-card-hascaption"&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2019/06/image-1.png" class="kg-image"&gt;&lt;figcaption&gt;Azure AD App registration&lt;/figcaption&gt;&lt;/figure&gt;
## PowerShell code

&lt;h3 class="relative group"&gt;Request authentication token
 &lt;div id="request-authentication-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="#request-authentication-token" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h3&gt;
&lt;p&gt;In order to use the Graph API we need an authentication token. The information we gathered before is now sent to the Azure AD OAuth 2.0 endpoint.&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;https://login.microsoftonline.com/{TenantID}/oauth2/v2.0/token&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;In the request supply a body with the following content:&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-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;8f9f420d-606c-4e13-889e-837072dbfb42&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;BlaBlaExampleSecret&amp;#34;&lt;/span&gt; &lt;span class="c"&gt;#Generated secret&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://graph.microsoft.com/.default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;client_credentials&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;scope&lt;/em&gt; and &lt;em&gt;grant_type&lt;/em&gt; are required attributes. A full example looks like:&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-powershell" data-lang="powershell"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$body&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="vm"&gt;@&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client_id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;8f9f420d-606c-4e13-889e-837072dbfb42&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;BlaBlaExampleSecret&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;https://graph.microsoft.com/.default&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;grant_type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;client_credentials&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;$tenantId&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;7955e1b3-cbad-49eb-9a84-e14aed7f3400&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;Invoke-WebRequest&lt;/span&gt; &lt;span class="n"&gt;-Uri&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;https://login.microsoftonline.com/&lt;/span&gt;&lt;span class="nv"&gt;$tenantId&lt;/span&gt;&lt;span class="s2"&gt;/oauth2/v2.0/token&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-ContentType&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;application/x-www-form-urlencoded&amp;#34;&lt;/span&gt; &lt;span class="n"&gt;-Body&lt;/span&gt; &lt;span class="nv"&gt;$body&lt;/span&gt; &lt;span class="n"&gt;-Method&lt;/span&gt; &lt;span class="n"&gt;Post&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If everything works we receive an access token object as HTML 200/ok response:&lt;/p&gt;</description></item><item><title>Intune map network drives and execute PowerShell script on each user logon</title><link>https://tech.nicolonsky.ch/intune-execute-powershell-script-on-each-user-logon/</link><pubDate>Fri, 11 Jan 2019 20:51:36 +0000</pubDate><guid>https://tech.nicolonsky.ch/intune-execute-powershell-script-on-each-user-logon/</guid><description>&lt;p&gt;Recently a customer needed a drive mapping solution to access his on premise file shares during his transition phase to a cloud-only workplace. I wanted to share the solution with you because it&amp;rsquo;s  a frequently asked question around a modern workplace migration. The following solution can also be extended or modified for a printer mapping or other PowerShell scripts which need to run on each user logon.&lt;/p&gt;
&lt;!--kg-card-begin: markdown--&gt;
&lt;p&gt;&lt;mark&gt;&lt;strong&gt;Updated 04.08.2019&lt;/strong&gt;: I&amp;rsquo;ve developed an automated solution to generate network drive mapping configurations with an online tool which also migrates group policy network drive mappings. See: &lt;a href="https://tech.nicolonsky.ch/next-level-network-drive-mapping-with-intune"&gt;next-level-network-drive-mapping-with-intune&lt;/a&gt;.&lt;/mark&gt;&lt;/p&gt;
&lt;!--kg-card-end: markdown--&gt;&lt;!--kg-card-begin: markdown--&gt;
&lt;p&gt;&lt;a href="https://github.com/nicolonsky/Techblog/tree/master/IntuneNetworkDrives" target="_blank" rel="noreferrer"&gt;Direct link to the final scripts&lt;/a&gt;&lt;/p&gt;
&lt;!--kg-card-end: markdown--&gt;
&lt;p&gt;Lets assume we have the following scenario:&lt;/p&gt;
&lt;figure class="kg-card kg-image-card"&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2019/01/Hybrid-AAD.png" class="kg-image"&gt;&lt;/figure&gt;
- Customer with hybrid user-identities (Azure AD Connect)
- On premise ressources with legacy file shares
- Devices are Azure AD joined &amp;nbsp;( **not** hybrid joined)
- MDM managed with Intune
- [Optional] Always on VPN for external on-premise resource access
- [Optional] Windows Hello for Business deployment as described [here](https://docs.microsoft.com/en-us/windows/security/identity-protection/hello-for-business/hello-hybrid-aadj-sso) 

&lt;h2 class="relative group"&gt;Architecture
 &lt;div id="architecture" 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="#architecture" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;With my colleague &lt;a href="https://blog.alschneiter.com/" target="_blank" rel="noreferrer"&gt;Alain Schneiter&lt;/a&gt; I designed the following solution:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Main PowerShell script stored on Azure blob storage which handles the drive mapping -  driveletters, UNC paths and descriptions can be configured within the script  &lt;/li&gt;
&lt;li&gt;Client side script deployed with Intune which triggers the main script during logon.  The main script is not stored locally which makes it easy to customize (no updates oder changes needed on client side)&lt;/li&gt;
&lt;li&gt;Deployment is user targeted via Azure AD group and Intune&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 class="relative group"&gt;Azure blob storage configuration
 &lt;div id="azure-blob-storage-configuration" 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="#azure-blob-storage-configuration" aria-label="Anchor"&gt;#&lt;/a&gt;
 &lt;/span&gt;
 
&lt;/h2&gt;
&lt;p&gt;We wanted to store the script within Azure because the customer was already using Azure blob storage. It&amp;rsquo;s also possible to store the PowerShell script on GitHub if you don&amp;rsquo;t want to use Azure.&lt;/p&gt;</description></item><item><title>Clean up stale Azure AD devices</title><link>https://tech.nicolonsky.ch/clean-up-azure-ad-devices/</link><pubDate>Thu, 10 Jan 2019 22:25:00 +0000</pubDate><guid>https://tech.nicolonsky.ch/clean-up-azure-ad-devices/</guid><description>&lt;p&gt;If you are using Azure AD and the time passes you&amp;rsquo;ll have a lot of old device entries. If you enable the automatic device cleanup rule in Microsoft Intune the device is only removed within MDM and the Azure AD entry still exists.&lt;/p&gt;
&lt;figure class="kg-card kg-image-card kg-card-hascaption"&gt;&lt;img src="https://tech.nicolonsky.ch/content/images/2019/01/image-1.png" class="kg-image"&gt;&lt;figcaption&gt;Intune device cleanup rule&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;For this reason I created a tiny PowerShell snippet to create a report with all devices which didn&amp;rsquo;t contact your Azure AD tenant since the treshold date specified. If you confirm the operation you can also delete all affected devices.&lt;/p&gt;
&lt;!--kg-card-begin: markdown--&gt;
&lt;p&gt;&lt;mark&gt;&lt;em&gt;Please be careful when running the script because when removing a device from Azure AD the stored Bitlocker recovery keys are also removed. I can recommend &lt;a href="http://rzander.azurewebsites.net/bitlocker-management-with-azure-storage-table/"&gt;Roger Zander&amp;rsquo;s Azure table-based Bitlocker recovery key solution&lt;/a&gt;.&lt;/em&gt;&lt;/mark&gt;&lt;/p&gt;
&lt;!--kg-card-end: markdown--&gt;&lt;!--kg-card-begin: markdown--&gt;&lt;script src="https://gist.github.com/nicolonsky/231844d2c383396331a94024bffbd7ff.js"&gt; &lt;/script&gt;&lt;!--kg-card-end: markdown--&gt;</description></item></channel></rss>