<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Merill Fernando</title>
    <description>The latest articles on DEV Community by Merill Fernando (@merill).</description>
    <link>https://dev.to/merill</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F231526%2Fe4cbd956-8aca-4e6b-ad96-411bdd4b2b02.png</url>
      <title>DEV Community: Merill Fernando</title>
      <link>https://dev.to/merill</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/merill"/>
    <language>en</language>
    <item>
      <title>aka.ms/mgps</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Wed, 29 Sep 2021 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/aka-ms-mgps-4mj9</link>
      <guid>https://dev.to/merill/aka-ms-mgps-4mj9</guid>
      <description>&lt;p&gt;Having trouble finding the Graph PowerShell commandlet reference? I created an easy to remember shortcut at &lt;a href="https://aka.ms/mgps"&gt;aka.ms/mgps&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now you can find the reference for commands like Connect-MgGraph, Get-MgUser quickly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BTW Are you migrating your old Azure AD PowerShell scripts to the new Graph PowerShell?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;| Did you know that we also have a handy map of the commands at &lt;a href="https://docs.microsoft.com/en-au/powershell/microsoftgraph/azuread-msoline-cmdlet-map?view=graph-powershell-beta"&gt;Find Azure AD and MSOnline cmdlets in Microsoft Graph PowerShell | Microsoft Docs&lt;/a&gt; |&lt;/p&gt;

</description>
      <category>tip</category>
      <category>powershell</category>
      <category>graph</category>
      <category>azuread</category>
    </item>
    <item>
      <title>Introducing Graph Permissions Explorer</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Fri, 17 Sep 2021 11:29:24 +0000</pubDate>
      <link>https://dev.to/merill/introducing-graph-permissions-explorer-4dj9</link>
      <guid>https://dev.to/merill/introducing-graph-permissions-explorer-4dj9</guid>
      <description>&lt;p&gt;If you are a developer in the Microsoft 365 ecosystem you will be well versed with the &lt;a href="https://docs.microsoft.com/en-us/graph/api/overview?view=graph-rest-1.0"&gt;Microsoft Graph API reference docs&lt;/a&gt; and most probably know about permission scopes (eg. User.Read).&lt;/p&gt;

&lt;p&gt;The docs are an awesome resource geared towards developers and lets you navigate by APIs and view the permissions required and includes code samples.&lt;/p&gt;

&lt;p&gt;What is missing in the docs however is a view that shows the APIs and resources that are exposed by a permission.&lt;/p&gt;

&lt;p&gt;Let's say you are the Azure AD administrator or a security/compliance officer in your organisation and a developer asks for the Files.Read.All permission. &lt;/p&gt;

&lt;p&gt;Until today it's not been very easy to find this out. You would need to search by permission and then click through to each API. &lt;/p&gt;

&lt;p&gt;To solve this created the Graph Permissions Explorer. This site lets you navigate by a permission scope and view all the Graph APIs and resources for a given permission.&lt;/p&gt;

&lt;p&gt;For example here is the view for &lt;a href="https://graphpermissions.merill.net/permission/Files.Read.All.html"&gt;Files.Read.All&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Hopefully you find this site useful when working with apps in Azure Active Directory and Microsoft 365. In my next post I will show how I built the solution and set up the automation to update the site everyday as the Microsoft Graph docs are updated.&lt;/p&gt;

&lt;p&gt;Give it a try at &lt;a href="https://graphpermissions.merill.net"&gt;https://graphpermissions.merill.net&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-1435233522109792258-886" src="https://platform.twitter.com/embed/Tweet.html?id=1435233522109792258"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1435233522109792258-886');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1435233522109792258&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>graph</category>
      <category>microsoft</category>
      <category>permission</category>
      <category>azuread</category>
    </item>
    <item>
      <title>PowerShell script to generate a report on all Power BI workspaces and groups in your Microsoft 365 tenant</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Tue, 05 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/powershell-script-to-generate-a-report-on-all-power-bi-workspaces-and-groups-in-your-microsoft-365-tenant-44pc</link>
      <guid>https://dev.to/merill/powershell-script-to-generate-a-report-on-all-power-bi-workspaces-and-groups-in-your-microsoft-365-tenant-44pc</guid>
      <description>&lt;p&gt;Here’s a useful script I wrote the other day. This uses a few PowerShell modules to pull together information about all the Power BI workspaces in your Microsoft 365 tenant. This also includes the names of the Workspace/Group owners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Install-Module AzureAD
#Install-Module MicrosoftPowerBIMgmt
#Connect-PowerBIServiceAccount
#Connect-AzureAD

