Fixed: Outlook desktop unable to render SharePoint hosted images embedded in to mail body through PowerAutomate send email action

This post comes out from a recent support experience to one of my clients. He was trying to use Microsoft PowerAutomate flow to embed a SharePoint library hosted image in to an email notification which sent regularly across the organization for all users. Usual way for doing this is using the <img src tag in the send email action but interestingly, these behaviors was a showstopper until I figured out the solution after several hours (described at the end of the article).



  1. Embedded images from a SharePoint URL did not render in Outlook desktop App
  2. Same image renders in OWA (Outlook Web App) however, there was a slight delay in loading the image.
  3. Same image hosted in public hosting locations rendered nicely as well (e.g –, Google etc..)

SharePoint hosted image in Outlook Desktop App: Strange enough !


External hosted image in Outlook Desktop App:


Tried and did not work for my case:

  • Change the text format to HTMLOutlook client application (File -> Options -> Mail -> Compose message in HTML format). This was already in place for my scenario.
  • Add the domain to safe/trusted sites in the browser settings
  • Plethora of other solutions from Microsoft articles and forums


The real solution:

To overcome this issue, you simply have to use these additional lines in your email step. Add a compose action and point it to ‘Get file content using path’ SharePoint action (or you can directly add this line to the mail body HTML)

Add a new Compose action in to the PowerAutomate flow 

Set the Expression as below (you can copy and paste this)



Amend the Mailbody to reflect the following or add the above mentioned expression directly to the HTML body. Either way should work.

File content using path<br> 

<img src="@{outputs('Compose_2')}"></img>


Full flow: Tested and working perfectly across web client and desktop client of Outlook


Result: SharePoint hosted image is now rendered perfectly in Outlook desktop App.


Root cause analysis:

The key point is the use of dataUri() to convert the file content to the right format that HTML can understand. An image or a file in general from a SharePoint link is not public link. Only authenticated users can view the image which is the root cause of this issue.

If a user logs in into Outlook on the web from  a browser, their Microsoft identification data are stored locally within the browser context as cookies. As a result, when opening an email that contains a SharePoint link in HTML image tags, a request will be sent to SharePoint servers with the same identification and the image can be downloaded if the user has enough privilege.

It’s the same way that if you have already logged in into one of the google services, you won’t have to login again when accessing other Google services in deferent tabs.

On the other hand, Outlook client is simply an email application which does not share the same architecture as a browser. Outlook account credentials are stored differently and Outlook does not have mechanism to detect and pass credentials to other Microsoft services. Hence, when it sees a SharePoint link in HTML image tags, a request without any authorization data will be sent to the SharePoint servers and of course, it will be refused. If a hyperlink added to the email, clicking on the link will open a browser and you will need to sign in.  In the end, the main purpose of Outlook client is for email-related tasks and it will not handle authentication for other services.


Remove orphaned delegation permissions of a deleted user in Exchange Online mailbox

You might think that a user’s delegate permissions for other mailboxes will be removed up on deleting the account in the Azure Active Directory, apparently it wasn’t in my case.



Location – Calendar folder of ‘\Calendar’

Delegated editor permissions to – ‘Marie Jonas’ (Abandoned identity after AD account deletion)

Even though this particular account was permanently deleted from Azure AD after 30 days of marking deletion, the delegation access (editor) to other users’ Exchange mailboxes remained intact which caused the following strange behaviors that I had to get rid of.

  • Others can still spot this user’s name in the calendar invites
  • Possibly in other various occasions too based on the permissions the user had before deleted

Here’s the PowerShell command to fetch the permissions of a specific location. This will list down all the delegated permissions of ‘Manoj’s’ Exchange calendar. In my case, the abandoned user also popped up in the results.

Get-EXOMailboxFolderPermission "\calendar" 


Now, to dig further down to be more specific to this mysterious user, let’s run this command

Get-EXOMailboxFolderPermission "\calendar" | where {$_.user.tostring() -like "Marie Jonas*"}


This means the permission thumbprint is intact even after the account was permanently deleted which is a mystery. Now to get rid of this, we can use this command below. I tried several other approaches from various Microsoft articles and forum posts but none of them worked but the following.

