This posting is ~1 year years old. You should keep this in mind. IT is a short living business. This information might be outdated.
In the previous blog post I have showed you how to interactively log in into the Microsoft Graph API. You had to enter a username, a password, and you had to enter a second factor. This is typically not want you want if you want to automate things. But there is another way to get access to the Microsoft Graph API.
Create an app registration
To get access, you have to register an app in your AzureAD. Go to your Azure portal and select “App registration” from the “Manage” section. Add a new registration by clicking to “New registration”.
Give your registration a meaningful name. Usually, only accounts in your AzureAD should be able to use this app.
The next step is to add permissions. This is equivalent to defining permission scopes during an interactive login. Make sure that you only follow the least-privilege method. In contrast to delegate access, this login type is truly limited to the permissions you grant in this step.
Select “Microsoft Graph” from the list.
Choose “Application permissions”.
Then select the necessary permissions.
Grant the permissions and select “Grant admin consent”. This step is pretty important. You, the admin, consent to the selected permissions. There is no further question to consent to the enduser.
Login with a client secret
But before we can use, we have to add something to use in the authentication process. There are two different methods to authenticate:
Certificate, or
client secret
A client secret is okay for test or dev environments. But I would not recommend the usage in a prod environment. You have to add this secret to a script or something, which is hard to protect. Create a new client secret. Please note, that a client secret has a lifetime. And make sure that you copy it. Tge client secret will be hidden later!
Make sure that you give your client secret a descriptive name.
The usage of a client secret is a two-step process. We need to get an access token, using the client secret, and use the token to connect to the Graph API. To get an access token, you need to install the Microsoft Authentication Libraries (MSAL) PowerShell module.
As you can see, this service principal login was made by the client secret.
Login with a certificate
Something more appropriate for a prod environment, is to use a certificate for the login. You can create a self-signed certificate, or use any other kind of X.509 certificate to authenticate. I used a S/MIME certificate in this case.
Make sure that you only upload the public key!! The certificate with the private key must be stored in the computer or user certificate store on the machine from which you want to access.
Upload the public key of a certificate.
Next step is to use the certificate hash during the login process:
This posting is ~1 year years old. You should keep this in mind. IT is a short living business. This information might be outdated.
There is a new API in town… naa, not really new, but the Microsoft Graph API will replace most, if not all, other Azure AD/ Microsoft 365 APIs. Actually, Microsoft has planned to retire Azure AD Graph API and ADAL in Juni 2022. Now they have postponed this date to somewhere after December 2022. This will give you some extra time to refactor your PowerShell scrips and move them to use the PowerShell SDK for Graph.
What is Microsoft Graph? Microsoft Graph is the spider web that connects everything in Microsoft 365. One part of Graph is a single and unified API endpoint, which allows you to access and manage Azure AD and Microsoft 365 services, such as Teams and Exchange Online, Intune etc.
Instead of different endpoints, the Graph API uses a single endpoint (https://graph.microsoft.com/v1.0), which is the pretty nice thing if it comes down to Firewall rules and traffic management. This single endpoint, together with a single access token, allows you to manage all M365 services using REST API calls. So you don’t have to use the PowerShell SDK, you can also use Python or curl. Furthermore, the Microsoft Graph PowerShell SDK is Open Source, it offers cross-platform support (Linux, MacOS, Windows), and its available on PowerShell 5.1 nd above. This is a pretty important thing for me. Now I can use a single PowerShell Module to manage all my M365 services. This was PITA in the past. Depending on the service, I had to use different PowerShell modules, and I had to switch between PowerShell and PoSh Core.
Install the Microsoft Graph PowerShell SDK
The installation is pretty simple. All you need is
at least PowerShell 5.1 or later,
.NET 4.7.2 or later, and
the PowerShell script execution policy must be set to remote signed or a less restrictive execution policy
The installation is done by calling Install-Module.
Install-Module Microsoft.Graph -Scope CurrentUser
Sure, you can also use -Scope AllUsers, but I prefer to install PowerShell modules in my CurrentUser context. That’s it! Now let’s authenticate to the Graph API.
Authentication & Authorization
First of all: The Graph API knows two types of authentication:
delegated access, and
app-only access
Delegates access allows an application to act as a specific user, where as application access allows an application to act as its own entity. If you want that an API call is executed with the users permissions, then you should use delegated access. If you want to run scripts, or a service, then you want to use app-only access. Some API call are only possible with delegated access, some calls can only be made with app-only access, and some calls can be made with either of the two methods.
As part of the login process, you must define the requested permission scope. This is to ensure that the least possible privileges are used. For example:
As you can see, this command will open a connection to the Graph API and you must consent the requested permissions after entering valid user credentials. Side note: Graph offers all the modern authentication stuff that we want to use today.
The tenant is specified by the singed-in user. If you want to connect to a specific tenant (to avoid usage of a cached access token), then you can add –TenantId <TenantId> to the command above.
As you can see, I now have a working connection using the Graph API using delegated access and with the requested permission scopes.
This map of Azure AD and MSOnline cmdlets was pretty helpful when playing around with Graph.
If you want to run a script, you might want to register an app in your tenant. This allows you to define the required permission scopes as properties of the app itself. I will show this in a separate blog post. This blog post will also cover the certificate-based authentication, as well as the authentication using a client secret.
— BleepingComputer (@BleepinComputer) July 7, 2022
My first reaction: WHAT. THE. FUCK?! Microsoft added this as feature 88883 in februrary 2022 to the Microsoft 365 roadmap, and I was pretty happy about this feature. Let’s take a look at this change.
The intention for this change was to add an extra layer of security in case that a user tried to open a downloaded file or an email attachment. The primary reason for this was, that Office documents with VBA were the main entry point for malware deployments. A highly customized email is sent to an employee with the goal, that the user opens the document. The embedded VBA code then is used to download and execute the malware.
Now, this highly wanted change is rolled back. IMHO there is only one reason for this: Customer complains about broken business processes. It’s that simple..
I’m not an InfoSec guy, but I know how to keep Ransomware gangs out of my network. There are three very efficient ways to do this:
Implement admin tiering, and avoid giving users admin permissions
Quarantine emails with attachments, and last, but not least
avoid to run unsighed office macros
Sure, you can allow users the use of Office documents with macros, but please make sure that these macros are signed with a proper code singing certicate, and stop allowing users to open documents with unsigned macros.
I really don’t get it why Microsoft is unable to push such an important change to the public. Of course, Microsoft isn’t responsible if Conti tears your store apart, but at least they could make it a little harder for you to let that happen…
No responsible person can tell me today “Sorry, we couldn’t do anything about this cyber attack”. But I also think that vendors should continue to turn off unsafe features. And if it breaks your business processes… yes, then you don’t deserve it any other way.
This posting is ~2 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
As part of a Office 365 tenant rebuild, I had to move a custom domain to the new Office 365 tenant. The old tenant was not needed anymore, and the customer had to move to a Non-Profit tenant for compliance reasons. So the migration itself was no big deal:
disable AzureAD sync
change UPN of all users
remove the domain
connect the domain to the new tenant
setup a new AzureAD sync
assign licenses
time for a beer
That was my, honestly, naive plan for this migration.
Disabling the AzureAD sync was easy. Even the change from ADFS to Password Hash Sync was easy. Changing the UPN for all users was a bit challenging, but the PowerSHell code in this article was quite helpful.
$users = Get-MsolUser -All | Where {$_.UserPrincipalName -like "*customdomain.tld"} | select UserPrincipalName
foreach ($user in $users) {
#Create New User Principal Name
$newUser = $user.UserPrincipalName -replace "customdomain.tld", "customdomain.onmicrosoft.com"
#Set New User Principal Name
Set-MsolUserPrincipalName -UserPrincipalName $user.UserPrincipalName -NewUserPrincipalName $newUser
#Display New User Principal Name
$newUser
}
But after this, I still was unable to remove the custom domain from the tenant. The domain was still referenced in the ProxyAddresses attribute, which was synced by the AzureAD sync…
Removing the domain from the users in the on-prem Active Directory was not solution. The users were already cloud-only because the sync was switched off. With this in mind my plan was to modify the cloud-only users in the tenant. To be honest: This solution worked in this specific case!
The customer was using Microsoft Teams Commercial Cloud trial licenses, so I had no Exchange Online to edit the proxy addresses. But luckily, the Exchange Online Management PowerShell Module was quite helpful.
This line of code gave me an idea how many users were affected… quite a lot… With my colleague Claudia I quickly developed some dirty PowerShell code to remove all proxy addresses that included the custom domain.
It tool about 45 minutes to modify ~ 2000 users. After this, I was able to remove the domain and connect it to the new tenant.
This solution worked in my case. Another way might be using the AzureAD sync itself, masking out the custom domain and wait until the domain is removed from all proxy addresses. But I didn’t tested this.
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
I just had a Teams call with a customer to resolve a strange mystery about Azure MFA.
The customer called me and explained, that he has a user with Azure Multifactor Authentication (MFA) disabled, but when he logs in with this account, he is asked to setup MFA. He setup MFA and was able to login according to their Conditional Access policies.
The user has MFA enabled and the second factor is an authenticator app on his phone.
Schrödinger’s MFA
The mystery is not a mystery anymore if you take into account that the first screenshot is the screenshot of the Per-User MFA.
The customer is using Conditional Access, therefore Security Defaults are disabled for his tenant. Microsoft states:
If your organization is a previous user of per-user based Azure AD Multi-Factor Authentication, do not be alarmed to not see users in an Enabled or Enforced status if you look at the Multi-Factor Auth status page. Disabled is the appropriate status for users who are using security defaults or Conditional Access based Azure AD Multi-Factor Authentication.
Conditional Access, or enabled Security Defaults, will force a user to enroll MFA, even if the per-user MFA setting is set to “disabled”!
You have to disable Security Defaults, and you have to disable Conditional Access in order to get per-user MFA reflect the current state of MFA for a specific user.
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
While migrating a customer from Exchange 2010 to Exchange 2016, I had to create an Exchange Hybrid Deployment, because the customer wants to use Microsoft Teams. Nothing fancy and I’ve did this a couple of times.
Unfortunantely the Hybrid Connection Wizard failed to create the migration endpoint. A quick check of the logs showed this error:
Microsoft.Exchange.MailboxReplicationService.MRSRemotePermanentException: The Mailbox Replication Service could not connect to the remote server because the certificate is invalid. The call to 'https://mail.contoso.com/EWS/mrsproxy.svc' failed. Error details: Could not establish trust relationship for the SSL/TLS secure channel with authority 'mail.contoso.com'. -->The underlying connection was closed: Could not establish trust relationship for the SSL/TLS secure channel. --> The remote certificate is invalid according to the validation procedure
The customer had not plans to move mailboxes to Exchange Online, so we didn’t care about this error. But the Calendar tab in Teams was not visible, and Teams logs stated that Teams was unable to discover the mailbox. A typical sign of a not working EWS connection.
It’s always TLS… or DNS… or NTP
The customer used a certificate from its own PKI, so it was not trusted by Microsoft. In addition, the Exchange was located behind a Sophos XG which was running Webserver Protection (Reverse Proxy). But this was not the main cause for the problems.
The root cause was the certificate from the customers PKI.
And therefore you should make sure to use a proper certificate from a 3rd CA for Exchange Hybrid Deployments. I really please every customer to stop using self-signed certificates, or certificates from their own PKI for external connections.
The customer has switched to a Let’s Encrypt certificate for testing purposes and the problems went away, without running the HCW again. He will now purchase a certificate from a 3rd party CA.
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
A couple of days ago, I wrote about our first steps to move our on-prem stuff to Azure. This post will cover how we adopted Office 365 and how we have started with our Azure deployment.
Our first step into Office 365 was Microsoft Teams. We needed a solution for calls (audio/ video) and chat. We skipped Skype 4 Business and started with Microsoft Teams.
Microsoft 2020 (c)
Our Microsoft Teams deployment was pretty simple: We used our Microsoft IUR Office 365 E3 plans. Microsoft Azure AD Connect was quickly deployed and the Microsoft Exchange Hybrid Connection Wizard did the rest. Some weeks later we deployed ADFS/ ADFS Proxy. We used this setup over several months and it was pretty slick and was working flawless. At this point, we only used Teams, Planner and OneDrive 4 Business (SharePoint).
Some months went by until we decided to move to Azure.
Resource groups in Azure
You can imagine a resource group (RG) as a container that contains one or more resources, like VMs, NICs, SQL instances etc. The resource group can contain all the resources for the solution, or only those resources that you want to manage as a group.
First question: What do we need to deploy?
The answer was easy:
in sum 9 VMs
VPN gateway
Recovery Services Vault
Automation Account
Log Analytics Workspace
Second question: One or multiple resource groups?
An easy rule of thumb is, that a resource group should contain only resources that share the same life cycle and sponsor.
Third question: Who needs delegated priviledges to manage this stuff?
In our case there was no need to fine-graded RBAC. All of our technical staff has a personalized admin account and should be able to do whatever is necessary.
To connect our on-prem network to Azure, we had to setup a Site-2-Site VPN. This was the first thing after creating our first resource group. We used a Gen 1 Basic VPN Gateway, which was sufficient for our needs (max 100 Mbit, no OpenVPN, no BGP).
Keep in mind to choose your networks and subnets wisely. If you need to deploy 9 VMs, don’t use 10.0.0.0/8. ;) In our case we added two network ranges with a single subnet in each network range. One for our server VMs, and a second subnet as gateway subnet.
VM Deployment
We deployed our VMs as B-Series VMs. A common mistake is to use the wrong VM size. Start small and right-size a VM if necessary. Most of our VMs are B2s (2 CPUs, 4 GB RAM). Only the Exchange (B4m), the management (B2ms) and the RDS server (B2ms) differ from this. This looks pretty small for Server 2019, but it is working pretty nice.
After deploying the VMs, we assigned static IP addresses to them. To our suprise most things in Azure are lacking proper IPv6 support. :( That hurt a lot.
For most VMs we used Standard HDDs instead of SSDs. Even for your file server, because the bottleneck is not the disk, it is the connection between clients and server. Beside this, we used managed disks for all VMs, and we deployed a second disk for data if necessary (Exchange, domain Controller, file server etc.).
If a server had a DNAT in our on-prem network, we deployed a public IP, and secured the access to it.
All VMs are connected to the same Network Security Group (NSG), which we use to get control over what a VM can reach, and who can access a VM.
Server Migration
Over a couple of days we moved more and more services to Azure, starting with our Domain Controllers, PKI and file services. These were low hanging fruits. The file server was easy because we already had a DFS namespace in place, so all we had to do were to change the DFS Links and point them to the new file server. The data was copied by using DFS replication.
DHCP was moved to our on-prem firewall. A printserver was not necessary any more. Windows Updates were switched back to download from Microsoft and Delivery Optimization.
The applications that were running on our Linux and Windows application server were also easy to migrate. After a couple of days we had our server workload running on Azure.
To get our ERP running, we deployed a single RDS host (quick deployment), and deployed our ERP as a remote app. It was too slow to use it over the VPN. Unfortunately the application lacks a proper database backend. :/ But as a remote app, it is working pretty good.
A bigger challenge was Exchange, but not because of the mailbox migrations.
Exchange Online
The migration to Exchange Online was pretty simple. Since our first HCW run, we used the central mail transport, so that all mails are received and sent by our on-prem mail gateway.
The mailbox migration was pretty easy and we had zero issues. Then we tried to switch the mail transport from central of Exchange Online. This was flawless too… except the fact, that our ticket system was unable to send e-mails.
Our ticket system relays its mail over our Exchange server. After switching the mail server in our ticket system to the new Azure based VM, the mails stuck in the outbound queue, even if the server tried to send the mail to our on-prem mail gateway. This quote from Microsoft explains the whole problem:
Starting on November 15, 2017, outbound email messages that are sent directly to external domains (such as outlook.com and gmail.com) from a virtual machine (VM) are made available only to certain subscription types in Microsoft Azure. Outbound SMTP connections that use TCP port 25 were blocked. (Port 25 is primarily used for unauthenticated email delivery.)
This change in behavior applies only to new subscriptions and new deployments since November 15, 2017.
This is the case for MSDN, Azure Pass, Azure in Open, Education, BizSpark, and Free Trial subscriptions!
If you created an MSDN, Azure Pass, Azure in Open, Education, BizSpark, Azure Sponsorship, Azure Student, Free Trial, or any Visual Studio subscription after November 15, 2017, you’ll have technical restrictions that block email that’s sent from VMs within these subscriptions directly to email providers. The restrictions are done to prevent abuse. No requests to remove this restriction will be granted.
If you’re using these subscription types, you’re encouraged to use SMTP relay services, as outlined earlier in this article or change your subscription type.
We accelerated our migration and disabled the central mail transport earlier than planned. Then we configured our Linux application server to authenticate against Exchange Online using SMTP Auth and SMTP Submission (587/tcp). For incoming mails, the mails are routed to the application server using a Exchange Online connector and a transport rule which matches to specific mail addresses.
The Azure based Exchange VM is only needed because we still have an Azure AD Connect running. Microsoft has planned to replace this by a new solution. And until this, we will run this Exchange 2016 in Azure. But it is not part of our mail flow.
Moving Azure AD Connect & decommissioning ADFS
Because we had to get rid of the ADFS server and ADFS Proxy, we deployed Pass-Through Authentication and Seamless SSO. Then we decommissioned the ADFS setup.
Moving Azure AD Connect was a bit quirky. We had conditional access already in place and the Azure AD Connect setup was unable to handle this. The synchronisation account was unable to sync, because it ran into a MFA request. We optimized our policies and got this sorted out.
Decommissioning old stuff
Whenever we moved a service successful to Azure, we switched off the on-prem server, and modified our documentation to reflect the made changes. At the end, we were able to switch off three of our four ESXi hosts. A last ESXi Host is still running for our Horizon View deployment and our firewall.
Next steps
The next post will cover how we automated this, how we do backups and whatever you’re interested in. Leave a comment! :)
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
Public Folders are still a thing. And while companies are moving their stuff into the cloud, Public Folders still need to be accessed by cloud-located mailboxes.
Allowing the access from Exchange Online mailboxes to on-premise hosted Public Folders is well documented by Microsoft, but there are also some fuzz. I had to deal with this during a Office 365 transition project at one of my customers.
The background
The customer is running a single Exchange 2016 server in a Windows Server 2012 R2 forest. AzureAD Sync is running and its syncing on-premise identities to AzureAD. The customer uses Office 365 E5 plans and he wants to move to Exchange Online, aside other O365 services like SharePoint Online, Teams etc.
Something was missing
After setting up the Exchange Hybrid, the customer and I where able to migrate the first mailboxes to Exchange Online.
To our surprise the on-premise Public Folders were not visible from the migrated Exchange Online mailboxes. We had still things to do…
In order to get the access to the Public Folders working, the Public Folder mailbox object needs to be synced to AzureAD. This is not complicated, because all you need to make sure is, that the user object is synced. If you are using an OU filter for the AzureAD sync, make sure that the OU with the Public Folder mailbox user object is included into the sync.
Check if the user is synced by using the Exchange Online PowerShell. This is how the Public Folder mailbox user looks like from the Exchange Online perspective:
PS C:\Users\p.terlisten> Get-MailUser Mailbox1
Name RecipientType
---- -------------
Mailbox1 MailUser
This is the Public Folder mailbox that is hosted on-premise.
PS C:\Users\p.terlisten> Get-Mailbox -PublicFolder
Name Alias ServerName ProhibitSendQuota
---- ----- ---------- -----------------
Mailbox1 Mailbox1 EX Unlimited
As long as you can’t see the MailUser in Exchange Online, you have no chance to configure the Public Folder access.
The next step is to synchronize the mail-enabled Public Folder objects to Exchange Online. For this, you have to download two scripts from Microsoft.
Sync-ModernMailPublicFolders.ps1
Sync-ModernMailPublicFolders.psd1
Run the Sync-ModernMailPublicFolders.ps1 script on your on-premise Exchange server. You will need your Office 365 admin credentials for this task.
Please note that some of these steps need some time to get active! It will take some time for the background tasks to get some things sorted.
Controlled Connections to Public Folders in Outlook
It is worth mentioning that after enabling the access to Public Folders all Exchange online users can see the on-premise hosted Public Folders. If you need to enable the access only for some Exchange Online users, Microsoft has a solution for you: Controlled Connections to Public Folders.
First, you need to enable the Public Folder access for the users you have selected.
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
A customer of mine asked for help to analyse a weird OAuth error. They are using a Microsoft Dynamics 365 Outlook plugin, which came up with an error:
“Can’t connect to Exchange”
In addition to this, they also faced an issueaccessing shared calendars of Exchange Online mailboxes.
Clearly an OAuth error. So we ran the Hybrid Connection Wizard again, which finished without any errors. But the errors persisted. Next stop: OAuth configuration.
We logged into one of the Exchange servers, started an Exchange Management Shell and checked the current OAuth configuration:
This posting is ~3 years years old. You should keep this in mind. IT is a short living business. This information might be outdated.
You might got this news some days ago: Starting with September 1, 2020, browsers and devices from Apple, Google, and Mozilla will show errors for new TLS certificates that have a lifespan greater than 398 days. Due to this move from Apple, Google and Mozilla, you have to deal with the replacement of certificates much more often. And we all know: Replacing certificates can be a real PITA!
Replacing TLS certificates used for ADFS and Office 365 can be a challenging task, and this blog post will cover the neccessary steps.
ADFS Server
The first service, for which we will replace the certificate, is the ADFS server, or the ADFS server farm. At this point it is important to understand that we are dealing with two different points to which the certificate is bound:
the ADFS service communications certificate, and
the ADFS SSL certificate
The first step is to replace the service communication certificate. After importing the certificate with private key, you need to assign “read” permission to the ADFS service account. Right click on the certificate, then “All Tasks” > “Manage Private Keys”.
Make sure to import the certificate on all farm servers! Next step: Start the ADFS management console on the primary node. Select “Certificates” and then “Select service communication certificate” on the right window pane.
Now we have successfully replaced the service communication certificate. But we are no finished yet! Now we have to set the ADFS SSL certificate. Depending on your OS, you have to run the PowerShell command on the primary node. If your are running Windows Server 2012 R2 or older, you have to run the PowerShell command on EVERY ADFS farm server!
You can get the certificate thumbprint using the Get-AdfsSslCertificate command. Set the ADFS SSL certificate with
In most cases you will have one or more ADFS proxies in your DMZ. The ADFS proxy is nothing more than a Web Application Proxy (WAP) and therefore the PowerShell commands for WAP will be used.
First of all: Import the new certificate with the private key on all ADFS proxies, and then get the certificate hash of the new certificate. Then open an elevated PowerShell on each proxy.
Then we have to re-establish the trust between the proxies and the primary ADFS farm server. You will need the local (!) administrator account of the primary farm server.
The last step is to update thefederated trust with Office 365.
Update the federated trust with Office 365
To update the federated trust with Office 365, you will need the Windows Azure Active Direcotry Module for Windows PowerShell and an elevated PowerShell. Connect to Office 365 and update the federated trust: