Using FIDO2 security keys with PowerShell

If you are using a FIDO2 Security Key, such as a YubiKey, you may have run into the issue that you cannot use it to authenticate with your Azure AD account using PowerShell:


As you can see, the needed Sign in with a security key option is missing here.

This is because PowerShell still uses the older Active Directory Authentication Library (ADAL) when prompting for Azure AD credentials. That login prompt is actually rendered using Internet Explorer, and IE will likely never have support for WebAuthN, the protocol that FIDO2 logon requires.

So we have four options:

  1. Wait until PowerShell moves from ADAL to MSAL, and sign in prompts are rendered by a modern browser that supports WebAuthN.
  2. Wait until each PowerShell Module you need starts supporting its own implementation of modern authentication to Azure AD.
  3. Use Cloud Shell, where you can run PowerShell directly in your browser:

    This option works with FIDO2, but a web-based shell has its limitations.

  4. Use Device Authorization Grant Flow to login.

This post explains the last option.

What is Device Authorization Grant Flow

The Device authorization grant flow is usually used when you need to sign in on “input-constrained devices”, such as IoT devices and printers. In this case, we can view PowerShell as a “device”. The sign in flow is initiated on the device, but the user needs to visit a web page (on any device with a browser that hopefully supports WebAuthN) to complete the sign in. Once the user has signed in, the device (or PowerShell window) can get the needed access tokens and refresh tokens.

Initiate the Device Authorization Grant Flow

Run this code in the PowerShell window you want to sign in to Azure AD:

Note: You do not need to register any new app in Azure AD for this to work since we are using the well-known ClientID for Azure AD PowerShell. You do not have to add any custom values for your tenant either, since we use the Common endpoint. This means that you will automatically be redirected to the tenant the user belongs to when signing in.

$ClientID = '1b730954-1685-4b74-9bfd-dac224a7b894'
$TenantID = 'common'
$Resource = '' #Service Endpoint for Azure AD Graph