Get-EXOMailboxFolderPermission "<\calendar>" | where {$_.user.tostring() -like "<FirstName Last Name>*"} | Remove-MailboxFolderPermission -Confirm:$False

After running that with no errors/warnings. I ran Get command again to verify if it really was a success. And Yes ! Nothing returned, which means the permissions are now cleared for this abandoned identity of ‘Marie Jonas’.


Allowed it a couple of hours, her name disappeared from the calendar invites as well.

Get-EXOMailboxFolderPermission "<\calendar>" | where {$_.user.tostring() -like "<FirstName Last Name>*"} | Remove-MailboxFolderPermission -Confirm:$False

Enable Microsoft Whiteboard for Teams

Whiteboard in Teams is powered by Whiteboard for the web and this is a very useful feature for collaborating in group meetings. A shared canvas space allows meeting participants to collaborate. In Office 365, Whiteboard feature is enabled by default unless you disabled it manually (mostly customers disable it due to data residency concerns).

Microsoft Note: The ability to start a new whiteboard is currently limited to the Microsoft Teams clients on Windows 10, macOS, and for the web. The Teams apps for iOS and Android cannot initiate sharing a whiteboard, but they can collaborate once a whiteboard is shared.

Now let’s get this configured. Login to Office 365 Admin center using admin credentials and type ‘Whiteboard’ in the global search field. You will get the Whiteboard global settings option in a search result dropdown.


Check the ‘Turn on’’ tick box to enable it globally in your Tenancy. Diagnostic data collection by Microsoft is disclosed via three options here.


Connected experiences and sharing from Surface Hub are two optional settings depending on the organizational requirements. Finally hit ‘Save’ to complete it.


Now the global setting is enabled, we need to ensure the Whiteboard capability is also enabled in the Meeting policies. If you have multiple policies, make sure this is enabled for all of them to affect it to the desired target audiences.

From the Teams admin center, navigate to Meetings –> Meeting policies


Then click on the desired policy (in my case, the ‘Default’ as it affects to all users)


Toggle the ‘Allow Whiteboard’ switch to ‘On’ state to enable it and hit ‘Save’


Notes: This might take a couple of ours to reflect to all users (in my case it took 7+ hours).

Testing the feature.

  1. Now to try this out, you can create a test meeting with another user and ensure the Whiteboard is appearing once ‘Share’ option is clicked.


  1. Also, if you login to, you should be able to see the ‘Whiteboard’ App under the Apps list.




If you still don’t see the feature in Teams meetings, try to toggle ‘Off’ the Whiteboard feature from Teams meeting policy. Then turn in it on again and try it in a couple of hours.

Removing orphaned OneDrive secondary site collection admins

This is a scenario where, the user was deleted from Azure AD months ago but the OneDrive secondary site collection administrator permission assignments (OneDrive secondary admin) were intact as a thumbprints. This target account  supposed to be a service account utilized during a file server migration project and apparently assigned with OneDrive secondary site collection admin permission across all users in the tenancy.

Screenshot 2020-11-29 002255

The generic SharePoint Online commands did not do the job because “The user account does not exists in the AD” hence the identity validation fails at the first place. The OneDrive admin UI will do the job for a single OneDrive account but doesn’t help much in bulk operation scenarios like the one I dealt with.

Workaround: To remove this I used SharePoint PnP PowerShell command which was the only way around it.

Add yourself first in to one of the site collections (OneDrive accounts) before running the command so that you can verify the status ‘before’ and the result ‘after’.

For a single site collection (OneDrive Personal site in this case), run PowerShell as admin and execute these lines after customizing with your tenant, URL and user details. For this case, we will be using ‘Span ID’ to point to the abandoned account which usually goes as follows i:0#.f|membership|

#Config Variables - Customize this to match yours 
$SiteURL = ""
#Connect to PnP Online Service MFA
Connect-PnPOnline -Url $SiteURL -UseWebLogin
#sharepoint online powershell delete user from site collection
Remove-PnPUser -Identity $UserID -Force

If your result is similar to below, the command has done its job ! now go check that permission box and you should not see that account anymore.

Screenshot 2020-11-29 001807

