Avoid the Oops: Proactively Monitor Entra Application Secret Expirations with Automation

In the fast-paced world of enterprise IT, even small oversights can lead to major disruptions. One of those easily overlooked — yet critically important — tasks is monitoring Microsoft Entra (formerly Azure AD) application secret expirations.

Imagine this: everything is running smoothly in production until — bam! — an app suddenly fails because its secret expired. No alerts, no heads-up, just user complaints and a flurry of incident reports. Sound familiar?

Why Monitoring Application Secrets Matters

At its core, application secrets are credentials that apps use to authenticate themselves with Microsoft Entra ID. But unlike passwords, secrets come with an expiration date. If they aren’t renewed in time, the app’s authentication fails — and with it, the business processes it supports.

For organizations running dozens (or hundreds) of app registrations, staying ahead of these expirations is not optional — it’s essential. Secrets that silently expire can grind systems to a halt, disrupt integrations, and worst of all, trigger security incidents or SLA breaches.

A Common Problem in the Real World

When I first set out to automate monitoring for app secret expirations, I assumed it’d be simple. A few PowerShell lines here, an API call there, maybe some Logic App magic… problem solved, right?

Well, not quite.

Most of the tutorials and blog posts I found focused solely on fetching the expiration date of secrets — they showed how to query the data, but not how to operationalize it. I wanted something that would proactively notify the right people before things went south.

Eventually, I came across a helpful post on Microsoft Tech Community:
Use Azure Logic Apps to Notify of Pending AAD Application Client Secrets and Certificate Expirations

It was a solid foundation. The Logic App would periodically check secrets and send an email notification if one was nearing expiration.

But then… I hit a snag.

If an application had multiple owners — which, in the enterprise world, is very common — the Logic App would only notify the first listed owner. Everyone else? Left in the dark.

Not ideal. Especially when that one person is on PTO, has left the company, or, let’s be honest, just ignores emails from IT.

So, I decided to roll up my sleeves and build a PowerShell-based solution that:

  • Queries all app registrations
  • Checks for secrets or certificates nearing expiration
  • Looks up all owners (not just the first one)
  • Sends clear, actionable email notifications to each owner

Why Automate This? Let’s Talk Benefits

Here’s why every enterprise IT team should care about automating secret expiration alerts:

  • Proactive Security – Timely notifications help you spot secrets that are about to expire — before they become a security risk or business disruption. It’s the difference between being reactive and being prepared.
  • Reduced Downtime – Missed secret expirations lead to failed authentications, which means broken apps. Proactive alerts buy you time to renew secrets and avoid outages.
  • No More Manual Tracking – Maintaining a spreadsheet of app secrets? Been there. Done that. Automation means less grunt work and fewer mistakes.
  • Smart Notifications – By targeting all app owners — not just the first in line — you’re covering your bases. Even if someone’s on vacation, someone else sees the alert and can take action.

What This Script Does

  • Authenticates to Microsoft Graph with the required permissions
  • Queries all Entra app registrations
  • Identifies app secrets and certificates that are expiring within a defined threshold (e.g., 30 days)
  • Pulls all assigned owners for each app
  • Sends an email notification to each owner with details about the impending expiration
  • Sends an email notification to an administrator email, a distribution group or a shared mailbox containing a list of all secrets that are expiring

Use task scheduler to run this script from your on-premise environment. You can securely store the credentials to be used in the PowerShell script using the SecretManagement module. I’ve covered this in detail in an earlier post here. The ideal and preferred method is to use Azure automation account which is much more easier and secure, which I will cover in a future post.

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Application.Read.All","User.Read.All","AppRoleAssignment.Read.All"

# Set default value for the number of days until expiration
$DaysUntilExpiration = 30

# Email configuration
$SmtpServer = "smtp.yourdomain.com"
$From = "alerts@yourdomain.com"
$DefaultEmail = "entra_app_cert_notif@yourdomain.com"

