O365 – Determine Licensed users

Who are the licensed users in our tenant and what licenses are assigned to them? This question comes up way too often in several scenarios and there are a few methods to determine this. I will go over those in this post. I’ve updated this post with some newer information about exporting from the admin portal when I learned them.

Using PowerShell

There are two versions of the PowerShell module that you can use to connect to Microsoft 365 and administer user accounts, groups, and licenses:

  • Microsoft Azure AD Module for Windows PowerShell, whose cmdlets include Msol in their name
  • Azure AD PowerShell for Graph, whose cmdlets include AzureAD in their name

Please make sure you have the MSOnline Module for PowerShell installed and loaded

The Get-MsolUser is a powerful cmdlet which provides a lot of details and I’m going to use it for determining the user’s license.

To connect to the service,

$credential = Get-Credential -credential "adminuser@tenant.onmicrosoft.com"
Connect-MsolService -credential $credential

To get all (licensed and unlicensed) users,

Get-MsolUser -All
Get-MsolUser output

To list only licensed users,

Get-MsolUser -All | Where {$_.isLicensed -eq $true}

To list unlicensed users,

Get-MsolUser -All -UnlicensedUsersOnly

To export all users to a csv with their user name, license status and license assigned,

Get-MsolUser -All | Where {$_.isLicensed -eq $true} | Select Displayname,userprincipalname,islicensed,{$_.Licenses.AccountSkuId} | Export-csv "C:\tmp\userlist.csv" -NoTypeInformation

The exported csv will look like this,

csv data

Using the O365 admin portal

Microsoft has enabled exporting licensing information from the portal.

  1. Login to O365 admin center
  2. Users –> Active Users
  3. Click Export Users
  4. Click Continue
admin portal licensing information

This is how the csv output looks like,

csv export from admin center

Thank you for stopping by. ✌

Office 365 – Update Primary Email Address in Bulk using PowerShell

In this post, I’ll go over steps on how to update users’ primary email address in bulk.

I had to update the custom domain name address for one of the tenants I manage. When the O365 tenant was setup, I didn’t have my domain name ready for various reasons and the users were setup with @{tenantname}.onmicrosoft.com addresses. Once I added the necessary DNS records for O365 and made sure my new domain name is listed as default in the domain tab(Microsoft 365 admin center -> Settings -> Domains) in the list of , I was ready to update the user accounts with the new domain name.

Before proceeding further make sure you are connected to Exchange Online,

$o365cred = Get-Credential
Connect-ExchangeOnline -credential $o365cred

To bulk update accounts from a csv file:

Note: csv file has User,Emailaddress as column headers. Enter the users’ email address with new domain in the csv file. It is strongly recommended to leave the onmicrosoft.com address in the users’ proxy addresses and specifying the new address as PrimarySmtpAddress with SMTP.

$users = Import-Csv C:\tmp\Update-Email\emails.csv
foreach ($user in $users){

$Mailbox= Get-Mailbox -Identity $user.User
$PrimaryEmail=$Mailbox.PrimarySmtpAddress
$SMTP ="SMTP:"+$user.Emailaddress
Set-Mailbox -Identity $user.User -EmailAddresses $SMTP,$PrimaryEmail -WindowsEmailAddress $user.Emailaddress -MicrosoftOnlineServicesID $user.Emailaddress 

}

To bulk update all accounts in the O365 tenant:

Note: This below script will change all accounts in the tenant from whatever your enter for the $oldDomain to the $newDomain. So, proceed with caution and comply with your change management process and steps.

$oldDomain = Read-Host "Enter existing domain name in '@domainname.com' format"
$newDomain = Read-Host "Enter new domain name in '@domainname.com' format"

$mailboxes = (Get-Mailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox).where{$_.PrimarySmtpAddress -like "*$oldDomain"}
foreach ($mbx in $mailboxes){

$PrimaryEmail = $mbx.PrimarySmtpAddress
$newSMTPAddress = $mbx.PrimarySmtpAddress -split '@'
$newSMTPAddress = $newSMTPAddress[0] + $newDomain
$SMTP ="SMTP:"+$newSMTPAddress
Write-Host "Processing: $mbx.Name --> $newSMTPAddress"
Set-Mailbox -Identity $mbx.Identity -EmailAddresses $SMTP,$PrimaryEmail -WindowsEmailAddress $newSMTPAddress -MicrosoftOnlineServicesID $newSMTPAddress
}

You can also make this change in bulk in the portal as well,

  1. Select all the users whom you wish you update
  2. Click on Change domains
  3. Select the desired domain name from the drop down at the pop-up window
  4. Click Save changes

Thank you for stopping by.✌

Active Directory – Decoding UserAccountControl Attribute Values