Error when accessing Exchange Online classic Admin Center (EAC): 403 Access denied :(

We have been pulling our hair out for several days due to this issue. Office 365 Exchange admin center gives the following error whereas the new admin center worked well.

when you click that “Exchange” blade from the Office 365 admin center, it usually takes you to the classic Admin center which we still need for some functions that new Admin center doesn’t have.



After lots of struggle, we managed to figure out the Root cause and reported to Microsoft through an incident.

Root cause: Group based access assignments in Privileged Identity Management.


Workaround: We had assigned Azure AD Roles such as Global Administrator, Exchange Administrator via Group based PIM which did not work properly with classic EAC. Assigning Direct permissions fixed this and we managed to open the classic console immediately, right after the direct assignment. If you are facing the same, try to get rid of “Group Assignments” for Exchange Admins at least for the time being and go for “Direct Assignments

Official reference: 


I will update this post up-on Microsoft’ support responses.

Renew Apple MDM Push Certificate in Microsoft Endpoint Manager (Intune)

Apple MDM Push certificate is the key element for Microsoft EndPoint Manager to manage iOS/iPadOS and macOS devices in the MEM portal. After you add the certificate to EndPoint Manager, your users can enroll their devices using: The Company Portal app or Apple’s bulk enrollment methods such as the Device Enrollment Program (a.k.a DEP), Apple School Manager, or Apple Configurator.


This renewal is crucial:  Ensure that you take necessary actions before the expiry date as revoking or allowing this certificate to expire will require existing devices to be re-enrolled with a new push certificate.

Prerequisites for renewal:

  1. Apple Identity portal account (mostly different from the Apple ID) which was used to setup the integration for your organization. –
  2. MFA code (sends to the device registered for MFA under above account)

  3. Appropriate access to MEM (Microsoft Endpoint Manager a.k.a Intune portal) – 

First we need to sign-in to MEM portal using your admin credentials copy paste this link and sign in 

Navigate to Devices blade from the left panel and go to Apple iOS/iPadOS enrolment section as shown below and then click on ‘apple MDM Push Certificate’ widget


From the screen popped up, simply click on download CSR file on the 2nd option. Save it to a secure/temporarily location as we will delete this after the renewal.


Let’s now switch in to Apple Identity portal. This is where you need the original credentials which was used to setup the integration with Intune. Login from that account to this site –


You can avoid MFA using other options but this may not be the same in your case. Hence make sure you have the device associated to the account to receive the MFA code. Hit ‘Continue“’ to enter the code or go to ‘other options’ to avoid it.


Highly recommended to associate a mobile device for MFA if you haven’t already, or, chose ‘don’t upgrade’ option to avoid it.


Once logged in, you will see all your certificates listed with the expiry date stated.


That little ‘i” button will show you more details of each certificate if you have multiple (mostly used for different tenancies under a single account). Serial Number is the key to identity which is which from the Intune portal. Ensure that you are renewing the correct certificate by cross-checking the Serial No here againts Intune. Once confirmed, simply click on that ‘Renew” button above and you should see a new dialog box prompting.


Add a note to indicate who renew it which might be useful in a organization this will be done by another person next year.

And now choose the CSR file you downloaded from Intune and hit ‘Upload’


That’s it and you can see the green tick indicates everything went well. Simply download the certificate and store in the same secure location you store CSR previously.


You should see the new expiry date for this certificate now.


Let’s head back to MEM (Intune) portal now and upload the new certificate file there. You should also provide the original Apple ID which was used to create the MDM push cert. Once done, hit ‘Upload’ button.


That’s about it and now you will see a green status prompts indicates it went well.


Certificate should now be valid for another year !


Outlook Error: Unable to convert a generic Outlook meeting to a Teams meeting (online meeting)

Article Updated: This issue is now resolved

Due to the popular demand, Microsoft has re-deployed this feature on 14th September 2020. If you restart the Outlook, Teams clients and try to convert a occurrence now, you should be able to do so.

This is one appointment in a series, To make it an online meeting, open the meeting series and try again


Did you get this error just out of the blue in Outlook as well ? – If so, this is an ongoing issue with Outlook clients and you are not the only one impacted, and, not everyone impacted either. Recurring meeting in Outlook had the ability to edit one occurrence out of the series and we could convert these generic meetings in to Teams meetings (online meeting) until last week 14-08-2020). However this has somehow changed for some customers probably due to an Outlook/Teams update (not yet confirmed).