# Function to send email
function Send-ExpirationAlert {
    param (
        [string]$To,
        [string]$FirstName,
        [string]$AppName,
        [string]$SecretOrCertName,
        [string]$SecretOrCertId,
        [datetime]$EndDate
    )

    $Subject = "Alert: Secret or Certificate Expiration Notice for $AppName"
    $Body = @"
<html>
<body>
<p>Hello $FirstName,</p>
<p>This is a notification that the secret or certificate named '$SecretOrCertName' for the application '$AppName' will expire on $($EndDate.ToShortDateString()).</p>
<p>Please contact Progressrail's Entra (previously known as Azure AD) Administrators and take the necessary actions to renew or replace the secret or certificate before it expires.</p>
<p>Details to provide the administrators:</p>
<ul>
<li>Application Name: $AppName</li>
<li>Secret or Certificate Name: $SecretOrCertName</li>
<li>Secret or Certificate ID: $SecretOrCertId</li>
<li>Expiration Date: $($EndDate.ToShortDateString())</li>
</ul>
<p><span style="color: red;">Please do not reply to this email, this mailbox is not monitored.</span></p>
<p>Thank you,<br>Your IT Team</p>
</body>
</html>
"@

    Send-MailMessage -SmtpServer $SmtpServer -From $From -To $To -Subject $Subject -Body $Body -BodyAsHtml
}

# Function to send summary email
function Send-SummaryEmail {
    param (
        [string]$To,
        [string]$Body
    )

    $Subject = "Summary: Secrets and Certificates Expiring in the Next 30 Days"
    Send-MailMessage -SmtpServer $SmtpServer -From $From -To $To -Subject $Subject -Body $Body -BodyAsHtml
}

# Get the current date
$Now = Get-Date

# Query all applications
$Applications = Get-MgApplication -All

# Initialize a variable to store the summary of expiring secrets and certificates
$SummaryBody = @"
<html>
<body>
<p>Hello,</p>
<p>The following secrets and certificates are expiring in the next 30 days:</p>
<table border="1">
<tr>
<th>Application Name</th>
<th>Secret or Certificate Name</th>
<th>Secret or Certificate ID</th>
<th>Expiration Date</th>
</tr>
"@