$DeviceCodeParameters = @{
    Method = 'POST'
    Uri    = "$TenantID/oauth2/devicecode"
    Body   = @{
        client_id = $ClientId
        resource  = $Resource

$DeviceCodeRequest = Invoke-RestMethod @DeviceCodeParameters
Write-Host $DeviceCodeRequest.message -ForegroundColor Green

A code will be shown that you need to enter at the following web page to continue the sign in:


Besides, you can also use Both will redirect you to

Enter the code in the prompt:


As you can see, we are now signing in on a remote device or service.

Be aware that this sign in method can be misused in phishing attempts. Only enter codes you generated yourself!

You can sign in using your regular account name and password, but to sign in using a FIDO2 key, click on Sign-in options:


Now we can use our FIDO2 key to authenticate:


Once authentication is successful, you can close the page in the web browser. The next step (obtaining tokens) will happen in the PowerShell window:


Obtain the tokens

Again, no customization is needed for this script block. We are re-using the device_code from the DeviceCodeRequest we made earlier.

$TokenParameters = @{
    Method = 'POST'
    Uri    = "$TenantId/oauth2/token"
    Body   = @{
        grant_type = "urn:ietf:params:oauth:grant-type:device_code"
        code       = $DeviceCodeRequest.device_code
        client_id  = $ClientId

$TokenRequest = Invoke-RestMethod @TokenParameters
$Token = $TokenRequest.access_token

You now have a valid access token in the variable $Token that can be used to authenticate when using Connect-AzureAD. Note that the variable $TokenRequest also contains refresh_token and id_token, if you want to use them.

Connect to Azure AD

When using the Connect-AzureAD cmdlet with an access token, you also need to specify the username you used to authenticate and the TenantId. You can find your TenantID using PowerShell:

$TenantDomain = ""

or by going to :

Now we are ready to connect to Azure AD:

Connect-AzureAD -AadAccessToken $Token -AccountId -TenantId <insert-tenant-id-here>

Now you should be able to run commands from that module, like this one to get the first group:

Get-AzureADGroup -Top 1

What if I need to use the Microsoft Graph?

That will also work, but you need to change $Resource variable in the first script block to the Service Endpoint of Microsoft Graph (;) and repeat the process.

Then you should be able to run queries against the Microsoft Graph, like this one to get the first group:

$GroupsParameters = @{
    Method  = 'GET'
    Uri     = '$top=1'
    Headers = @{
        'Authorization' = "Bearer $Token" 

$GroupRequest = Invoke-RestMethod @GroupsParameters

How about Exchange Online?

For this to work, you need to change both the $Resource and the $ClientID variables in the first script block to:

$ClientID = ‘a0c73c16-a7e3-4564-9a95-2bdf47383716’  # Exchange Online PowerShell Azure Active Directory

$TenantID = ‘common’

$Resource = ‘’        # Service Endpoint for Exchange Online

After you obtain the token you need to create a new credential object based on your username and the token:

$upn = ‘’
$TokenAsSecString = ConvertTo-SecureString “Bearer $($token)” -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($upn,$TokenAsSecString)

Now you can connect to Exchange Online using these commands:

$session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri “” -Credential $credential -Authentication Basic -AllowRedirection

Import-PSSession $session


Big thanks to Stefan Schörling (@stefanschorling) for pointing me in the right direction and to Simon Wahlin for his writeup about Device login flow for MS Graph access.

Posted in Okategoriserade | Leave a comment

Highlight custom text on any Microsoft Docs page

Sometimes I want to highlight specific text when I’m sharing a Microsoft Docs-page to someone, like in this example:


You can do this yourself by appending the following text after the Docs-link:

?view=o365-worldwide#:~:text=Text To highlight

Unfortunately, this only works in Edge and Chrome, not in Firefox or IE.

Here’s an example:

Original Docs-link:

Appended text: identity



The yellow highlighting goes away when you click anywhere on the page or reload it.

If you want to highlight more text, you can add start text and end text. Everything in-between will be highlighted:

?view=o365-worldwide#:~:text=Start of highlight,End of Highlight

Example: Active Directory (,Microsoft 365.



I needed to add the ”(” there since the text Azure Active Directory existed many times on the page. Without it, it looked like this:


In other words, you will have to test your link to make sure it looks as expected.

Note that any spaces need to be converted to %20 for the entire link to be clickable: Active Directory (,Microsoft 365.  <- Missed,Microsoft%20365.

You don’t have to add them all manually. If you copy/paste the entire link into a web browser, it will convert %20 (and any other special characters according to standard HTML URL Encoding) wherever needed.

I hope this was a helpful tip!

Posted in Okategoriserade | Tagged , | Leave a comment

The consequence of not renewing ATA certificate in time

A customer who uses Microsoft Advanced Threat Analytics (ATA) recently had severe issues with their ATA implementation. At first, the portal started to behave strangely, not showing all information in alerts and some configuration settings were missing. After a restart of the ATA servers, the services failed to start at all.

The Microsoft.Tri.Center-Errors.log file contained many errors like this:

2020-01-09 12:34:27.9920 1140 98 Error [CertificateExtension] Microsoft.Tri.Infrastructure.Utils.ExtendedException: There are no matching certificates [StoreLocation=LocalMachine StoreName=My thumbprint=89E1C9790B175D2E6B716CFDDABA3D9F444829F6]

It turned out that their internal PKI had automatically renewed the certificate that ATA was configured to use. In general, this is what you want from a PKI (auto-renewed certificates), but unfortunately, ATA does not support renewing an existing certificate.

The reason is that some ATA data is encrypted using the configured certificate, and during certificate renewal, the old certificate is removed, so you lose the ability to decrypt that data.

So you need to create a new certificate before the old one expires and manually configure ATA to use the new certificate.

This requirement is clearly stated in the Microsoft ATA-documentation:



You will even get alerts in ATA Health Center about upcoming certificate expiration:



Replacing the certificate is not really that difficult or time-consuming. But if you do not replace the certificate before it expires you will get this alert:



You can see that that when this happens, the only resolution is to redeploy your ATA, and you will lose all your configuration, alerts, and behavior analysis history.

Other services that use certificates can usually be recovered really easy from issues caused by expired certificates by simply getting a new certificate and pointing the service to the new certificate, but since the “certificate pointing” in ATA is done in the ATA Configuration, which is encrypted by the previous certificate, there is a catch 22 situation here.

Some people have tried to manually add the thumbprint of a new certificate in the SystemProfile_date.json configuration file, and they have gotten the ATA up and running again. However, they could not edit all ATA settings after that, so they eventually ended up redeploying from scratch.

Restoring from backup after redeployment will not work either since the backup still points to the old removed certificate. You can still use that backup configuration file as a manual reference on how to configure ATA again , since it is in cleartext.

So go ahead and make sure that your ATA implementation does not use a certificate that will be automatically renewed, and/or put a reminder in your calendar to renew it before it expires. And monitor those health alerts!

Update 2020-09-14

In the newly released ATA version 1.9.3, Microsoft has updated the functionality around certificate renewal notifications:

Increased advance notice for Center certificate expiration to three months prior to expiration (previously three weeks). Additionally, the notice now provides a clearer description of the severity of failing to renew the certificate.

You can get the new version by using Windows Update or downloading it here::

Posted in ATA, Certificates, PKI, SSL | Tagged , | 1 Comment

Teams on iOS now supports Sensitivity Labels

In the newly released version 1.0.91 of Teams for iOS it was announced that it now supports Sensitivity Labels for your Teams:

(Sorry that the screenshots are in Swedish, you’ll have to trust me or translate it 😀)

I first tried to create a Team before I upgraded the Teams app, and I did not see any option to select Sensitivity Labels:

I then updated Teams to the new version, and sure enough, I could now select the Sensitivity of my new Team:

Always great to see Microsoft Information Protection getting adopted in more and more places.

Posted in Okategoriserade | Leave a comment

Copy your AIP Polices to the Security & Compliance Center

You have for a while been able to copy your AIP Labels to the Security & Compliance Center from the Azure Information Protection Portal.

But you can now also copy your AIP Policies (in Preview)!


You get a warning that any existing policies with the same name will be overwritten.
Click Yes to proceed:


It just takes a moment until you see the completion notification:


You will see a summary of the polices that was copied:

(I only had one policy in this tenant)

And sure enough, the new policy appeared right away in the Security & Compliance Center:


The policy settings I had configured was also copied:


Remember that this feature is still in Preview, so use with caution in production. And as always: test first!


Posted in AIP, encryption, information protection | Leave a comment

Using PowerShell to get wildcard certificate from Let’s Encrypt

This is a guide that shows you how to get a publicly trusted wildcard certificate at no cost from Let’s Encrypt using PowerShell.


  • Windows PowerShell 5.1
  • .NET Framework 4.7.2 (link to check)
  • Possibility to add CNAME in DNS

Step by step

Start PowerShell as admin (see information below for non-admin steps)

Verify that PowerShell’s ExecutionPolicy allows running scripts (i.e. RemoteSigned or less)


Otherwise: Set-ExecutionPolicy RemoteSigned


Install-Module -Name Posh-ACME

Accept warnings about untrusted repositories (that is, if you accept PSGallery, a common module repository):



New-PACertificate * -AcceptTOS -Contact <your-email> -DnsPlugin AcmeDns -PluginArgs @{ACMEServer=''} -Install


Explanation of the options used:

* The name you want in the certificate. You can add additional comma-separated names
AcceptTOS Indicates that you accept the Let’s Encrypt Terms of Service (see
Contact Email for expiration notification (optional)
DnsPlugin Which DNS plugin should be used for automatic domain ownership validation. Since my DNS provider Loopia isn’t natively supported by Posh-ACME, I used the ACMEDns option, which requires you to manually add a CNAME record in your DNS provider once, and that can be reused when updating the certificate. Here is a list of DNS providers supported by Posh-ACME:
PluginArgs Options that depends on chosen DNSPlugin
Install This option will install the certificate in the computer’s Certificate Store (requires admin permission, see Getting certificate without admin permission below)

Do not close the PowerShell window!

Add the CNAME record shown in the output of the command you just ran in the DNS registrar for the domain.
Here is an example from Swedish DNS registrar Loopia, but your DNS registrar interface may look different:


Go back to the PowerShell window and press enter to continue.
The script will wait 2 minutes for DNS to propagate:


After that, you should get the certificate:


To see more information about the certificate, you can use the following command:

Get-PACertificate | Format-List


Here you can see basic information about the certificate and that all the relevant files are stored in %LOCALAPPDATA%\Posh-ACME folder, and that it includes a PFX-file if you want to install the certificate on another machine. The default PFX-password is “poshacme”. You can specify your own with the option -PfxPass when running the New-PACertificate command.

Go to the Local Computer certificate store (run certlm.msc) and verify that the certificate has been installed correctly:


clip_image012 clip_image013

Depending on what service you are using the certificate for, you may need to make extra configuration steps in the service to start using the certificate.

You can manually renew the certificate by running the following command:

As you can see, it will not renew certificates that are not about to expire yet (I believe it uses 30 days or less validity time). You can override this by running:

Submit-Renewal -Force

To automate the renewal, you can create a scheduled task that runs this command daily:

Create a file called C:\Cert\AutoRenewal.ps1, containing the command “Submit-Renewal” (not the -Fore option, since you don’t want to renew at every check).

Run the following commands, but first change <password> to your own password
Note: The scheduled task must run in the context of the user requesting the certificate since validation information is stored in that user’s profile.

$Trigger = New-ScheduledTaskTrigger -At 10:00am -Daily
$Action= New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "C:\Cert\AutoRenewal.ps1"
Register-ScheduledTask -TaskName "Certificate AutoRenewal" -Trigger $Trigger -User "$env:USERDOMAIN\$env:USERNAME" -Password '<password>' -Action $Action -RunLevel Highest –Force

Test certificates

For testing, you can switch the Let’s Encrypt server you send your requests to. The test server does not create a publicly trusted certificate but has no rate limiting.

Read more about rate limiting here:

To use test server:


To use production server:

Set-PAServer LE_PROD

It will keep using the specified server until you change it again.

Getting certificate without admin permission

Most steps above work without admin permission, with the exception of installing the certificate in the Computer certificate store.

You might need to restrict the scoop of these commands as well:

Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

Install-Module -Name Posh-ACME -Scope CurrentUser

Then exclude the -Install option in the New-PACertificate command example above.

You will still get a valid publicly trusted certificate, and you can move the created pfx-file to a computer where you want to install it (where you are admin).

Custom Acme-DNS instance

In my example above, I use the public ACME-Dns service. The advantage of that is that your DNS provider does not have to support API access for the Domain Verification part. Instead, you manually create a CNAME record in your DNS provider once that redirects the DNS validation to ACME-Dns.

To increase security, you should use your own instance of Acme-DNS, see here:

Posted in Okategoriserade | 1 Comment

Hyper-V Guests with Windows 10 (1903) hangs when using Enhanced Session/RDP?

Are you also having the issue where accessing your Hyper-V VM Guests works great when connecting via Virtual Machine Connection, but the VM hangs when you try to access it using Enhanced Session or RDP?

The VM becomes irresponsible and the only solution is to use Turn off (shutdown doesn’t work). The machine starts to continuously consume about 12% or 24% CPU (seems to depend on the number of CPU cores).

I run client Hyper-V on a Windows 10 (1903) machine, and the guest is also Windows 10. Enhanced Session used to work great, until Windows 10 (1903).

After some troubleshooting and researching I found out that a new RDP display driver called WDDM was introduced in 1903. By disabling WDDM and reverting to the old XDDM driver the problem went away for me.

Here’s how to do it:

Start the Local Group Policy Editor:


Navigate here:
Local Computer Policy
/Computer Configuration
  /Administrative Templates
   /Windows Components
    /Remote Desktop Services
     /Remote Desktop Session Host
      /Remote Session Environment

Configure the setting Use WDDM graphics display driver for Remote Desktop Connections to Disabled:


In an AD environment you can of course use the regular Group Policy Management.

You can also create and import a reg-file with the following text:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services]

Reboot the Guest VM.

Yay, now I can access that guest VM using Enhanced Session again.

Posted in Hyper-V, RDP, Windows 10 | Tagged , , | 2 Comments

Enable FIDO2 credential manager in Windows 10

Once you have enrolled your FIDO2 security key in Azure AD (which can be done here), you can easily sign-in to web pages that use Azure AD as Identity Provider without needing to enter your password.

If your security key doesn’t have a fingerprint reader, you need to enter the key’s PIN but remember that this is only to unlock the secret on the key, and it is never sent or stored anywhere outside of the key:

If you also want to sign-in on a Windows 10 machine with a FIDO2 device (currently supported on Azure AD joined and version 1809 or higher), you need to enable the FIDO security key credential provider on that machine first:

This can be enabled in one of three ways:

1. Using Intune, as explained here.

2. If Intune doesn’t manage the client, you can manually create a provisioning package using Windows Configuration Designer  (an application that is available in the Microsoft Store. The steps are explained here.
Note that you have to choose All Windows desktop editions, if you choose All Windows editions, the setting isn’t available.

3. You can enable the FIDO credential provider, you by adding the following Registry Setting:

Windows Registry Editor Version 5.00

Copy the text above to a new text file, call it something.reg, double-click it and accept the warning.

Note! I haven’t seen the last method mentioned anywhere official, so it might not be supported. Use it with caution and test before using it in production.

Posted in fido2, Password, passwordless | Tagged , , | Leave a comment

Always get the English version at

When you visit, it shows pages in the local language you have configured in your browser’s settings. Sometimes the pages are properly translated by humans, sometimes it is machine translated.

I always want the English versions of the Docs site pages, but I do not want to have English as the default language in my browser since I want Swedish version on other websites.

I discovered the Firefox plugin called Redirector. It does one very simple task. It looks for pattern matches in the URL and modifies them according to my rules.

So I installed it and created the following Redirect rule:


The * is a wildcard, so anything will match. $1 is the value that the first wildcard represented. Note that my rule only matches Swedish (sv-se), you may need to modify your rules to match your language (or all languages).

Now, whenever I visit a page that starts with* it is immediately changed to*:


There are similar extensions for Chrome, but I have not tested them yet:


Switcheroo Redirector

Posted in Okategoriserade | Leave a comment

Azure Information Protection – Indication that a label encrypts

I’ve been missing an easy way to tell if an AIP label will encrypt information, or if it “only” adds the label metadata and/or visual markings. Sure, I can explain it in the description of the label, but that is not very intuitive.

We cannot add images to AIP labels, but I realized that there are a lot of symbols in the Unicode world – that are in fact just text but shown as icons – and I found this padlock icon using Word’s Insert Symbol feature:


If I insert that symbol into Word, I can then copy it from there and paste it wherever I want it.

This is what it looks like as text in Word 2016:


This is what it looks like in the Azure Portal, after I have pasted it into the Label display name and Description of an AIP label:


This is what it looks like in Word 2016 as an AIP label:


So the symbol looks different on different platforms, but it is always a padlock. There are other fonts that have padlocks, but I chose Segoe UI Symbol, since that font is installed by default in Windows.

Please note that using an unusual Unicode character might cause issues:

PowerShell ISE can partly handle the symbol correctly:


while PowerShell cannot:


Azure Information Protection Client can show it (right-clicking on files in Windows):


Cloud App Security can also show it correctly:


I do not know how it will look on platforms that do not have that font.

I do not know if other systems (like DLP) are able to correctly read/set the label. Many DLP can however use partial matching of strings.

Please leave a comment below if you have any more info on where this works or does not work.

Posted in AIP, CAS, encryption, information protection, Rights Management Services, RMS | Leave a comment