In my case, the following version of Outlook 2016 had the issue (and it’s not the only version impacted)


This may not be one of those common features used by majority but, it is indeed an important feature for those who are having busy calendars to manage.


Usually when you try to edit an single occurrence in a series.


It prompts you to choose a one or the entire series. The following steps are captured from my device as it seems not impacted.


The problem starts when you click on “Teams Meeting” icon to convert the meeting to a Teams meeting.


This is how it supposed to look like when it converted. You can simply send the update and the generic meeting will become a “Teams Meeting” and the meeting details will be inserted to the bottom of the screen.


So far I have tried the following but nothing made any difference.

  1. Clear Outlook cache and restart Outlook and PC
  2. Clear teams cache and restart
  3. Disable and enable Teams Add-in for Outlook

Workaround: (this is verified to be working): There is an alternative way of changing meetings using OWA for now. I truly understand this is frustrating but until Microsoft come back to us, perhaps Mary can use this workaround from Outlook Online ? (Web version from )

Workaround: Outlook on the web is the only workaround as of now. It works well on OWA but if you have shared calendars it may not be the best option. To test it out follow these steps:

From outlook web, go to Calendar tab à from the desired series of events, double click on one of the occurrence in the series


And Edit “This Event”


Go to “More options”


And toggle the “Teams Meeting” switch next to room location


Then Save it. You should be able to see this occurrence has now set to a Teams Meeting.


There are many who impacted as per this forum post and keeps growing. If you are facing the issue as well, just post a comment there  –

I am currently working with a Microsoft support engineer to engage the backend team and will keep this post updated as soon as I have an update. If you have faced it too or have found a fix, please reach out to me on and share the ideas !!

Update: Due to the popular demand, Microsoft has re-deployed this feature on 14th September 2020. If you restart the Outlook, Teams clients and try to convert a occurrence now, you should be able to do so.

Transfer ownership of a PowerApp using PowerShell

    PowerApps administration capabilities have considerably evolved from where it was and now we can easily transfer the ownership of a specific App using a simple PowerShell command. This article will cover that specific task.


    However, If you look at the latest Power Platform Admin center ( you’ll figure out there’s nothing much we could do there as admins, so PowerShell comes again for the rescue.


    PowerApps offers two separate PowerShell packages for Creators (a.k.a Makers) and Administrators respectively. Before you can do anything, you need this Admin module installed in your machine.

    you can download the NUGPKG manually from the first link, or run the command below to install it directly.

Install-Module -Name Microsoft.PowerApps.Administration.PowerShell -RequiredVersion 2.0.1

Once you have the module installed, the following command will give you an idea of the number of apps created in your environment. This is important so that you can standardize the permissions and accessibility for all your Apps via proper governance.

Before we begin, here’s the first command to login to PowerApp service. Run PowerShell as admin and then execute this.


This command will list-down all the apps in your environment with basic information for you to understand the App Name, Display Name Current Ownership etc..


To retrieve the current permissions for a specific PowerApp:

Get-AdminPowerAppRoleAssignment -AppName <APP ID>

This will list down the deep down information of a specific app including all assigned permissions for that particular app.


So now that we have all the information, to change ownership, we can either run this simple command and input the details as prompted, or use the full command below. To run this, ensure that you login from the new owner.


If you get this error (Conflict) it means that the app is opened and being edited. Close all the session for this app and try to execute the command again.


This is the full command with all the parameters and inputs are predefined. The new Owner must run this command as it uses the current logged in user to execute the change.

Set-AdminPowerAppOwner -AppName '895a38f1-f3c3-4cb6-a2d4-64b199badb3d' -AppOwner $Global:CurrentSession.userId -EnvironmentName 'Default-f50d5133-e13c-4359-85f6-ef76484f4c32'


That should easily run and change the new Owner. However, the previous owner will still remain as a normal user which allows the new Owner to decide whether to keep remove. As new owner can use the User Interface to manage the app, he can simply manage the permission there.



Determine On-Premise and Cloud Mailbox Users

During an Exchange online management activity for one of our enterprise clients, I had to determine which mailboxes are on cloud and which ones still resides on-premise. After going through several PS commands, I had to come up with a customized basic script to get this done neatly. This script will run against Office 365 and check for the following.

Get licensed users, fetch Display Name, UPN and IsLicensed properties and format the output then export the result to an CSV file.

Connect to Exchange online PowerShell using Connect-ExchangeOnline and then run the following  after customizing the output path to suit your environment.

Get-MsolUser -MaxResults 50000 |
Where-Object isLicensed -eq $true |
Select-Object -Property DisplayName, UserPrincipalName, isLicensed,
                            switch ($_.MSExchRecipientTypeDetails) {
                                      1 {'Onprem'; break}
                                      2147483648 {'Office365'; break}
                                      default {'Unknown'}
                        }} | Export-Csv c:\Official\Tools\mailusers.csv