$workspaces = Get-PowerBIWorkspace -Scope Organization -All
$wslist = @()
foreach ($ws in $workspaces) {
    $ws
    $owners = $null
    if ($ws.State -eq 'Active') { 
        if ($ws.Type -eq 'Workspace') {
            $u = $ws.Users | Where-Object AccessRight -eq 'Admin' | Select-Object UserPrincipalName
            Write-Host $u
            $owners = $u.UserPrincipalName -join ","
        }
        elseif ($ws.Type -eq 'Group') {
            $go = Get-AzureADGroupOwner -ObjectId $ws.ID 
            $owners = $go.UserPrincipalName -join "," 
        }
    } 
    $item = [ordered] @{
        Id = $ws.ID
        Name = $ws.Name
        Type = $ws.Type
        State = $ws.State
        IsReadOnly = $ws.IsReadOnly
        IsOrphaned = $ws.IsOrphaned
        IsOnDedicatedCapacity = $ws.IsOnDedicatedCapacity
        CapacityId = $ws.CapacityId
        Owners = $owners
    }
    $u = new-object PSObject -Property $item
    $wslist += $u
}
$wslist | Export-Csv .\PowerBI-Workspaces.csv -NoTypeInformation

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tips</category>
      <category>powershell</category>
      <category>report</category>
      <category>powerbi</category>
    </item>
    <item>
      <title>Password Hash Sync and Staged Rollout - Things you need to know</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Mon, 04 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/password-hash-sync-and-staged-rollout-things-you-need-to-know-22di</link>
      <guid>https://dev.to/merill/password-hash-sync-and-staged-rollout-things-you-need-to-know-22di</guid>
      <description>&lt;p&gt;Now that Staged Rollout is out of NDA, I can finally talk about one of the projects I’ve been working on for the last twelve months.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Staged Rollout?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;How do you migrate from an on-prem identity provider to using Azure AD as the authentication provider? Before Staged Rollout was available the only option was either big-bang where you switched the entire domain from federated to managed or you had to mess with the user’s UPN and temporarily move them to a managed domain. Not very great options which basically meant it made the already difficult task an almost impossible one.&lt;/p&gt;

&lt;p&gt;Thanks to Staged Rollout you can now migrate a few users at a time to native Azure AD authentication. The end result will be as simple as adding the users to an AAD group.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Things to consider before doing a staged rollout with Password Hash Sync&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The documentation for &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-password-hash-synchronization"&gt;Password Hash Sync&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-staged-rollout"&gt;Staged Rollout&lt;/a&gt; give a good overview of what you need to do as a bare minimum, however there are many things you need to consider or might run into when implementing this in the real world. I ran into most of these when turning on Password Hash Sync (PHS) but most of the guidance is equally applicable to Pass Through Authentication (PTA) as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tighten up your Conditional Access policies
&lt;/h2&gt;

&lt;p&gt;Check your conditional access policies and make sure you’ve covered all the scenarios. At a minimum, make sure you have MFA as a requirement for any user access that comes in over the internet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Block Legacy Authentication
&lt;/h2&gt;

&lt;p&gt;You will also want to &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/block-legacy-authentication"&gt;block legacy authentication&lt;/a&gt;. If not, you have opened the door for bad guys to run brute force attacks on your user passwords. A quick note that blocking legacy authentication will not break Exchange Active Sync sign ins (even though they use a form of basic auth). You might have issues blocking legacy authentication for users that are on the LAN/VPN, especially if you have robot accounts using EWS APIs, old Outlook clients, etc. At a minimum you should set up a CA policy to block legacy auth requests coming in over the internet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dMyqavKZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-437469.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dMyqavKZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-437469.png" alt="2019-11-01-437469.png" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  UPN Analysis
&lt;/h2&gt;

&lt;p&gt;You should also do an analysis of the accounts that are being synced to Azure AD. What you might not be aware is that users having a UPN suffix (domain) that is not registered in Azure AD will end up with an @.onmicrosoft.com UPN in Azure AD.&lt;/p&gt;

&lt;p&gt;In a federated world this might have been enough to block these users from signing into Azure AD but that’s not true anymore once you sync the hashes. Users can type in their cloud UPN (e.g. &lt;a href="mailto:name@mytenant.onmicrosoft.com"&gt;name@mytenant.onmicrosoft.com&lt;/a&gt;) and on-prem password and be signed into Azure AD.&lt;/p&gt;

&lt;p&gt;There are a few ways you can go about address this, a combination of registering the domain in AAD, dynamic groups and conditional access will help you manage/block these accounts if they are not supposed to sign into Azure AD.&lt;/p&gt;

&lt;h2&gt;
  
  
  Password Expiry