In Active Directory, When we open properties of an user account, click the Account tab, and then either check or uncheck boxes in the Account options dialog box, numerical values are assigned to the UserAccountControl attribute. This UserAccountControl attribute determines the state of an account in the AD domain: active or locked, Password change at the next logon is enabled or not, if users can change their passwords and other options.

UserAccountControl Attribute in AD

To view user accounts,

  1. Click Start –> Programs
  2. Open Administrative Tools
  3. Click Active Directory Users and Computers
    • Or run dsa.msc from run window
  4. Search for a user and right-click and select Properties
  5. Click on Account tab

The Account Options section has the following options,

  • User must change password at next logon
  • User cannot change password
  • Password never expires
  • Store password using reversible encryption
  • Account is disabled
  • Smart card is required for interactive logon
  • Account is sensitive and cannot be delegated
  • User Kerberos DES encryption types for this account
  • This account supports Kerberos AES 128 bit encryption
  • This account supports Kerberos AES 256 bit encryption
  • Do not require Kerberos preauthentication

Each of these user account options is 1 (True) or 0 (False) and are not stored as separate AD attributes, instead the UserAccountControl attribute is used. The flags are cumulative. The total value of all options are stored in the value of UserAccountControl attribute.

To determine the current value of the attribute,

Using PowerShell,

$user = Read-Host "Enter user's logon"
Get-ADuser $user -properties * | Select name, UserAccountControl | ft

Using dsa.msc,

  1. dsa.msc from Run window
  2. Search for a user and right-click and select Properties
  3. Click on Attribute Editor tab
    • If you are missing this tab, Click View in the Active Directory Users and Computers window and select Advanced Features

In this example, the value of the attribute is 0x200 (decimal value is 512).

The following table lists possible flags that can be assigned to an account. Each flag corresponds to a certain UserAccountControl bit, and UserAccountControl value equals the sum of all flags.

UserAccountControl FlagHexadecimal ValueDecimal Value
SCRIPT0x00011
ACCOUNTDISABLE0x00022
HOMEDIR_REQUIRED0x00088
LOCKOUT0x001016
PASSWD_NOTREQD0x002032
PASSWD_CANT_CHANGE0x004064
ENCRYPTED_TEXT_PWD_ALLOWED0x0080128
TEMP_DUPLICATE_ACCOUNT0x0100256
NORMAL_ACCOUNT0x0200512
INTERDOMAIN_TRUST_ACCOUNT0x08002048
WORKSTATION_TRUST_ACCOUNT0x10004096
SERVER_TRUST_ACCOUNT0x20008192
DONT_EXPIRE_PASSWORD0x1000065536
MNS_LOGON_ACCOUNT0x20000131072
SMARTCARD_REQUIRED0x40000262144
TRUSTED_FOR_DELEGATION0x80000524288
NOT_DELEGATED0x1000001048576
USE_DES_KEY_ONLY0x2000002097152
DONT_REQ_PREAUTH0x4000004194304
PASSWORD_EXPIRED0x8000008388608
TRUSTED_TO_AUTH_FOR_DELEGATION0x100000016777216
PARTIAL_SECRETS_ACCOUNT0x0400000067108864

The userAccountControl value is calculated as,

NORMAL_ACCOUNT (512) + ACCOUNTDISABLE (2) = 514

NORMAL_ACCOUNT (512) + DONT_EXPIRE_PASSWORD (65536) + ACCOUNTDISABLE (2) = 66050

To list all active users,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=512)" | Select UserPrincipalName,userAccountControl | ft

To list all disabled user accounts,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=514)" | Select UserPrincipalName,userAccountControl | ft

To list accounts with a non-expiring password,

Get-ADUser -Properties * -ldapFilter "(useraccountcontrol=66048)" | Select UserPrincipalName,userAccountControl | ft

Here are the default UserAccountControl values for the certain objects:

  • Typical user: 0x200 (512)
  • Domain controller: 0x82000 (532480)
  • Workstation/server: 0x1000 (4096)

Decode UserAccountControl Values

To fully decode UserAccountControl bit field we can use this PowerShell script,

Add-Type -TypeDefinition @'
[System.Flags]
public enum UserAccountControl{
	SCRIPT = 1,
	ACCOUNTDISABLE = 2,
	BIT_02 =  4,
	HOMEDIR_REQUIRED = 8,
	LOCKEDOUT = 16,
	PASSWD_NOTREQD = 32,
	PASSWD_CANT_CHANGE = 64,
	ENCRYPTED_TEXT_PWD_ALLOWED = 128,
	TEMP_DUPLICATE_ACCOUNT = 256,
	NORMAL_ACCOUNT = 512,
	BIT_10 = 1024,
	INTERDOMAIN_TRUST_ACCOUNT = 2048,
	WORKSTATION_TRUST_ACCOUNT = 4096,
	SERVER_TRUST_ACCOUNT = 8192,
	BIT_14 = 16384,
	BIT_15 = 32768,
	DONT_EXPIRE_PASSWORD = 65536,
	MNS_LOGON_ACCOUNT = 131072,
	SMARTCARD_REQUIRED = 262144,
	TRUSTED_FOR_DELEGATION = 524288,
	NOT_DELEGATED = 1048576,
	USE_DES_KEY_ONLY = 2097152,
	DONT_REQ_PREAUTH = 4194304,
	PASSWORD_EXPIRED = 8388608,
	TRUSTED_TO_AUTH_FOR_DELEGATION = 16777216,
	PARTIAL_SECRETS_ACCOUNT = 67108864
}
'@

