Automatically Roll Over Kerberos Decryption Key with Azure AD SSO

In Azure AD, Seamless Single Sign-on can be configured when Password Hash Sync or Pass through authentication is configured. Azure AD Seamless SSO automatically signs in users when they are in their corporate owned devices and one the corporate network. This helps save a lot of time without repeatedly typing credentials in to Azure AD and other Azure AD integrated applications.

When we enable Azure AD Seamless SSO, a computer account named AZUREADSSOACC is created in on-premises AD in each AD forest. This computer account represent Azure AD in the on-premises AD. Considering how important this computer object is, it is better to take the following steps to protect it,

  • Move it into a OU,
    • Where they are safe from accidental deletions
    • Where only domain admins have access
  • Ensure that Kerberos delegation on the computer account is disabled
  • No other accounts in AD have delegation permissions
    • This can be easy to miss if you have permissions sprawl

The Kerberos decryption key for this computer account is securely shared with Azure AD. Microsoft recommends to roll over the Kerberos decryption Key at least every30 days. You will notice a warning when the key has not been updated in the past 30 days.

Azure AD warning
Kerberos decryption key

As I mentioned earlier, Microsoft recommends to roll over the keys at least every 30 days. Obviously, I can remember it promptly or even put a meeting invite in Outlook to recur 30 days, keep snoozing it to eventually dismiss the alert because I’m stuck doing something else on that day. I’m sure this feels very familiar to most of you reading this. 😂

This is a great scenario where automation can come in handy and I’ll go through the steps on how I implemented this.


Below are the requirements for implementing this solution.

  • Global admin account
    • With MFA exception (preferably by origin IP)
  • Administrator account on AD Connect server with logon as a batch job
  • On-Premises AD domain admin account
  • Domain account that has permissions to ‘login as batch service’ on the Azure AD connect server

I covered in later half of another post about securely storing credentials using PowerShell into a file. Run these below lines to store encrypted credentials into a text file. This is far better than storing the password in plain text.

Remember, this method is secure but not 100% safe.

$ADCred = Get-Credential
$ADCred.Password | ConvertFrom-SecureString | Out-File "C:\temp\ADCred_sec.txt"
$AzureAD = Get-Credential
$AzureAD.Password | ConvertFrom-SecureString | Out-File "C:\temp\AzureAD_sec.txt"

Enter the domain user and Azure AD user which has necessary permissions in this below script and save it.

$ADUser = '\user' #Must be entered in the SAM account name format\jdoe
$ADUserEncrypted = Get-Content "C:\temp\ADCred_sec.txt" | ConvertTo-SecureString
$OnPremADCred = New-Object System.Management.Automation.PsCredential($ADUser,$OnPremADCred)

$AzureADUser = ''
$AzureADUserEncrypted = Get-Content "C:\temp\AzureAD_sec.txt" | ConvertTo-SecureString
$AzureADCred = New-Object System.Management.Automation.PsCredential($AzureADUser,$AzureADUserEncrypted)

Import-Module 'C:\Program Files\Microsoft Azure Active Directory Connect\AzureADSSO.psd1'
New-AzureADSSOAuthenticationContext -CloudCredentials $AzureADCred
Update-AzureADSSOForest -OnPremCredentials $OnPremADCred

Schedule to automate

Once the script is stored, create a basic scheduled task to run it every month. Below are my settings,

Scheduled Task – General
Scheduled Task – Trigger
Scheduled Task – Actions

After making sure all the setting, Click OK and you will be prompted for credentials. If you receive the below error,

Task Scheduler Error “A specified logon session does not exist” - Microsoft  Tech Community
  1. Run gpedit.msc
  2. Look in Computer Configuration | Windows Settings | Security Settings | Local Policies | Security Options
  3. Double-click Network access: Do not allow storage of passwords and credentials for network authentication
  4. Set the policy to Disabled
  5. Go back to scheduled task to enter your credentials and click OK