# Process each application
foreach ($App in $Applications) {
    $AppName = $App.DisplayName
    $AppID   = $App.Id
    $ApplID  = $App.AppId

    $AppCreds = Get-MgApplication -ApplicationId $AppID
    $Secrets = $AppCreds.PasswordCredentials
    $Certs   = $AppCreds.KeyCredentials

    foreach ($Secret in $Secrets) {
        $StartDate  = $Secret.StartDateTime
        $EndDate    = $Secret.EndDateTime
        $SecretName = $Secret.DisplayName
        $SecretId   = $Secret.KeyId

        $Owners = Get-MgApplicationOwner -ApplicationId $App.Id

        if ($Owners.Count -eq 0) {
            # No owner information, send to default email
            $FirstName = "Admin"
            Send-ExpirationAlert -To $DefaultEmail -FirstName $FirstName -AppName $AppName -SecretOrCertName $SecretName -SecretOrCertId $SecretId -EndDate $EndDate
        } else {
            foreach ($Owner in $Owners) {
                $Username = $Owner.AdditionalProperties.userPrincipalName
                $OwnerID  = $Owner.Id

                if ($null -eq $Username) {
                    $Username = $Owner.AdditionalProperties.displayName
                    if ($null -eq $Username) {
                        $Username = '**<This is an Application>**'
                    }
                }

                # Extract first name from givenName or user principal name
                $FirstName = $Owner.AdditionalProperties.givenName
                if ($null -eq $FirstName -or $FirstName -eq '') {
                    $FirstName = $Username.Split('@')[0].Split('.')[0]
                }

                $RemainingDaysCount = ($EndDate - $Now).Days

                if ($RemainingDaysCount -le $DaysUntilExpiration -and $RemainingDaysCount -ge 0) {
                    if ($Username -ne '<<No Owner>>') {
                        Send-ExpirationAlert -To $Username -FirstName $FirstName -AppName $AppName -SecretOrCertName $SecretName -SecretOrCertId $SecretId -EndDate $EndDate
                    }
                }
            }
        }

        # Add to summary if expiring in the next 30 days
        if ($RemainingDaysCount -le $DaysUntilExpiration -and $RemainingDaysCount -ge 0) {
            $SummaryBody += @"
<tr>
<td>$AppName</td>
<td>$SecretName</td>
<td>$SecretId</td>
<td>$($EndDate.ToShortDateString())</td>
</tr>
"@
        }
    }

    foreach ($Cert in $Certs) {
        $StartDate  = $Cert.StartDateTime
        $EndDate    = $Cert.EndDateTime
        $CertName   = $Cert.DisplayName
        $CertId     = $Cert.KeyId

        $Owners = Get-MgApplicationOwner -ApplicationId $App.Id

        if ($Owners.Count -eq 0) {
            # No owner information, send to default email
            $FirstName = "Admin"
            Send-ExpirationAlert -To $DefaultEmail -FirstName $FirstName -AppName $AppName -SecretOrCertName $CertName -SecretOrCertId $CertId -EndDate $EndDate
        } else {
            foreach ($Owner in $Owners) {
                $Username = $Owner.AdditionalProperties.userPrincipalName
                $OwnerID  = $Owner.Id

                if ($null -eq $Username) {
                    $Username = $Owner.AdditionalProperties.displayName
                    if ($null -eq $Username) {
                        $Username = '**<This is an Application>**'
                    }
                }

                # Extract first name from givenName or user principal name
                $FirstName = $Owner.AdditionalProperties.givenName
                if ($null -eq $FirstName -or $FirstName -eq '') {
                    $FirstName = $Username.Split('@')[0].Split('.')[0]
                }

                $RemainingDaysCount = ($EndDate - $Now).Days

                if ($RemainingDaysCount -le $DaysUntilExpiration -and $RemainingDaysCount -ge 0) {
                    if ($Username -ne '<<No Owner>>') {
                        Send-ExpirationAlert -To $Username -FirstName $FirstName -AppName $AppName -SecretOrCertName $CertName -SecretOrCertId $CertId -EndDate $EndDate
                    }
                }
            }
        }

        # Add to summary if expiring in the next 30 days
        if ($RemainingDaysCount -le $DaysUntilExpiration -and $RemainingDaysCount -ge 0) {
            $SummaryBody += @"
<tr>
<td>$AppName</td>
<td>$CertName</td>
<td>$CertId</td>
<td>$($EndDate.ToShortDateString())</td>
</tr>
"@
        }
    }
}

# Close the HTML table and body
$SummaryBody += @"
</table>
<p>Thank you,<br>Your IT Team</p>
</body>
</html>
"@

# Send the summary email
Send-SummaryEmail -To $DefaultEmail -Body $SummaryBody

Monitoring Entra application secret expirations may not be the flashiest part of your security strategy, but it’s one of the most crucial. It’s also one of those tasks that’s easy to automate, but costly to ignore.

If you’re currently relying on manual processes — or using a Logic App that only pings one owner — consider leveling up your approach. A bit of PowerShell and planning can save you hours of downtime, reduce late-night incident calls, and help keep your environment secure.

Thank you for stopping by. ✌️

Azure AD – Improve Authenticator Notifications with Additional Context and Number Matching

As I have covered several times before, disabling basic authentication in one of the best things you can do in your O365 tenant for security.

MFA helps protect user’s account and prevents attacks. It is not perfect by any means but it is being improved. I’m a big fan of the Authenticator App. I try not to use the SMS or voice call options. Whenever I get a chance I always advocate the users I work with, to stick with the App. If your organization is yet to roll out MFA, it is time to take a hard look and make some drastic changes.

Microsoft in their November 18 Azure AD Identity blog revealed two new features for the Authenticator app. IMO, all O365 tenants should strongly consider enabling these two features below.

  • Number matching in Microsoft Authenticator
  • Additional context in Microsoft Authenticator

Number Matching

When a user responds to MFA challenge, they will see a number in the application or in the webpage which is challenging them and the user must enter this number in the Authenticator app to complete the process. This process is already part of the passwordless authentication method.

Additional Context

The Authenticator will also display the name of the app requesting MFA and also the user’s sign-in location. The sign-in location is based on the user’s public IP address. The location may not be accurate at times. This is because the IP location tagging and based on what I saw it is not the exact location of where the application’s traffic origin but usually close enough.