Which can be used like this to decode the bits,

If you want to display all flags that are set in UAC,

Get-AdUser -Filter * -Properties UserAccountControl | select name, @{n='UAC';e={[UserAccountControl]$_.UserAccountControl}}

This script can also be used to determine UserAccountControl value for specific AD accounts,

$user = Read-Host "Enter user's logon"
Get-ADuser $user -properties * | select name,UserPrincipalName, @{n='UAC';e={[UserAccountControl]$_.UserAccountControl}}

Update UserAccoutControl Attribute in AD using PowerShell

To change UserAccountControl attribute in AD using PowerShell, we can use Set-ADUser, Set-ADComputer and Set-ADAccountControl cmdlets,

$user = Read-Host "Enter user's logon"
Set-ADAccountControl -Identity $user –CannotChangePassword:$true -PasswordNeverExpires:$true

or

$user = Read-Host "Enter user's logon"
Set-ADUser -Identity $user –CannotChangePassword:$true -PasswordNeverExpires:$true

Set a specified computer to be trusted for delegation,

$Computer = Read-Host "Enter computer or server name"
Set-ADAccountControl -Identity $Computer -TrustedForDelegation $True

or

$Computer = Read-Host "Enter computer or server name"
Set-ADComputer -Identity $Computer -TrustedForDelegation $True

The user account attribute can also be updated using the Set-ADUser cmdlet. In this below example, I’m enabling user account,

$user = Read-Host "Enter user's logon"
Set-ADUser $user -Replace @{UserAccountControl = 512}

Hope this post helped you get a better understanding of the UserAccountControl attribute.

Thank you for stopping by ✌

PowerShell – Generate and email list of new users created in AD – Updated

If you don’t have an AD user provisioning tool implemented in your environment, I’m sure most of your user provisioning and de-provisioning is done using PowerShell scripts which helps in reducing the amount of time consumed in this process.

You probably are bombarded with requests from various departments in your organization to provide them with a list of new users who were created for various reasons.

This script can be automated by securely storing the credentials and running a scheduled task that runs on a specific day. Don’t store your admin or any credentials in any of your scripts.

You can use ConvertFrom-SecureString command to get an encrypted standard string and ConvertTo-SecureString to simply reverse the process by importing the data from your file and then create a PSCredential object.

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

$User = "AdminUser@acme.com"
$File = "C:\Temp\Password.txt"
$MyCredential=New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, (Get-Content $File | ConvertTo-SecureString)

In this above method, the point of converting password to a SecureString and storing it in a file is to keep it out of plain text in PS scripts so that it’s not as easily discovered. This can be easily decrypted and not recommended.

You can use the Microsoft.PowerShell.SecretManagement and Microsoft.PowerShell.SecretStore PS modules which I’ve covered in a later post.

​$Days = -7
$Maxdate = (Get-Date).addDays($Days) 
$CurrentWeekNumber = Get-Date -UFormat %V

$dateformat = "dddd MM/dd/yyyy"
$subjDate = Get-Date $Maxdate -Format $dateformat

$NewUsers = Get-ADUser -filter { whencreated -ge $Maxdate} -Properties EmailAddress, co, Description | Select-Object -Property GivenName, SurName, DisplayName, Description, co, EmailAddress # Gathering recent New AD Users

if ($NewUsers) # If there are more than one new user created in last $Days, prepare to send a mail
    {
    $MailBody = $NewUsers | ConvertTo-Html -Fragment
    
            $MailParams = @{Body       = $mailBody | Out-String
                            BodyAsHtml = $true
                            From       = "AD-Admin@acme.com"
                            To         = "jsmith@acme.com" # separate with comma for multiple users. "jdoe@acme.com", "jroe@acme.com"
                            SmtpServer = "smtp.acme.com"
                            Subject    = "New users for the week : $CurrentWeekNumber | Week Starting - $subjDate"
                            Encoding   = "UTF8"
                            Priority   = "Normal" # Accepted values: Normal, High, Low
                            #Port      = xxxx #If not 25
                            Credential = $(Get-Credential)
                            }
    Send-MailMessage @MailParams
    }

Hope this script was useful is generating weekly reports of newly created AD users.

Thank you for stopping by. ✌