Hope this helped you out in automating the Kerberos decrypting key roll over for the AZUREADSSOACC computer account.

Thank you for stopping by. ✌

Azure AD – Password Hash Synchronization – Non-Expiring Password Service Accounts

Recently I worked on implementing password hash synchronization with Azure AD Connect sync in one of the tenants I manage. This interested me on so many levels but especially the lengths that Microsoft has gone to protect this hash sync process fascinated me.

To synchronize a password, Azure AD Connect sync extracts password’s hash from on-premises AD. Extra security processing (meaning, When a user attempts to sign in to Azure AD and enters their password, the password is run through MD4+salt+PBKDF2+HMAC-SHA256 process) is applied to the password hash before it is synchronized to the Azure AD authentication service. Passwords are synchronized on a per-user basis and in chronological order.

When password hash synchronization is enabled, by default the cloud account password is set to ‘Never Expire’. This is a bit scary because if left in default state, users can still login to applications with their password that is expired in on-premise AD. Also meaning that the on-premise AD password expiration policy is not in sync with Azure AD. Users can be forced to comply with your Azure AD password expiration policy by enabling the EnforceCloudPasswordPolicyForPasswordSyncedUsers feature.

When EnforceCloudPasswordPolicyForPasswordSyncedUsers is disabled (which is the default setting), Azure AD Connect sets the PasswordPolicies attribute of synchronized users to “DisablePasswordExpiration”


To enable the EnforceCloudPasswordPolicyForPasswordSyncedUsers feature, run the following command using the MSOnline PS module

Set-MsolDirSyncFeature -Feature EnforceCloudPasswordPolicyForPasswordSyncedUsers -Enable $True

Once enabled, Azure AD does not go to each synchronized user to remove the “DisablePasswordExpiration” value from the ’PasswordPolicies’ attribute. But waits till the user’s next password change to the “DisablePasswordExpiration” from the ‘PasswordPolicies’ which is when the next password sync happens.

For this reason it is recommended to enable EnforceCloudPasswordPolicyForPasswordSyncedUsers prior to enabling password hash sync, this way the initial sync of password hashes does not add the “DisablePasswordExpiration” value to the ‘PasswordPolicies’ attribute for the users. But if you miss enabling this it is not the end of the world.

Use the below cmdlet to determine a user’s Azure AD password policy,

$user = Read-host "Enter user's UPN:"
Get-AzureADUser -objectID $user | Select DisplayName, passwordpolicies

The issue we need to address are the service accounts that live in on-premise AD with non-expiring password and their identity is synced to Azure AD so these accounts can be used in various applications. So, if you enable EnforceCloudPasswordPolicyForPasswordSyncedUsers feature and then enable password hash sync, your service accounts with non-expiring password will not have any password policy attached to it in Azure AD. These accounts will need the “DisablePasswordExpiration” policy set to them explicitly.

You can set this policy for all the non-expiring password account using the below script,

$ou1 = Get-ADUser -SearchBase 'OU=Users,OU=OU1,DC=domain,DC=com' -Filter ( passwordNeverExpires -eq $true -and enabled -eq $true } | Select userPrincipalName
$ou2 = Get-ADUser -SearchBase 'OU=Users,OU=OU2,DC=domain,DC=com' -Filter ( passwordNeverExpires -eq $true -and enabled -eq $true } | Select userPrincipalName #if you are syncing only certain OUs, this helps

$AllOu = $ou1 + $ou2