&lt;/h2&gt;

&lt;p&gt;This is a big one and has an impact on user experience. By default the Azure AD password is set to ‘Never Expire’. The result is that when a user’s password has expired on-prem they will still be able to sign into Azure AD with the old password.&lt;/p&gt;

&lt;p&gt;The issue stems from the fact that password expiry status is not a true/false flag that’s stored against the user in Active Directory. Instead it’s a calculated field based on the pwdLastSet attribute of the user + the password expiry policy that applied to the user. This is why there is no such attribute to configure in AAD Connect.&lt;/p&gt;

&lt;p&gt;The good news is that the story is a lot better now (Nov 2019) than what is was a few months ago. What you need to do now is create a password policy in Azure AD that matches your on-prem policy (eg 90 day expiry). Then you need to do two things.&lt;/p&gt;

&lt;p&gt;The first is to turn on &lt;em&gt;EnforceCloudPasswordPolicyForPasswordSyncedUsers&lt;/em&gt; in AAD. This will ensure that going forward whenever a user resets the password, AAD Connect will set that user’s password policy from &lt;em&gt;DisablePasswordExpiration&lt;/em&gt; to &lt;em&gt;None&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set-MsolDirSyncFeature -Feature EnforceCloudPasswordPolicyForPasswordSyncedUsers  $true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However this is not going to go and fix each user’s account. To do that you need to set it for each individual user like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Set-AzureADUser -ObjectID &amp;lt;User Object ID&amp;gt; -PasswordPolicies "DisablePasswordExpiration"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for the catch. If you try this on a federated user account, AAD will complain its a synced account and throw the error “Unable to update the specified properties for on-premises mastered Directory Sync objects or objects”. Nothing that some simple PowerShell can’t solve. All you have to do is switch the user’s UPN to a managed domain, update the policy and switch the UPN back to the federated one. There is no impact to the user (they won’t see any sign in prompts or weird behaviour). Remember to use the user’s GUID as the ObjectId instead of the UPN since we are swapping the UPNs around. I also added the .x@ to the temporary managedUpn to avoid conflicts where some users&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function SetPasswordPolicyNone($objectId, $upn)
{
    $upnSplit = $upn.Split("@")
    $tenantDomain = "&amp;lt;mytenantname&amp;gt;.onmicrosoft.com"

    $managedUpn = $upnSplit[0] + ".x@" + $tenantDomain
    # Change UPN to managed domain
    Write-Host "Update Policy: Updating " $upn " to " $managedUpn
    Set-AzureADUser -ObjectId $objectId -UserPrincipalName $managedUpn
    # Update the password policy
    Set-AzureADUser -ObjectId $objectId -PasswordPolicies DisablePasswordExpiration
    # Change UPN back to the federated domain
    Set-AzureADUser -ObjectId $objectId -UserPrincipalName $upn
}