You can run it directly from PowerShell which would result as below if everything went well.


Or use PowerShell ISE


Result would look something similar to this.


Get-MsolUser -MaxResults 50000 |
Where-Object isLicensed -eq $true |
Select-Object -Property DisplayName, UserPrincipalName, isLicensed,
                            switch ($_.MSExchRecipientTypeDetails) {
                                      1 {'Onprem'; break}
                                      2147483648 {'Office365'; break}
                                      default {'Unknown'}
                        }} | Export-Csv c:\Official\Tools\mailusers.csv

Export All Sites, libraries and lists of a SharePoint Online Site Collection

If you remember classic SharePoint, it had that nice looking (and yet unreliable sometimes) feature called “SharePoint Site Structure” which was eventually deprecated as move & copy functions were introduced. This was very insightful to understand the site and content hierarchy across the entire SharePoint

However, let’s assume you want to review your modern day SharePoint Online hierarchy every once in a while, and make sure your sites, libraries and lists are aligning to best practices as far as the depth of the site levels? Or, you just want to know what sort of sites exist in your site collection, we still have a manual way of getting those information out using a simple PowerShell script. This may not be the best sophisticated way of getting a handy report which can probably be obtained using a 3rd party tool.

Unless its a test environment, we rarely notice any Office 365 tenant without MFA enabled, so this script is Modern-Auth friendly and supports MFA. You can generate a basic report of all sites, libraries and lists in a specific site collection by defining the site collection name and CSV path to save it.

###Function to Get Lists and Libraries of a web
Function Get-SPOSiteInventory([Microsoft.SharePoint.Client.Web]$Web)
    Write-host -f Yellow "Getting Lists and Libraries from site:" $Web.URL
    ###Get all lists and libraries
    $SiteInventory= @()
    $Lists= Get-PnPList -Web $Web
    foreach ($List in $Lists)
        $Data = new-object PSObject
        $Data | Add-member NoteProperty -Name "Site Name" -Value $Web.Title
        $Data | Add-member NoteProperty -Name "Site URL" -Value $Web.Url
        $Data | Add-member NoteProperty -Name "List Title" -Value $List.Title
        $Data | Add-member NoteProperty -Name "List URL" -Value $List.RootFolder.ServerRelativeUrl
        $Data | Add-member NoteProperty -Name "List Item Count" -Value $List.ItemCount
        $Data | Add-member NoteProperty -Name "Last Modified" -Value $List.LastItemModifiedDate
        $SiteInventory += $Data
    ###Get All Subwebs
    $SubWebs = Get-PnPSubWebs -Web $Web
    Foreach ($Web in $SubWebs)
        $SiteInventory+= Get-SPOSiteInventory -Web $Web
    Return $SiteInventory
###Config Variables
$SiteURL = ""
$CSVFile = "C:\temp\filename.csv"
###Get Credentials to connect
Try {
    #Connect to PNP Online
    Connect-PnPOnline -Url $SiteURL -UseWebLogin
    ###Get the Root Web
    $Web = Get-PnPWeb
    ###Call the function and export results to CSV file
    Get-SPOSiteInventory -Web $Web | Export-CSV $CSVFile -NoTypeInformation
Catch {
    write-host "Error: $($_.Exception.Message)" -foregroundcolor Red

As you execute it, you’ll be prompted for credentials and the report will be generated (duration might depend on the number of site collections and the weight of each)



Original script used in this scenario was published in this article of SharePoint Diary