foreach ($account in $AllOU) {

            $t = (Get-AzureADUser -ObjectID $account.userPrincipalName).passwordpolicies
            if ($t -ne "DisablePasswordExpiration") {
               Set-AzureADUser -ObjectID $account.userPrincipalName -PasswordPolicies "DisablePasswordExpiration"                

The Azure AD password policy for these account is empty when it is created in on-premise AD and the administrator creating the account can set the “DisablePasswordExpiration” policy on a per-account basis by running this below,

$user = Read-host "Enter the user's UPN"
Set-AzureADUser -ObjectID $user -PasswordPolicies "DisablePasswordExpiration"

Another caveat here is, when these account’s password is changed on-premises for whatever reason the ‘PasswordPolicies’ value switched to ‘None’

This can happen when,

  • You allow helpdesk resets service account passwords
  • You allow service account owners reset account password
  • Application admins who use these service accounts quit or change job positions and the password needs to be changed
  • Administrator creating the service account on-premise forgot to set the password policy by running the Set-AzureADUser

When the ‘PasswordPolicies’ value gets set to ‘None’ as I mentioned earlier, the account sign-ins to Azure AD will fail with error code ‘50055 — InvalidPasswordExpiredPassword — The password is expired’.

To avoid this, you can create a scheduled task on an on-premise server which run the PS script from above maybe once a week. An issue here will be for these script to run the Connect-AzureAD cmdlet needs to be run. There are probably a thousand different ways to accomplish this but for the sake of simplicity, you can consider these two options,

  • Store your credentials in plan text in the script
  • Create an encrypted, secure string password file and use it in the script

Store credentials in plain text

This is not recommended practice and never be used but there might be scenarios where you may have to use it for some quick tests. In such a scenario, you can just do something like this,

$user = ""
$pwd = "MySeCur3P@$$w0rd"
$secpwd = ConvertTo-SecureString $pwd -AsPlainText -Force 
$cred = New-Object System.Management.Automation.PSCredential ($user, $secpwd)
Connect-AzureAD -Credential $cred | Out-Null

All this being said, don’t use this method and if you do, please remember to delete the script after testing.

Use secure string password file

This method is far better to securely store password for automation scripts. The idea is, you create password file which has the password stored encrypted. It goes without saying that it is not a good idea to save this file as password.txt.

To create password file,

(Get-Credential).Password | ConvertFrom-SecureString | Out-File "C:\temp\sec.txt"

To silently connect to Azure AD using stored credentials,

$User = ""
$File = "C:\temp\sec.txt"
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)
Connect-AzureAD -credential $credential | Out-Null

Keep in mind that you can only use this file on the computer or server where you created it. This happens because of how Windows Data Protection API encrypts the information from current computer or user account. If you try the file on a different computer you’ll get a ‘Key not valid..’ error. I think this is great and adds another layer of security.

Also, this won’t the password being decrypted or from reusing the encrypted password if it falls into wrong hands. The basic idea here is not to store password in plaintext. This method is not foolproof but good enough.

If you need a secure password file that needs to be used in multiple scripts and on different machines, AES encryption algorithm can be used and covering that will take this post way off the Azure AD non-expiring password accounts topic..too late for that..I know. 😁

Hope this helped you setup your environment before those password expired in Azure AD.

Thank you for stopping by..✌

O365 – Prevent Users from Signing Up for Trials and Purchasing Their Own Pro license

I’ve updated this post with the newer MSCommerce PowerShell module

Self-service is a great idea in several instances but in my opinion when it comes to users signing up for trials and purchasing licenses, it seems to be causing unexpected issues especially while answering to the purchasing team.

Most organizations these days have procurement processes in place to meet regulatory, security, compliance and governance needs. And the need to ensure that all licenses are approved and managed according to defined processes is very important. And when you take expenses, privacy or security into consideration, it is a good idea to disable self-service sign-up and purchases.

To disable all self-service sign-ups

This can be achieved using the MSOL PowerShell module. Type below command to check current settings:

Get-MsolCompanyInformation | fl AllowAdHocSubscriptions
current settings

To disable all self-service sign-ups,

Set-MsolCompanySettings -AllowAdHocSubscriptions:$false

When users try to sign-up, they’ll see the below message,

Your IT department has turned off signup

Prevent users from purchasing their own Pro license

To install and connect the MSCommerce module, start PowerShell as an administrator to install the module,

Install-Module -Name MSCommerce
Import-Module -Name MSCommerce
Get-Command *-mscommerce*

To determine current setting,

Get-MSCommercePolicy -PolicyId AllowSelfServicePurchase

View a list of all available self-service purchase products and the status,

Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase

Disable the policy setting for a specific product, Below example: ‘Power BI Pro’

Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId CFQ7TTC0L3PB -Enabled $False

Below is an example script on how your can disable AllowSelfServicePurchase by getting the ProductID for ‘Power BI Pro’

$p = Read-Host "Enter product name"
$product = Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase | where {$_.ProductName -match $p }
Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId $product.ProductID -Enabled $false

In scenarios where there are more than one values for the product, Below example: ‘Power Automate’

$p = Read-Host "Enter product name"
$product = Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase | where {$_.ProductName -match $p }
Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId $product[0].ProductID -Enabled $false
Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId $product[1].ProductID -Enabled $false
Update-MSCommerceProductPolicy # more than one value

To disable AllowSelfServicePurchase for all products,

Get-MSCommerceProductPolicies -PolicyId AllowSelfServicePurchase | ? {$_.PolicyValue -eq "Enabled" } | ForEach {Update-MSCommerceProductPolicy -PolicyId AllowSelfServicePurchase -ProductId $_.ProductId -Enabled $False }
To disable for all products

Thanks for stopping by.✌

Active Directory – Set ‘Manager Can Update Membership List’ with PowerShell

AD group management usually is delegated in most organizations. Usually one of helpdesk’s responsibility or sometime a department manager decides who is member of her or his team at any given time. These users can be non-IT users in several situations.

To serve this purpose, a user can be designated as manager in the Managed By tab of the security group using Active Directory Users and Computers (ADUC) console. Placing a checkmark next to Manager can update membership list allows the user to update the group member by adding or removing users from the security group.

The Manager can update membership list option modifies the Access Control List (ACL) of the security group which we can see in the Security tab, in Advanced.

Setting the Managed by is fairly straight-forward. We can use the Set-ADGroup cmdlet to update the value. We can use the below code to update manager for a group:

$grpname = Read-Host "Enter AD Group's name"
$Managername = Read-Host "Enter AD user's name"
Get-ADGroup -Identity $grpname | Set-ADGroup -ManagedBy "$Managername"

But this doesn’t enable the Manager can update membership list option. To allow this user who is set as this group’s manager, we need to add an AccessRule for this user to the ACL of the group. I’m using this below process to put together a script,

In this below script, We get the user and current ACL of the group. And then the user who will be the manager. And to build the new ACL, we obtain the SID string, then set control type and AD permission. We also need to specify the System ID GUID of the Member attribute and this ACL need to be applied to this specific attribute (Member). Use all the variables to build a new rule, add the rule to the existing rule. And finally use Set-Acl cmdlet to apply new ACL to the Group. Yup!.. that easy!! 🤷‍♂️

$grpname = Read-Host "Enter AD Group's name"
$Grp = Get-ADGroup -Identity $grpname
$GroupACL = Get-Acl AD:\$Grp

$Managername = Read-Host "Enter AD user's name"
$Manager = Get-ADUser -Identity $Managername
$UserSid = New-Object System.Security.Principal.NTAccount ($Manager.SamAccountName)

$Rights = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
$Control = [System.Security.AccessControl.AccessControlType]::Allow
$Guid = [guid]"bf9679c0-0de6-11d0-a285-00aa003049e2"
$Rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule ($UserSid, $Rights, $Control, $Guid)
Set-Acl -AclObject $GroupACL -path AD:\$Grp
Get-ADGroup -Identity $Grp | Set-ADGroup -ManagedBy "$Manager"
Write-Host $Manager.Name set as manager on $group.groupname

What if you have to update multiple groups with a user as manager to each. I didn’t have enough time to make a detailed one and the below script will serve the purpose. I’d probably include checks to make sure the group and the user exists in AD.

Note: csv file has groupname,managerSamname as column headers

$groups = import-csv "C:\Scripts\list.csv"

foreach ($group in $groups){
        $Grp = Get-ADGroup -Identity $group.groupname
        $GroupACL = Get-Acl AD:\$Grp
        $Manager = Get-ADUser -Identity $group.managerSamname
        $UserSid = New-Object System.Security.Principal.NTAccount ($Manager.SamAccountName)
        $Rights = [System.DirectoryServices.ActiveDirectoryRights]::WriteProperty
        $Control = [System.Security.AccessControl.AccessControlType]::Allow
        $Guid = [guid]"bf9679c0-0de6-11d0-a285-00aa003049e2"
        $Rule = New-Object System.DirectoryServices.ActiveDirectoryAccessRule ($UserSid, $Rights, $Control, $Guid)
        Set-Acl -AclObject $GroupACL -path AD:\$Grp
        Get-ADGroup -Identity $Grp | Set-ADGroup -ManagedBy "$Manager"
        Write-Host $Manager.Name set as manager on $group.groupname

Hope this post helped you in bulk setting group managers in AD.

Thank you for stopping by.✌

Power BI – Create Visualizations with data from Active Directory

Power BI provides a wide variety of options to connect, analyze and visualize data from various sources. There were many instances where I’ve been asked to get a count of all users in the domain while in meetings and if possible a country-wise breakdown. Well..I don’t have that ready but would be nice to know if this information was needed earlier. As the user count is a moving target, I figured it’d be nice to have a PBI viz to help me answer this whenever asked.

There are several different ways to get this information and PBI viz is one of those.

In this post, I’ll go over steps on creating a visualization that I find useful to get a breakdown of users in the domain by country.

This should give you an idea on how to connect Power BI to AD and pull data to built visualizations.

To proceed further, make sure you have the Power BI desktop App downloaded and installed on your machine.

Launch Power BI Desktop,

  1. Click Get data and Click More…
  2. In the Get Data window, Click Other and Active Directory
  3. Click Connect
  1. Enter your Domain name under Domain then click OK
Enter domain name
  1. Enter credentials which has permissions to read attributes from AD and click Connect
Enter credentials
  1. The Navigator window shows all the tables available. In this post, I’m only going to use the data from user table
  2. Place a check mark next to user and click Transform Data
  1. In the Power Query Editor window, we can select the values we’ll be working with. As we can see, the query editor has detected what is known as Complex columns. The reason they are complex is that they actually contain an object, not just a simple value like a single line of text column.
  2. Click on Expand column icon
  3. Place a checkmark next to co
    • I’m also selecting c and countryCode for the sake of it, because why not! 😉
  4. I’m also leaving the Use original column name as prefix checked
  5. Click OK
  1. I’m repeating the same steps for other columns as well to pick values I need
    • I’d need the UPN for unique values, so I’m picking that
Expand user
  1. Below screenshots shows all the columns I’ve selected to be loaded using Choose Columns, unselecting the columns I don’t need
  2. Once satisfied with the data, Click Close & Apply
  1. Data gets loaded into the model and depending on how many users you have in your domain and the hardware specs of the machine running PBI desktop, this can take a while

Below I have created a basic visualization which shows a pie chart with user breakdown by country name,

I did some formatting of the title, the legend and such to make it look pretty. If the data changes in AD, you can click on Refresh to get the updated information populated in the visualizations you create.

Here is another basic stacked column chart I created with UAC status of users per country. I created a UAC table which has the values for the UAC codes in AD and I merged those queries. I keep saying these are basic because by no means I’m a PBI expert but I’m very interested in learning and improving my skills in it every chance I get.

You can incorporate the visualizations you create, in a AD dashboard in PBI and If you have an on-premise PBI report server you can publish this report there or to PBI web.

Hope this post helped you in your AD visualizations journey.

Thank you for stopping by✌