$users = Import-Csv .\users.csv
foreach ($user in $users){
    Write-Host $user.userPrincipalName
    SetPasswordPolicyNone -upn $user.userPrincipalName -objectId $user.ObjectId
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now for some notes/warnings&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You should do some reporting to understand the current state of the user’s password policies. This article has some helpful scripts to do this &lt;a href="https://docs.microsoft.com/en-us/office365/admin/add-users/set-password-to-never-expire?view=o365-worldwide"&gt;https://docs.microsoft.com/en-us/office365/admin/add-users/set-password-to-never-expire?view=o365-worldwide&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have some users or types of users on-prem that don’t have a password expiry policy you will need to make sure you don’t set their password policy to None. If you do it they will be prompted with the ‘Change Password’ flow in Azure AD even though their password has not expired on-prem.&lt;/p&gt;

&lt;h2&gt;
  
  
  CA Policy to Lockdown access to the Security info page
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/user-help/security-info-setup-auth-app"&gt;Security Info&lt;/a&gt; page where your users can set up the MFA options is well protected by Microsoft once the user has set up an MFA option. Each time they access this page they will be prompted to perform an MFA.&lt;/p&gt;

&lt;p&gt;However, the first time you add the user to the MFA group they will be able to access this page with just the username and password and sometimes this could be over the internet. My recommendation is to secure this page so that it is only accessible from a managed device (ie IsCompliant or Hybrid Joined) and to lock down un-managed devices to the LAN.&lt;/p&gt;

&lt;p&gt;This way you can prevent intruders hijacking a user’s account and setting up MFA between the window where you add them to PHS and the user first logging in. Steps to turn this on can be found here &lt;a href="https://docs.microsoft.com/bs-latn-ba/azure/active-directory/authentication/howto-registration-mfa-sspr-combined#conditional-access-policies-for-combined-registration"&gt;https://docs.microsoft.com/bs-latn-ba/azure/active-directory/authentication/howto-registration-mfa-sspr-combined#conditional-access-policies-for-combined-registration&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tcOn9D-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-842606.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tcOn9D-a--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-842606.png" alt="2019-11-01-842606.png" width="800" height="540"&gt;&lt;/a&gt; &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJuAE7l8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-718026.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJuAE7l8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-11-01-718026.png" alt="2019-11-01-718026.png" width="800" height="815"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  MFA configuration for end users
&lt;/h2&gt;

&lt;p&gt;This is more about end user comms and planning. You need to figure out how you guide your users through the process of setting up MFA.&lt;/p&gt;

&lt;p&gt;Microsoft has a good guide to set this up over &lt;a href="https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-getstarted"&gt;https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-getstarted&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You get the best end user experience if you are licenced for Identity Protection (currently AAD P2) since it guides the user through the MFA set up process as part of their initial sign in.&lt;/p&gt;

&lt;p&gt;If you are not licenced you will need to roll your own and come up with a plan to migrate users. If you don’t do anything then your users will be hit with the MFA set up process the first time a CA policy checks for it. Unfortunately for a vast majority of users this could be when they are signing in from a mobile device. Users are going to get stuck real fast on the mobile when it asks them to scan the QR code (displayed on the mobile phone) with the phone itself. To avoid this deadlock and very bad user experience you need to send out comms early to users and make sure they have set up their MFA.&lt;/p&gt;

&lt;p&gt;Unfortunately, reporting on the MFA options set up by the user is still locked down to the old MSOL PowerShell module.&lt;/p&gt;

&lt;p&gt;This script will help create a report for you.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Remove-Item $outputCsvPath
$result=@() 
$inputUserCsv | ForEach-Object {
    Write-Host $_.UserPrincipalName
    $user = Get-Msoluser -UserPrincipalName $_.UserPrincipalName
    $result = New-Object PSObject -property @{         
        UserPrincipalName = $user.UserPrincipalName
        UserName = $user.DisplayName
        MFADefault = ($user.StrongAuthenticationMethods | Where-Object IsDefault -eq True).MethodType
        MFAMethods = ($user.StrongAuthenticationMethods | ForEach-Object { $_.MethodType }) -join ", "
        ImmutableId = $user.ImmutableId
    }
    $result | Export-CSV $outputCsvPath -NoTypeInformation -Append
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other titbits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Sites with domain hint
&lt;/h3&gt;

&lt;p&gt;Microsoft has a warning about sites with domain hint. Yes they will still redirect the user to the federated sign in page, however most users will rarely see this page. If they have a PRT token or they’ve signed in before it will take them to the cloud authentication flow. The rare occurrence where they might see this is if they are on a mobile device that doesn’t have single sign on (eg. Safari).&lt;/p&gt;

&lt;h3&gt;
  
  
  Do I need to implement Seamless SSO?
&lt;/h3&gt;

&lt;p&gt;If all the users you are migrating are on Windows 10 and AAD Hybrid Joined then Seamless Sign On does not add any benefit. You can skip it altogether. However if you are migrating Windows 7 users to PHS then yes you should set up Seamless SSO&lt;/p&gt;

&lt;h3&gt;
  
  
  What should I set the Active Directory Service Connection Point to?
&lt;/h3&gt;

&lt;p&gt;It’s better to have the SCP point to the .onmicrosoft.com domain instead of your custom domain to avoid DNS and proxy issues related to your tenant.&lt;/p&gt;

</description>
      <category>azuread</category>
      <category>conditionalaccess</category>
    </item>
    <item>
      <title>Intune Custom Notifications</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Tue, 06 Aug 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/intune-custom-notifications-2cg0</link>
      <guid>https://dev.to/merill/intune-custom-notifications-2cg0</guid>
      <description>&lt;p&gt;Google recently released the details of some &lt;a href="https://www.theverge.com/2019/7/30/20746827/apple-ios-security-flaw-imessage-google-project-zero"&gt;major iOS security flaws&lt;/a&gt;. The good thing is that Apple already released the patch for five of them in the iOS 12.4 update a few weeks ago. The bad thing is that more than 90% of our corporate user base did not have the update applied.&lt;/p&gt;

&lt;p&gt;This is a brilliant opportunity to use Intune’s new &lt;a href="https://docs.microsoft.com/en-us/intune/custom-notifications"&gt;Custom Notifications&lt;/a&gt; feature to target and notify just the devices that haven’t yet updated to the latest version.&lt;/p&gt;

&lt;p&gt;To do this you start by creating a dynamic group in Azure AD using the ‘Dynamic Devices’ option. The query for the group is fairly simple and goes like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(device.deviceOSType -in ["iOS","IPhone", "IPad", "IPod"]) -and (device.deviceOSVersion -ne "12.4")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SUj5nwP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-08-06_22h04_08.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SUj5nwP---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-08-06_22h04_08.png" alt="Dynamic membership rule" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Wait for the group to be populated (might take anywhere from a few minutes to an hour or more depending on how many devices you have in your Azure AD).&lt;/p&gt;

&lt;p&gt;Next go to Intune &amp;gt; Devices &amp;gt; Send custom notifications to compose and send out the notifications to your users. You can keep sending this everyday and since this is just a dynamic group it will target the remaining devices that haven’t been updated.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yb4D7N3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-08-06_22h09_49.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yb4D7N3y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://merill.net/assets/2019-08-06_22h09_49.png" alt="Intune custom notifications" width="800" height="298"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Remove ms-outlook urls from your Google Contacts</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Sun, 21 Jul 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/remove-ms-outlook-urls-from-your-google-contacts-18kh</link>
      <guid>https://dev.to/merill/remove-ms-outlook-urls-from-your-google-contacts-18kh</guid>
      <description>&lt;p&gt;Microsoft Outlook for mobile is one of the best, if not the best mobile mail client out there. However things can get a bit messy if you use the Save Contacts feature on iOS and also have a third party contact sync app keeping iCloud and GMail contacts in sync. I use the awesome &lt;a href="https://apps.apple.com/au/app/contacts-sync-for-google-gmail/id454390333"&gt;Contacts Sync for Google&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you wind up with 100s of contacts having weird urls like ‘ms-outlook://people/’ or notes filled with the text ‘This contact is read-only. To make changes, tap the link above to edit in Outlook.’ then your in a bit of a bind especially if you have a bit of OCD like me.&lt;/p&gt;

&lt;p&gt;Have no fear &lt;a href="https://script.google.com"&gt;Google Script&lt;/a&gt; is here to rescue us. A simple hack and five minutes later you can enjoy a fully cleaned up contacts list without all the Outlook junk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;outlookJunkNote&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This contact is read-only. To make changes, tap the link above to edit in Outlook.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ContactsApp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getContacts&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cnt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="c1"&gt;//Clean outlook:// urls&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getUrls&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;getLabel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Outlook&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;deleteUrlField&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;//Clean outlook notes&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getNotes&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;indexOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outlookJunkNote&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;regex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;RegExp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;outlookJunkNote&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;g&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;cleanNotes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;notes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nx"&gt;cnt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setNotes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cleanNotes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I have published the script over at Google Script so you can simply save it your account and run it to clean up your Google contacts. &lt;a href="https://script.google.com/d/17QekwOHQwWAbELmO2xgiHnrRLkzMyaXo-1Fe2L_cBhGitMhsXJvL3asF/edit?usp=sharing"&gt;Remove Outlook Junk Script&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Update the Azure AD password of a federated user</title>
      <dc:creator>Merill Fernando</dc:creator>
      <pubDate>Sun, 16 Jun 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/merill/update-the-azure-ad-password-of-a-federated-user-p0e</link>
      <guid>https://dev.to/merill/update-the-azure-ad-password-of-a-federated-user-p0e</guid>
      <description>&lt;p&gt;There are times you need to update the Azure AD password of a user that’s synced from Active Directory. However running either Set-AzureADUserPassword or Set-MsolUserPassword fails with one of the following errors.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set-MsolUserPassword : You cannot reset a password for a federated user.&lt;/li&gt;
&lt;li&gt;Set-AzureADUserPassword : Error occurred while executing SetUser Code: Request_BadRequest&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a simple hack to workaround this limitation. All you need to do is temporarily change the user’s UserPrincipalName to that of a managed domain, update the password and then change the UserPrincipalName back to the federated domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Change UPN to managed domain&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-AzureADUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ObjectId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xxxxx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UserPrincipalName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;domain.onmicrosoft.com&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Update the password&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-AzureADUserPassword&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ObjectId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xxxxx&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Change UPN back to the federated domain&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Set-AzureADUser&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-ObjectId&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;xxxxx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-UserPrincipalName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="err"&gt;@&lt;/span&gt;&lt;span class="nx"&gt;domain.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it. The user will eventually be signed out of the apps they are in and will have to re-sign in again.&lt;/p&gt;

&lt;p&gt;The new password will remain until the user changes their password on-prem in Active Directory which will then sync across to Azure Active Directory.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