Application prompt on the webpage
Authenticator prompt

How to enable number matching with additional context in Azure AD

  • Open Azure AD admin center(https://aad.portal.azure.com/)
  • Click on the Security tab –> Authentication methods
  • Select Microsoft Authenticator
  • Toggle ENABLE to Yes
  • Toggle TARGET to All users
    • Depending on how you decide to roll out this feature, you can select a Azure AD group by selecting Select users, Select the group and follow along the next steps
  • Click on the three dots and Configure
  • Set
    • Authentication mode = Any
    • Require number matching = Enabled
    • Show additional context in notifications = Enabled
  • Click Done
  • Click Save
Microsoft Authenticator settings

Configure settings for All Users

In the drop down for ‘Require number matching’ and ‘Show additional context in notifications’, there is a ‘Microsoft Managed‘ option. It means this functionality will be enabled by default for all tenants after the feature is generally available. Currently it is in public preview.

Thank you for stopping by.✌

Azure AD – Assign Groups and Users to an application

Azure AD allows granting access to resources by providing access rights to a single user or to an entire Azure AD group. Using groups let the application or the resource owner to assign a set of permissions to all the members of a group. Management rights can be granted to other roles, like example., Helpdesk administrators to add or remove members from the group.

When a group is assigned to an application, only users in the group will have access. Also, if the application exposes role, roles can also be assigned to groups or users.

When I was working on integrating Salesforce with Azure AD for SSO, I needed to assign groups to the roles that Salesforce exposed and I figured I’d document the process I went though here.

Bulk create Azure AD groups

This section describes how to create multiple groups in Azure AD. This is not needed if your organization already has groups created.

Use below script to create multiple Azure AD groups that are listed in a csv file,

Connect-AzureAD
$groups = import-csv "C:\tmp\AzureAD Groups\groups.csv"

Foreach($group in $groups) {

New-AzureADGroup -DisplayName $group.name -Description $group.description -MailEnabled $false -SecurityEnabled $true -MailNickName "NotSet"

}

csv file input,

csv file

PowerShell output,

output

Assign Groups and Users to an app using PowerShell

Assigning groups or users can be done from the Azure AD admin portal by clicking on the Users and groups tab in the application which you are granting access to.

My plan here is to create Azure AD groups that corresponds to the name of the role that Salesforce exposes and then add users to those groups which provides them with appropriate access to the application.

Determine the roles available for the application

To determine the roles that the application exposes, use the cmdlet below.

$appname = Read-Host "Enter your App's Display Name"
$spo = Get-AzureADServicePrincipal -Filter "Displayname eq '$appname'"
$spo.AppRoles | ft DisplayName,IsEnabled,Id
AppRoles Output

Assign Groups to Roles in Application

Use below script to assign the application’s roles to groups. If you notice the csv file, I’m using the groups created in the previous step to the roles. This way, it is easier to manage. The New-AzureADGroupAppRoleAssignment cmdlet can be used to achieve this.

$appname = Read-Host "Enter your App's Display Name"
$spo = Get-AzureADServicePrincipal -Filter "Displayname eq '$appname'"
$groups = import-csv "C:\tmp\Salesforce_Asgn\groups.csv"

Foreach($group in $groups) {
	$id = Get-AzureADGroup -SearchString $group.name
	$app_role_name = $group.role
	$app_role = $spo.AppRoles | Where-Object { $_.DisplayName -eq $app_role_name }
	New-AzureADGroupAppRoleAssignment -ObjectId $id.ObjectId -PrincipalId $id.ObjectId -ResourceId $spo.ObjectId -Id $app_role.Id
	
}
csv input
PowerShell output

This below is how the application looks like in the Azure AD admin portal after running the above script,

Application Users and groups tab

Assign Users to Roles in Application

Use below script to assign the application’s roles to users. This can be achieved using the New-AzureADUserAppRoleAssignment cmdlet. Use the below script,

$appname = Read-Host "Enter your App's Display Name"
$spo = Get-AzureADServicePrincipal -Filter "Displayname eq '$appname'"
$users = import-csv "C:\tmp\Salesforce_Asgn\users.csv"

Foreach($user in $users) {
	$id = Get-AzureADUser -ObjectId $user.name
	$app_role_name = $user.role
	$app_role = $spo.AppRoles | Where-Object { $_.DisplayName -eq $app_role_name }
	New-AzureADUserAppRoleAssignment -ObjectId $id.ObjectId -PrincipalId $id.ObjectId -ResourceId $spo.ObjectId -Id $app_role.Id
	
}
PowerShell Output
Application Users and groups tab

Get all role assignments to an application using PowerShell

Get-AzureADServiceAppRoleAssignment cmdlet can be used to determine all role assignments to an application,

$appname = Read-Host "Enter your App's Display Name"
$spo = Get-AzureADServicePrincipal -Filter "Displayname eq '$appname'"
Get-AzureADServiceAppRoleAssignment -ObjectId $spo.ObjectId -All $true
PowerShell Output

Remove All Groups and Users assigned to an application

To remove all assigned groups and users from an application, Remove-AzureADServiceAppRoleAssignment cmdlet can be used,

$appname = Read-Host "Enter your App's Display Name"
$spo = Get-AzureADServicePrincipal -Filter "Displayname eq '$appname'"
$app_assignments = Get-AzureADServiceAppRoleAssignment -ObjectId $spo.ObjectId -All $true
$app_assignments | ForEach-Object {
	if ($_.PrincipalType -eq "user") {
		Remove-AzureADUserAppRoleAssignment -ObjectId $_.PrincipalId -AppRoleAssignmentId $_.ObjectId
	} elseif ($_.PrincipalType -eq "Group") {
		Remove-AzureADGroupAppRoleAssignment -ObjectId $_.PrincipalId -AppRoleAssignmentId $_.ObjectId
	}
}

It should go without saying that removing all permissions will disable user’s access to the application. Don’t try this as a first step in a production environment, unless you are absolutely sure of it.

Thank you for stopping by.✌

Azure AD – Implement SSO integration with Salesforce

In this post I will go over the steps required to implement Azure AD SSO integration with Salesforce. With Salesforce and Azure AD SSO integration in place, it allows:

  • Users to sign-in to Salesforce with their Azure AD account
  • Administrators to control who can access Salesforce
  • Administrators can also manage users in one location – Azure AD admin center

Salesforce supports,

  • Service Provider-Initiated Login
  • Just In Time user provisioning – If a user doesn’t already exist, a new one is created in Salesforce when a login is attempted
  • Automated user provisioning and deprovisioning (This is covered in a later post)
  • Configuring the mobile application with Azure AD SSO
High level implementation steps

In Azure AD add Salesforce to Enterprise Applications

To configure this integration, first step is to add Salesforce from the gallery to your list of managed SaaS apps. Below are the steps,

  1. Login to Azure AD Admin Center(https://aad.portal.azure.com) and click on the Enterprise applications tab
  2. To add new application, Click New application
  3. In the Browse Azure AD gallery section, enter ‘Salesforce’ in the search box
  4. Select Salesforce and you can name it to differentiate from development to production instance with a prefix but in this scenario, I’ll leave it as default as in screenshot below. Click Create
  5. It can take a few seconds for the app to be added
Search ‘Salesforce’
Add Salesforce by clicking ‘Create’

Configure Azure AD SSO

Below steps details how to enable SSO in Azure AD portal for the Salesforce application,

  1. On the Salesforce application page in Azure AD,
    • Click on SAML-based Sign-on tab under the Manage section
    • Select SAML
  2. Select the edit icon in the Basic SAML configuration section
Basic SAML Configuration
  1. Your Salesforce administrator should know this information and if not, you can contact Salesforce support. But in general, this information is easy to figure out. I’ve mentioned the format of these URLs below. and I have used my own instance’s URL in the screenshot.
Enterprise accountDeveloper account
Identifier (Entity ID)https://{your-subdomain}.my.salesforce.comhttps://{your-subdomain}-dev-ed.my.salesforce.com
Reply URLhttps://{your-subdomain}.my.salesforce.comhttps://{your-subdomain}-dev-ed.my.salesforce.com
Sign-on URLhttps://{your-subdomain}.my.salesforce.comhttps://{your-subdomain}-dev-ed.my.salesforce.com

Note: Recently, Salesforce has started forcing the lightning experience for the salesforce orgs. The URL is redirected to .lightning.force.com once user is logged in but based my testing, .my.salesforce.com works for the SSO configuration. This can be clarified with Salesforce tech support if necessary.

In my scenario, I’m using a Salesforce developer instance and the values in the below screenshot represent my environment.

  1. Enter the values and click Save
Fill the URL values
  1. On the Set up single sign-on with SAML page, in the SAML Signing Certificate section, find Federation Metadata XML and select Download to download the xml file and save it on your computer
Download Federation Metadata XML
  1. The Set up section has the configuration URLs
Azure AD configuration URLs

Create Salesforce test user

If you are planning to do Just In Time(JIT) user provisioning which is enabled by default, no action is needed but if you don’t plan on using JIT user provisioning, you will have to work with your Salesforce administrator to create a user who already exists in your Azure AD.

Configure Salesforce

  1. Login to Salesforce portal with System Administrator privileges
  2. Click on the Setup under settings icon on the top right corner of the page
Click Setup
  1. In the quick find, type ‘Single Sign-on..’
Search Single Sign-On
  1. On the Single Sign-On Settings page, click the Edit button
Edit Single Sign-On Settings
  1. Place checkmark next to the following options below and click Save
    • SAML Enabled
    • Make Federation ID case-insensitive
  1. Click New from Metadata File
New SAML Single Sign-On Settings from Metadata file
  1. Click Choose File to upload the metadata XML file downloaded from the Azure AD admin center from step 5. in ‘Configure Azure AD SSO’ section and click Create
Choose Federation Metadata file downloaded from Azure AD
  1. In the SAML Single Sign-On Settings page, the fields are automatically populated using the information from the federation metadata xml file. Fill in values for below and to keep things simple, I named it ‘AzureAD’ but pick what makes sense or follows naming conventions in your organization,
    • Name
    • API Name
SAML Single Sign-On Settings w/o JIT user provisioning
  1. Optional. In the Just-in-time User Provisioning section, I’m leaving the User Provisioning Enabled unchecked but if you want to use SAML JIT, place a checkmark next to User Provisioning Enabled and select SAML Identity Type as Assertion contains the Federation ID from the User object.
SAML Single Sign-On Settings with JIT user provisioning
  1. Optional..Continued.. If you configured SAML JIT, you must complete an additional step in the Configure Azure AD SSO section. The Salesforce application expects specific SAML assertions, which requires you to have specific attributes in your SAML token attributes configuration. The following screenshot shows the list of required attributes by Salesforce.
Screenshot that shows the JIT required attributes pane.
  1. On the left navigation pane in Salesforce, search for My Domain
Search ‘My domain’
  1. In the Authentication Configuration section, and click the Edit button
Authentication Configuration
  1. In the Authentication Configuration section, under Authentication Service, place checkmark next to ‘Login Form‘ and ‘AzureAD‘ and click Save
Authentication Configuration – Authentication Service
  1. If more than one authentication service is selected, users are prompted to select which authentication service they like to sign in with while initiating SSO to your Salesforce environment
    • If you don’t want it to happen, then you should leave other authentication services unchecked
user login screen with authentication options

Enable Token Encryption (Optional)

Enabling encryption of SAML assertions adds another layer of security. The SAML assertions are encrypted such that the assertions can be decrypted only with the private keys held by the service provider.

Some organizations require encryption SAML assertions and this is fairly straight-forward to setup in Salesforce and Azure AD.

  1. In the SAML Single Sign-On Settings, select the ‘SelfSignedCert…’ and click save
    • Your organization might require using a 3rd party certificate(Example: DigiCert, GeoTrust, etc) and in that scenario you will have to import the certificate into Salesforce using the Certificate and Key Management
SAML Single Sign-On Settings – Assertion Decryption Certificate
  1. In the navigation pane on the left, search for Certificate and Key Management
  2. Click on the certificate
Click on the certificate
  1. Click on Download Certificate and save the file to your machine
    • This steps exports the public key of the certificate which will be used by Azure AD to encrypt the assertion which Salesforce can decrypt using the private key
Click ‘Download Certificate’
  1. In Azure AD admin center, open the Salesforce application and click on the Token encryption tab. Click Import certificate, browse to the download certificate from Salesforce and click Add. Click on Activate token encryption certificate to make the certificate status active.
Token encryption Azure AD application
  1. Test the Salesforce SSO to make sure everything works as expected

Test SSO

  1. Open your organization’s Salesforce Sign-On URL directly
    • Use Incognito or InPrivate mode to avoid previously saved cookies
  2. The portal should auto-redirect to login.microsoftonline.com and prompt a sign-in

Issues you may encounter and tips on how to fix it

Error: Your administrator has configured the application to block access unless they are specifically granted (“assigned”) access to the application.

Fix: This can be fixed by adding users directly in Users and groups tab of the Salesforce application in Azure AD. It is also a better idea to create group for Salesforce roles and adding users to these groups. This also works better if you have an on-premise AD environment and syncing user to Azure AD.

Or you can set No to the Assignment required? option in the application properties. This way, the user access is managed in Salesforce. But managing user access in Azure AD is lot easier and along with Azure AD P2’s group reviews.

In my scenario, once I added my test user to ‘Salesforce-Standard Users’ Azure AD group I’ve created and assigned a role, the login worked.

login error

I’ve detailed the steps to accomplish this in a different post.

Azure AD Groups assigned to Salesforce Roles

Error: Single Sign-On Error. We can’t log you in because of an issue with single sign-on. Contact your Salesforce admin for help.

Fix: This is a generic error but depending on the issue, it will need more in-depth troubleshooting.

In my scenario, In the SAML Identity Type as Assertion contains the Federation ID from the User object when I was testing JIT, I left this option enabled which caused this error. I set SAML Identity Type as Assertion contains the User’s Salesforce username and it fixed it.

Depending on your scenario, you may have to determine the issue and I use SAML-tracer which is available as extensions for Chrome and Firefox.

Typically the issue is with not having the correct SAML Assertion Fields in the Azure AD application.

Salesforce login error

Hope these steps above in this guide helped you in setting up Azure AD SSO with Salesforce.

Thank you for stopping by. ✌

Office 365 – Export Email Addresses and UPN of O365 users with PowerShell

I will go over steps on how to export the list of users with their UPN, Object ID, primary SMTP address and Alias email address.

The Get-AzureADUser cmdlet comes in handy to pull all the user details in this scenario. The Mail attribute contains the Primary SMTP address of the user and the Primary SMTP address and Alias email address are stored in the ProxyAddresses attribute in Azure AD. The ProxyAddresses attribute is a multi-value property. The Primary SMTP address can be easily identified as it is in this format, SMTP:user@emaple.com The upper-case SMTP denotes that it the primary email address.

When an object is synced from on-premise Active Directory to Azure AD, the values in the proxyAddresses attribute in AD are compared with Azure AD rules and then populated in Azure AD. So, the values of the proxyAddresses attribute in AD may not match the ProxyAddresses attribute in AzureAD.

Export all users to csv file

The below script will pull all Azure AD users,

Connect-AzureAD

$Output = @() #create an empty array

$AzureADUsers = Get-AzureADUser -All $true | Select DisplayName,UserprincipalName,ObjectId,Mail,ProxyAddresses #Get all Azure AD users

ForEach ($User in $AzureADUsers)
{
	$Output += New-Object PSObject -property $([ordered]@{ #fetch user detail and add to $output
		UserName = $User.DisplayName
		UserprincipalName = $User.UserprincipalName
		UserId = $User.objectId
		SMTPAddress = $User.Mail
		AliasSMTPAddresses = ($User.ProxyAddresses | Where-object {$_ -clike 'smtp:*'} | ForEach-Object {$_ -replace 'smtp:',''}) -join ','
		
	})
}
$Output | Export-csv "C:\tmp\O365Users_$((Get-Date).ToString("MMddyyyy_HHmmss")).csv" -NoTypeInformation -Encoding UTF8 #Export users to csv file

Output file,

csv output

Thank you for stopping by.✌