This has been on my To-Do list for such a long time and because of Covid-19 I have finally found the hours required to get this done. A while back I received two Yubico and never got around to testing them 🙁 naughty I know. So let’s look at Yubico;
Microsoft and Yubico have been created a path for a passwordless future for organizations of all shapes and sizes. With a technology standard called FIDO2 and U2F which Yubico co-authored with, Microsoft and Google. Yubico became a founding member of the FIDO Alliance.
How does it all work, I hear you
The Yubikey supports multiple methods for authentication, enabling and the same key to be used across services and applications. With an out of the box native integration for the Microsoft environment provides a rapid deployment.
The user plugs the FIDO2 security key into their computer.
Windows detects the FIDO2 security key.
Windows sends an authentication request.
Azure AD sends back a nonce.
The user completes their gesture to unlock the private key stored in the FIDO2 security key’s secure enclave.
The FIDO2 security key signs the nonce with the private key.
The primary refresh token (PRT) token request with signed nonce is sent to Azure AD.
Azure AD verifies the signed nonce using the FIDO2 public key.
Azure AD returns PRT to enable access to on-premises resources.
Select Security InfoClick Add MethodSelect Security Key –> AddSelect USB devicePress NextInsert your Security Key into one of your USB ports.Specify a security key PINTouch the button on the security keyProvide a name to identity the security keyAll Done!!
Did you know that Enforce Cloud Password Policy for Password Synced Users exists? and that it is also disabled by default. This means that any user that you sync using Azure Active Directory Connect will not have an expiration timer set against their account. This can be a nightmare for an organization that has strict password policies.
So let’s switch it on and get all your synced users applied
First of all, you will need to run the following command after you have ran Connect-MsolService
Imagine, your company has just been brought by another organization. The acquiring company what you using Office 365 services as quick as possible so they create you a Cloud Only Account to leverage their existing tenant. Now imagine, you are 12 months into the acquisition and you want to have a single sign-on experience for your end-users.
Now you have a dilemma on your hands, as your primary user principle name on-premises is different from your UPN in the Azure Tenant.
WHAT DO YOU DO!!!
What did I do??
You engage your Windows PowerShell Console in Administrator Mode and teleport in the Get-ImmutableID.ps1 PowerShell script
Engage!!! New Features coming soon!!
With this script, you are able to download all the ImmutableIDs from your local Active Directory into a single CSV file to your desktop.
Please Note:
If there are additional fields you would like to see in this script, please submit an update via Github or email alerts@blogabout.cloud
You will need some manual intervention matching your on-premises AD Users and AAD Users but once this is complete you will be able to run the following script to set the ImmutableID in your Azure Active Directory.
ForEach($user in $csv1){
Try
{ Get-AzureADUSer -ObjectId $user.primarysmtpaddress -ErrorAction Ignore Write-Host "Success:",$user.PrimarySMTPAddress,"was found and set with",$user.ImmutableID -BackgroundColor DarkGreen
Set-AzureADUser -ObjectID $user.PrimarySMTPAddress -ImmutableID $user.ImmutableID }
catch
{ Write-Host "ERROR:",$user.PrimarySMTPAddress,"could not be found" -BackgroundColor DarkRed }
Stop-Transcript
While this is a tried and tested in my own deployments, I am unable to take responsibility for any potential issues you may encounter. Keep safe with responsible scripting, always test in a lab environment first.
I have been recently working with a customer and errors within AAD look which pointed to an issue with Device Writeback not being enabled on Azure Active Directory Connect.
But how do you check if the device is writing back? Well, I’m glad you asked. First of all, we need the Device ID which is obtain running a cmd via command prompt.
dsregcmd /status
Once you have this information you will need to run the following command using PowerShell on one of your domain controllers.
This post will explain how to merge an on-premise AD user objects with an already existing Azure AD user using hard-match with the sourceAnchor/immutableID property. I have recently experience this issue with a customer who was merging their contoso.com addresses to their fabikam.com Azure AD account.
As you can imagine this isnt a simple process but with the power of PowerShell and good old fashion “I can” attitude, this merger was a complete success.
Before we continue I would like to state that there are two methods that Azure AD Connect will use to match existing users; – Soft-Match – Hard-Match
When you install Azure AD Connect and you start synchronizing, the
Azure AD sync service (in Azure AD) does a check on every new object and
try to find an existing object to match. There are three attributes
used for this process: userPrincipalName, proxyAddresses, and sourceAnchor/immutableID.
Soft-Match
Soft-Match will use the properties userPrincipalName and proxyAddresses to match existing users.
Hard-Match
Hard-Match will use the property sourceAnchor/immutableID. You can only select which property is used as sourceAnchor during the installation of Azure AD Connect as described in their documentation.
If the selected sourceAnchor is not of type string, then Azure AD Connect Base64Encode the attribute value to ensure no special characters appear.
Important Note
By default, Azure AD Connect (version 1.1.486.0 and older) uses objectGUID as the sourceAnchor attribute. ObjectGUID is system-generated.
So we only have to set the immutableID property of the existing user in our Azure AD to the Base64 encoded string of the ObjectId of the user in our on-premise AD. If you already synchronized your Active Directory then you probably have two users with the same name in your Azure AD. Just follow the following steps to finally merge these users:
You have to execute the following PowerShell commands on the machine with your on-premise AD and the Azure PowerShell commands via the Azure Cloud Shell.
In my scenario, I had a customer that the Email Address on the Active Directory Account didn’t match the PrimarySMTPAddress in Azure AD, however, the PrimarySMTPAddress in Exchange was correct. So I need to match both objects using the PrimarySMTPAddress from Exchange And Azure to set the ImmutableID. I create a PowerShell to gather PrimarySMTPAddress from Exchange along with the required information from Active Directory
If you have synced users and have duplicate accounts you will need to remove these before looking at continuing. A simple way of doing this changing the OU you have synced which has caused the duplicate or you can use the Azure Portal
Deleted Users
But if you love PowerShell the following command is also possible as well.
Remove-AzureADUser -ObjectId <objectid>
3. Get Azure AD User ObjectID
One of the key requirements for this post is that we require the ObjectID of the Azure Active Directory account we are looking to match against. The following PowerShell command prints a list of all users with their ObjectId and exports to your desktop.
Once you have a single pane of glass with your ObjectID and ImmutableID matched within a csv, you will now be able to set all the ImmutableID for all your Azure AD Objects.
5. Set immutableId for Azure AD User in Bulk
Run the following script against Azure AD using PowerShell.
$Filepath1 = $env:USERNAME\desktop\immutableid.csv
$csv1 = Import-Csv -Path $filepath1
#endregion
Start-Transcript $env:USERPROFILE\desktop\PilotUser.csv
foreach($user in $csv1){
Set-AzureADUser -ObjectID $user.ObjectId -ImmutableID $user.ImmutableID
Write-Host $user.PrimarySMTPAddress,"with ObjectID"$user.ObjectId," has been set with ImmutableID",$user.ImmutableID
}
Stop-Transcript
6. Start AD Sync
You can now resync the OUs which had all the user accounts and hard matching will be completed using the newly set ImmutableID.
In this example I have local Active Directory with AAD Connect installed one of the Azure Region, which sync users and password hash to Office 365. I have now decided to migrate the authentication from local Active Directory to Office 365 and decommission on-premises Active Directory.
Azure Active Directory Connect Diagram
In order to transition from on-premises “Synced Identity” to “In Cloud Identity”, we will need to complete the following process.
IMPORTANT NOTE!!!!!
When deactivating Directory Sync it may take up to 72 hours before it can reenable depending on the size of your production network. All users will keep their current password but all synchronized objects are removed from Azure AD, please keep this in mind.
To check if you can reenable Directory Sync you will need to run Get-MSOLCompanyInformation. This will show you the detailed information. and the last four fields are the most important in this scenario as this will indicate if Directory Sync can be reenabled as the status is False. DirectorySynchronizationEnabled LastDirSyncTime LastPasswordSyncTime PasswordSynchronizationEnabled
In my scenario, Directory Sync was able to be reactivated after 8 hours. The customer I was working with accepted the potential risk in order to complete this work.
Sign into the AAD Connect Server and Sync the Delta
The following command performs a sync of all AD Objects before attempting to convert into Cloud Only.
Start-ADSyncSyncCycle Delta
Turn off AAD Connect Sync
The following command turns off Azure Active Directory Connector while we perform all the following tasks. In this post I have outlined all steps which can be taken to convert AD Users account into Cloud Only.
Set-MsolDirSyncEnabled -EnableDirSync $false
Convert Single User to Cloud Only
The following command converts a single user into a Cloud Only account
Once you have completed all the required conversions of AD accounts to Cloud. Head back to your local Active Directory, move user(s) to an OU that isn’t synchronized using AADC.
This helps you as an IT Pro understand who has been converted at a quick glance now not worry about using PowerShell to discovery who is or isn’t.
The following command turns on Azure Active Directory Connector now that we have converted the users accounts to Cloud Only
Set-MsolDirSyncEnabled -EnableDirSync $true
Enable Force Sync if the Sync didn’t work
Start-ADSyncSyncCycle -PolicyType Initial
If you are using an ADFS Server there is an additional step providing you have moved all your users to the Cloud. You will need to change the Federated Domain to Standard Domain
All that is left now is to log in as one of the converted users to prove Single Sign-On is working and logon as a Global Admin into Office 365 to check the sync status of the users has a pretty cloud for “In-Cloud”
What is DBEB? It is a solution that allows an organization to reject message for invalid recipient at the service network perimeter. DBEB enables your Office 365 Global Administrator to add mailed-enabled recipients to Office 365 and block all messages sent to email address that aren’t present in Office 365.
Valid messages are then subject to the rest of the service filtering layers which are;
Antimalware Antispam Mail Flow Rules (otherwise knows as Transport Rules)
Invalid messages are blocked before filtering even occurs, and a non-delivery report (also known as an NDR or bounce message) is returned to the sender. The NDR looks like this:
In hybrid environments, in order for DBEB to work, email for the domain must be routed to Office 365 first (the MX record for the domain must point to Office 365).
Configuring DBEB
First of all, you need to verify that your accepted domain EXO is an Internal Relay, this is done by going to Exchange Admin Console –> Mail Flow –> Accepted domains.
If, your domain type is Authoritative you will need to click the edit button and set to internal relay
Adding your users to Office 365
Directory synchronization: Add valid users to Office 365 by synchronizing from your on-premises Active Directory environment to Azure Active Directory in the cloud. For more information about how to set up directory synchronization, see “Use directory synchronization to manage recipients” in Manage Mail Users in EOP.
In the EAC, go back to Mail flow > Accepted domains.
Select the domain and click Edit. Set the domain type to Authoritative. Choose Save to save your changes, and confirm that you want to enable DBEB.
Until all of your valid recipients have been added to Exchange
Online and replicated through the system, you should leave the accepted
domain configured as Internal relay. Once the domain type has been changed to Authoritative,
DBEB is designed to allow any SMTP address that has been added to the
service (except for mail-enabled public folders). There might be
infrequent instances where recipient addresses that do not exist in your
Office 365 organization are allowed to relay through the service.
If there’s one thing most IT department are not great at its removing Exchange Mailboxes for Disabled Users. So here’s a quick Powershell win to determine who within your Exchange organisation has a mailbox and a disabled AD account.
Before the joys of Export-CSV there used to be another way of dumping Active Directory data to CSV using again native tooling. In a recent project I have had to rediscover the old ways and go back to school to learn the required switches, which I am now going to share with you all.
Switch
Description
-a
UserDistinguishedName
Password. If you must use these switches, then treat -a and -b as
a pair. A likely scenario is that you are logged on as
non-administrator and wish to run CSVDE against your Active Directory.
As a non-administrator, you would get an error unless you employ these
switches to connect with the correct credentials
-b
UserDistinguishedName
Password. If you must use these switches, then treat -a and -b as
a pair. A likely scenario is that you are logged on as
non-administrator and wish to run CSVDE against your Active Directory.
As a non-administrator, you would get an error unless you employ these
switches to connect with the correct credentials
-c
String1 String2. This
switch replaces all olddomain names in String1 with newdomain names
String2. Could be used to change all dc=oldom distinguished name in the
export domain (String1) with dc=newdom of the import domain (String2).
-d
This is useful filter switch for
when you want to export from just one OU. Use the -d switch to set the
root directory for the export. For example, if you are only interested
in an OU called Newport type, CSVDE -f export.csv -d
“OU=mycompany,DC=domain,DC=com”.
Note, there are no spaces between domain,DC=com.
-f
filename is a mandatory switch
for both import and export. Simply specify the .csv file for transfer
data. It makes life easier if this file is in the same directory as you
issue the CSVDE command. Here is an export example CSVDE
-f export.csv
-g
Omits paged
searches. I have never bothered with this switch.
-i
Switches CSVDE to import
mode. For example, CSVDE -i -f export.csv. Remember that the default mode is export, in which case
it’s just plain CSVDE -f FileName.csv
-j
Path Sets the log file
directory. The point of a log file is that it’s permanent where as the
-v verbose mode is ephemeral. -j creates one or two log files. It
always creates a file called csv.log, additionally it creates csv.err if it encounters
any errors.
-j
Trap: As far as I can see
without the -j switch, CSVDE will not create a log file at all. I
mention this as other documentation suggests that you are just setting the
path, in my opinion, with -j you are creating the file as well as setting its
path.
-k
Useful for ignoring simple
errors: “Object already exists,” “Constraint violation,”
and “Attribute or value already exists.” I almost always use
this switch as part of the CSVDE import command
-l
LDAP Attributes. On
the one hand, I think of L for list, on the other hand I think of -l as a
column-wise filter. What this switch does is export only the LDAP
properties that you are interested in and ignores the rest of the attributes.
Example CSVDE -f export.csv -l “DN,
objectclass, objectcategory, givenName, sn”.
Note the position of speech marks and commas.
-m
Another column-wise
filter. Omits Active Directory properties such as the ObjectGUID, objectSID, pwdLastSet
and samAccountType
attributes.
I hope these switches help you, like they have helped me and credit to all the previous bloggers which enabled me to get this list together.
Sometimes Get-ADUser just isn’t enough if you are working thousands upon thousands of AD Objects. In a recent scenario, while resolving an Active Directory Health issue. I needed the ability to be able to compare AD Objects from 2 Active Directory Domains from within a resource forest.
What is ADSISearcher?
ADSISearcher is a command line driven LDAP Lookup procedure has the ability to query Active Directory. As ADSISearcher looks up Active Directory it enables a faster discovery of the required AD Objects.
My scenario
I need to ensure CustomAttribute10 in Child1.domain.com matches CustomAttribute10 in Child2.domain.com, yes I could use Get-ADUser | export-csv but this has proved to take to long and needed a faster solution.
ADSISearcher has proved to reduce the time required to execute this script and dumping out to a transcript file with “,” separating the text allows the information to be imported to excel if required.
The script
Clear-Host Write-Host "You are currently running Version 1.0" -BackgroundColor DarkGray [string] $Menu = @' ┌─────────────────────────────────────────────────────────────┐ ADSISearcher for CustomAttribute10 Created by @thewatchernode └─────────────────────────────────────────────────────────────┘ '@ Menu $Menu Transcript Start-Transcript -Path "$env:userprofile\Desktop\Child1vsChild2.txt" Start Time $start = [datetime]::Now region Client Array $Child1LDAPFilter = '(objectclass=user)' $PageSize = 1000 $Child1DN = 'DC=child1,DC=domain,DC=com' $Child1SB = 'DC=child1,DC=domain,DC=com' $Child1Searcher = [ADSISearcher]('{0}' -f $child1LDAPFilter) $Child1Searcher.SearchRoot = [ADSI]('GC://{0}' -f $Child1SB) $Child1Searcher.SearchRoot = [ADSI]('GC://{0}' -f $child1DN) $Child1Searcher.PageSize = $PageSize $Child1Objects = $Child1Searcher.FindAll() endregion region Collab Array $Child2SB = 'DC=child2,DC=domain,DC=com' $Child2DN = 'DC=child2,DC=domain,DC=com' endregion region Client vs Collab Foreach($Object in $child1Objects){ $childca10 = $Object.Properties.'customattribute10' $Child2LDAPFilter = "(objectclass=user,customattribute10=$childca10)" $child2Searcher1 = [ADSISearcher]("{0}" -f $child2LDAPFilter) $child2Searcher1.SearchRoot = [ADSI]("GC://{0}" -f $Child2SB) $child2Searcher1.SearchRoot = [ADSI]("GC://{0}" -f $Child2DN) $child2Searcher1.PageSize = $PageSize #$AllObjects1 = $collabSearcher1.FindAll() $nullvalue = $object.Properties.'customattribute10' if ($nullvalue -eq $null) { Write-Host 'INFO, Null Value Found in Child Domain 1,' $Object.Properties.samaccountname -BackgroundColor Red } else { try { ($Object.Properties.'customattribute10' -eq $child2searcher1.Properties.'customattribute10') Write-Host 'Skipping, Attribute match found in Child domain 2 using Child domain 1,' $Object.Properties.samaccountname -ForegroundColor Green } catch { Write-Host 'INFO, No Attribute match found in Child domain 2 using Child domain 1,' $Object.Properties.samaccountname -BackgroundColor Red } } } endregion Stop Transcript Stop-Transcript End Time $end = [datetime]::Now $resultTime = $end - $start Write-Host ('Execution : {0}Days:{1}Hr:{2}Min:{3}Sec' -f $resultTime.Days, $resultTime.Hours, $resultTime.Minutes, $resultTime.Seconds)