With Azure AD B2B collaboration, we can invite guest users into our tenant to allow them to access M365 apps and other Azure AD SSO integrated apps. There are multiple ways to invite external users into our Azure AD tenant. In this post, I’ll go through what I worked on recently to invite a bunch of external users in to one of the tenants I manage.
$GuestName = Read-Host "Enter name of user being invited"
$GuestEmail = Read-Host "Enter email address of user being invited"
New-AzureADMSInvitation -InvitedUserDisplayName $GuestName -InvitedUserEmailAddress $GuestEmail -SendInvitationMessage $True -InviteRedirectUrl "http://myapps.microsoft.com"
To bulk invite users from a csv file, this below script will work. This script checks to make sure if the user is already invited and also includes a custom message you can include in the invite.
How the csv file looks like,
$GuestUsers = Import-csv "C:\tmp\InviteGuestUsers\GuestUsers.csv"
$invitationBody = @"
Hi,
Please accept this invitation to join our organization.
If you have any questions, please contact our helpdesk at
support@internaldomain.com
"@
$invitemessage = @{customizedmessagebody = $invitationBody}
ForEach($GuestUser in $GuestUsers) {
$GuestUserEmail = $GuestUser.GuestEmail
$GuestUserName = $GuestUser.GuestName
if ((Get-AzureADUser -SearchString $GuestUserEmail).Length -le 0) {
$Invite = New-AzureADMSInvitation -InvitedUserDisplayName $GuestUserName -InvitedUserEmailAddress $GuestUserEmail -SendInvitationMessage $True -InvitedUserMessageInfo $invitemessage -InviteRedirectUrl "http://myapps.microsoft.com"
Write-Host "Guest user $GuestUserName invited" -ForegroundColor Green
} else {
$status = Get-AzureADUser -filter "Mail eq '$GuestUserEmail'" | Select -Expandproperty UserState
Write-Host "Guest user $GuestUserName already invited - Guest account exists in tenant and invite status is $status" -ForegroundColor Red
}
}
To list all guest users in the tenant and their invitation acceptance status:
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.
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,
Click Start –> Programs
Open Administrative Tools
Click Active Directory Users and Computers
Or run dsa.msc from run window
Search for a user and right-click and select Properties
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.
Search for a user and right-click and select Properties
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.
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.
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.
I recently faced an issue where users are provisioned to AD using an user system/tool that applies the Country value to the user while creating the account but it doesn’t have the ability to update the countryCode and co attributes. And I had few thousand users with no value set in the co and countryCode attributes.
In this post, I’ll cover the details on how came up with a workaround for this issue.
The AD attributes we are dealing with here are,
c (Country-Name): ISO-3166 2-digit string value
countryCode (Country-Code): ISO-3166 Integer value
co (Text-Country): Open string value
When we pick a country name from the drop-down in the Active Directory users and computers GUI, the c, co and countryCode attributes are automatically assigned.
With PowerShell, we can use the Set-ADUser to assign the c attribute to the user,
In this method, no values are assigned to the co and countryCode attributes automatically like how it happened while updating in the GUI. Below are the screenshots of the user properties after running the above cmdlet.
We can use this method to assign all three values for the user,
In my scenario, the users provisioned by the tool already had the c attribute value set. I exported all users from the AD domain, determined the countries and then used the below script to update the co and countryCode attributes.
This table at the end of this post provides all countries in the AD address tab Country/region drop-down list. You can use this to update the above script according to your needs. I also made this script to be run as a scheduled task to run once a week to update the new users created throughout the week. Not a perfect solution but replacing the user provisioning tool wasn’t an option in my case, hence I stuck with this method.
Hope this post helped you in better understanding the c, co and countryCode attributes in AD and an easier method to update it.