Pages

Showing posts with label Exchange Online. Show all posts
Showing posts with label Exchange Online. Show all posts

Monday, April 3, 2023

Script to continuously run New-ComplianceSearchAction to purge emails discovered by eDiscovery

I recently had to assist with troubleshooting an issue where running the cmdlet New-ComplianceSearchAction against a Content Search result in Microsoft Purview (https://compliance.microsoft.com/) would not delete any email and discovered a few key behavioral items that I wanted to highlight and provide a script I used to delete the emails.

First off, attempting to use the cmdlet New-ComplianceSearchAction against a Content Search will not delete anything. The results from running:

Get-ComplianceSearchAction | FL SearchName,Results,Action,Name,Status

… will always display:

Results: Purge Type: SoftDelete; Item count: 0; Total size 0; Details: {}

What I discovered was that in order to receive results from the deletion is to create the search in eDiscovery, and use the cmdlet New-ComplianceSearchAction against that search:

image

Figuring this out then lead to another problem where the cmdlet would only delete 10 emails at a time so the final solution was to use a script that would continuously create a new job when the previous one has succeeded. This script can be found at my following GitHub repository: https://github.com/terenceluk/Azure/blob/main/PowerShell/New-ComplianceSearchAction-Continuously-Purge.ps1

Hope this helps anyone who may encounter the same issue as I had. The experience can be very frustrating given the changes to the cmdlets over the past few years.

Friday, February 11, 2022

Using PowerShell to configure Exchange Online Inbound and Outbound Connectors to force TLS

As stated in the following Microsoft documentation:

How Exchange Online uses TLS to secure email connections
https://docs.microsoft.com/en-us/microsoft-365/compliance/exchange-online-uses-tls-to-secure-email-connections?view=o365-worldwide

By default, Exchange Online always uses opportunistic TLS. Opportunistic TLS means Exchange Online always tries to encrypt connections with the most secure version of TLS first, then works its way down the list of TLS ciphers until it finds one on which both parties can agree. Unless you have configured Exchange Online to ensure that messages to that recipient must use secure connections, then by default the message will be sent without encryption if the recipient organization doesn't support TLS encryption. Opportunistic TLS is sufficient for most businesses. However, for businesses that have compliance requirements such as medical, banking, or government organizations, you can configure Exchange Online to require, or force, TLS.

I have worked with organizations in the past which have had extremely strict requirements for messaging delivery and have asked for connectors to be configured to force inbound and output TLS connections. For inbound connections, it could be a bit labour intensive if there is a long list of domains to be configured. For outbound connections, it can also be laborious to configure multiple domains with corresponding smarthosts to for where to establish a TLS connection and send the email (this covers organizations that do not have SPF records configured).

Manually configuring inbound and outbound connectors with the GUI may not be the best for an abundance of domains so I’ve created the following two scripts that uses an Excel file to import the configuration settings.

Inbound Connector

The purpose of this script is to create an inbound connector for Exchange Online that forces the defined incoming domains to require TLS.

This script will import a list of domains from an Excel spreadsheet with a column named domains.

https://github.com/terenceluk/Microsoft-365/blob/main/Exchange-Online/Create-Inbound-Connector-For-TLS.ps1

The used for the spreadsheet should look as such:

image

Note that there is a limit on the length of sender domains passed so if there are too many domains then you’ll need to split them out:

Exception: Cannot bind parameter 'SenderDomains' to the target. Exception setting "SenderDomains": "SenderDomainString: The length of the

property is too long. The maximum length is 2243 and the length of the value provided is 5666."

image

Outbound Connector

The purpose of this script is to create an outbound connector for Exchange Online that forces the defined destination domains to require TLS and use a defined smarthost.

This script will import a list of domains from an Excel spreadsheet with a column named domains.

https://github.com/terenceluk/Microsoft-365/blob/main/Exchange-Online/Create-Outbound-Connector-For-TLS.ps1

The used for the spreadsheet should look as such:

image

Monday, May 31, 2021

Configuring App-only authentication with certificates for unattended scripts with EXO V2 module

Those who have worked with Exchange Online PowerShell for a while will know how much a challenge it was to move from basic to modern authentication with MFA for unattended scripts that are scheduled to run non-interactively. The introduction and enforcement of modern authentication and MFA meant attempting to run unattended scripts would no longer work because it would require an administrator to interactively enter credentials and authenticate with the 2nd authentication. As such, many administrators continued to use basic authentication or modern authentication with accounts without MFA enforced to work around the issue, which leads to vulnerability issues. Microsoft originally had plans to disable basic authentication in 2020 but delayed it indefinitely.

Given the challenge as described above, I was extremely excited when Microsoft released the EXO V2 2.0.3 module for public preview in July 2020 where it introduced certificate based authentication. This meant it was now possible to connect to Exchange Online with unattended scripts that no longer passed a username and password, and therefore eliminating the issue where MFA is required upon authentication. I haven’t been working with Exchange Online for sometime due to my new role but was asked by an ex-colleague about setting up unattended scripts so I took the opportunity to capture the process while demonstrating the setup, which I will now use for this blog.

The Scenario

An organization wants to use a PowerShell script to export Office 365 audit logs of users’ events from Exchange Online, SharePoint Online, OneDrive for Business, Azure Active Directory, Microsoft Teams, Power BI, and other Microsoft 365 services with the Audit Log search feature in the following two Microsoft 365 consoles:

Office 365 Security & Compliance
https://protection.office.com/unifiedauditlog

Microsoft 365 compliance
https://compliance.microsoft.com/auditlogsearch

The log will then get emailed for review at the end of the month with a scheduled task.

The Challenge

As this will be an automated process that runs at the end of each month, attempting to setup a PowerShell script that requires using Connect-ExchangeOnline with basic or modern authentication means a username and password will be used with an account without MFA.

The Solution

With the release of EXO V2 2.0.3, unattended scripts (automation) scenarios can now authenticate using Azure AD applications and self-signed certificates.

How does it work?

The EXO V2 module uses the Active Directory Authentication Library to fetch an app-only token using the application Id, tenant Id (organization), and certificate thumbprint. The application object provisioned inside Azure AD has a Directory Role assigned to it, which is returned in the access token. Exchange Online configures the session RBAC using the directory role information that's available in the token.

image

The Tools

To accomplish the task above, we will require the following components:

  1. EXO V2 2.0.3 or higher module
  2. PowerShell Version 7 and higher
  3. Self-signed certificate
  4. PowerShell Script using the Search-UnifiedAuditLog (https://docs.microsoft.com/en-us/powershell/module/exchange/search-unifiedauditlog?view=exchange-ps)

This post will focus on setting up the components required for certificate based authentication but for those who are interested in #4, I’ve written another blog post and will provide the following link to that post:

Script to export audit logs for the current month from Office 365 using Search-UnifiedAuditLog
http://terenceluk.blogspot.com/2021/05/script-to-export-audit-logs-for-current.html

Official Microsoft Documentation

As always, I’d like to provide the official Microsoft documentation and other useful reference documents here:

App-only authentication for unattended scripts in the EXO V2 module
https://docs.microsoft.com/en-us/powershell/exchange/app-only-auth-powershell-v2?view=exchange-ps

Modern Auth and Unattended Scripts in Exchange Online PowerShell V2
https://techcommunity.microsoft.com/t5/exchange-team-blog/modern-auth-and-unattended-scripts-in-exchange-online-powershell/ba-p/1497387

About the Exchange Online PowerShell V2 module
https://docs.microsoft.com/en-us/powershell/exchange/exchange-online-powershell-v2?view=exchange-ps

Basic Authentication and Exchange Online – July Update
https://techcommunity.microsoft.com/t5/exchange-team-blog/basic-authentication-and-exchange-online-july-update/ba-p/1530163

UPDATE: Exchange Online deprecating Basic Authentication (Basic Auth)
https://docs.microsoft.com/en-us/lifecycle/announcements/exchange-online-basic-auth-deprecated

Step #1 – Required Module and PowerShell

Begin by obtaining the required PowerShell and EXO V2 modules as using the incorrect version of say, PowerShell, will cause the certificate based authentication to fail. Download and install the latest versions of the following:

ExchangeOnlineManagement 2.0.5 (the latest at the time of this writing)
https://www.powershellgallery.com/packages/ExchangeOnlineManagement

v7.1.3 Release of PowerShell (the latest at the time of this writing)
https://github.com/PowerShell/PowerShell/releases/tag/v7.1.3

While not a requirement, I highly recommend using Visual Studio Code and the PowerShell extension to write and test PowerShell scripts as the Windows built-in ISE only supports version 5:

Visual Studio Code
https://code.visualstudio.com/download

Using Visual Studio Code for PowerShell Development
https://docs.microsoft.com/en-us/powershell/scripting/dev-cross-plat/vscode/using-vscode?view=powershell-7.1

image

Step #2 – Register an application in Azure AD

In order to authenticate with the EXO V2 module’s Connect-ExchangeOnline with a certificate, you must register the an application in Azure AD, which will represent the unattended script.

Begin by logging into https://portal.azure.com, navigate to Azure Active Directory > App registrations:

image

Click on the New Registration button to register a new app that will represent the identity of the unattended script:

image

Provide a name for the application and select the appropriate account types option. For the purpose of this demonstration, we’re limiting to the single tenant so the following is selected:

Accounts in this organizational directory only (<YourOrganizationName> only - Single tenant)

The Redirect URI (optional) field is not required for what we’re trying to accomplish so leave Web as the selection and the URI empty.

image

The newly created registration of the application should now be displayed:

image

With the application created, we’ll need to assign the appropriate permissions to the application that will represent our unattended script. Proceed to navigate into the configuration of the registered application:

image

----------------------------------------------------------------------------------------------------------------------------

There are two ways to configure the appropriate permissions:

Option #1 – Use the Manifest configuration

This is the easiest as you simply edit the manifest properties, which will configure the permissions and remove the default Microsoft Graph > User.Read permissions as shown here in the API permissions:

image

Navigate to the Manifest configuration and locate requiredResourceAccess entry around line 44:

image

"requiredResourceAccess": [

{

"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",

"resourceAccess": [

{

"id": "dc50a0fb-09a3-484d-be87-e023b12c6440",

"type": "Role"

}

]

}

],

image

Click Save to apply the changes:

image

Navigate to API permissions should now display the Exchange.ManageAsApp permissions configured:

image

Proceed to grant admin consent for the configured permission:

image

image

image

Option #2 – Use the API permissions configuration

The second option is to use the API permissions to manually add the preproperate permissions for the app:

image

Search for Office 365 Exchange Online:

image

Select Application permissions:

image

Under Exchange (1), select Exchange.ManageAsApp:

image

Grant admin consent for the Exchange.ManageAsApp permissions that was just assigned:

image

image

Remove the Microsoft Graph permissions:

image

image

----------------------------------------------------------------------------------------------------------------------------

Step #3 – Generate a self-signed certificate for the application that will be authenticating

The next step is to generate a self-signed X.509 certificate that the application will use to authenticate against Azure AD to request the app-only access token. It is also possible to use an internal or public PKI infrastructure for the certificate but this demonstration will use a self-signed certificate that can be generated locally on a Windows Server with PowerShell version 7.

Note that next Generation (CNG) certificates are not supported for app-only authentication with Exchange. CNG certificates are created by default in modern Windows versions. You must use a certificate from a CSP key provider.

To generate a self-signed certificate for authentication, log onto any Windows Server or desktop with PowerShell version 7 or newer and execute the following:

# Create certificate
$mycert = New-SelfSignedCertificate -DnsName "contoso.org" -CertStoreLocation "cert:\LocalMachine\My" -NotAfter (Get-Date).AddYears(1) -KeySpec KeyExchange

image

A certificate with the private key will be created in the local computer store:

image

The certificate with the private key located on the computer will be used to authenticate the identity of an unattended script. A corresponding certificate with the public key (without the private key) will need to be attached to the Azure AD application. Execute the following cmdlet to create a .cer file with the public key:

# Export certificate to .cer file
$mycert | Export-Certificate -FilePath mycert.cer

image

image

If the intention is to execute Connect-ExchangeOnline from the server where this self-signed certificate is generated then we can simply reference it with its thumbprint when we authenticate. If the script will reside on another server that may not be Windows or have the certificate imported into the local computer store then it is possible to export the certificate with the private key to a .pfx file, which can then be used to authenticate. Scenarios such as having an App Service that needs to authenticate against Azure AD can have the .pfx file stored in the Azure Key Vault and retrieved during the authentication process. Use the following cmdlet to export the certificate to a pfx file:

# Export certificate to .pfx file
$mycert | Export-PfxCertificate -FilePath mycert.pfx -Password $(ConvertTo-SecureString -String "P@ssw0Rd1234" -AsPlainText -Force)

Step #4 – Attach the self-signed certificate to the Azure AD application

The next step is to upload the certificate with the public key (without the private key) to the Azure AD application. Proceed to navigate to the App registrations configuration in the Azure portal and click into the application:

image

Navigate to Certificates & secrets and click on the Upload certificate button:

image

Upload the .cer export of the certificate:

image

The uploaded certificate will be displayed:

image

Step #5 – Assign the required Azure AD roles to the application

The last step for the configuration is the RBAC roles with the required permissions for the registered application so it is able to execute the required cmdlets with the EXO V2 module because authenticating with the certificate will not be in the context of a user. Not all of the Azure AD roles are currently supported but the following ones are:

  • Global administrator
  • Compliance administrator
  • Security reader
  • Security administrator
  • Helpdesk administrator
  • Exchange administrator
  • Global Reader

Begin by navigating to Azure Active Directory > Roles and administrators, search for the Exchange administrator role and open the properties:

image

Click on Add assignments:

image

Search for the app registration we created earlier to grant the service principal permissions:

image

Note how the registered app is now assigned Exchange administrator permissions:

image

Step #6 – Authenticate against Azure AD with Connect-ExchangeOnline using the certificate

We can now use the certificate to authenticate against Azure AD with the Connect-ExchangeOnline cmdlet. Proceed to obtain the Application (client) ID from the Overview properties of the registered application:

image

And the thumbprint of the certificate from the Certificates & secrets of the registered application or the certificate on the Windows operating system’s local computer store:

image

image

With the variable properties above, the following cmdlet can be used to authenticate.

Authenticating with a certificate stored on the Windows server or desktop’s Local Computer > Personal Certificates store

Ensure that the certificate is located in the appropriate store:

image

Connect-ExchangeOnline -CertificateThumbPrint "3D057B3299A75B824F326F1A8A64262F12C60958" -AppID "b6925809-be8c-441b-8915-1bbcc2f2b6fc" -Organization "contoso.onmicrosoft.com"

image

Authenticating with an exported PFX file

Alternatively, you can also use an exported PFX to connect via the following cmdlet:

Connect-ExchangeOnline -CertificateFilePath "C:\scripts\mycert.pfx" -CertificatePassword (ConvertTo-SecureString -String "<MyPassword>" -AsPlainText -Force) -AppID "36ee4c6c-0812-40a2-b820-b22ebd02bce3" -Organization "contoso.onmicrosoft.com"

Authenticating with a certificate object (e.g. retrieved from Azure Key Vault)

The last method to provide a certificate is to use a certificate object via the following cmdlet:

Connect-ExchangeOnline -Certificate <%X509Certificate2 Object%> -AppID "36ee4c6c-0812-40a2-b820-b22ebd02bce3" -Organization "contoso.onmicrosoft.com"

When the Certificate parameter is used, the certificate does not need to be installed on the computer where the command is executed. This parameter is applicable for scenarios where the certificate object is stored remotely and fetched at runtime during script execution. An example of this is when the certificate is stored in the Azure Key Vault.

Script to export audit logs for the current month from Office 365 using Search-UnifiedAuditLog

I was recently asked by a colleague who was looking for a way to automate the export of events from Exchange Online, SharePoint Online, OneDrive for Business, Azure Active Directory, Microsoft Teams, Power BI, and other Microsoft 365 services with the Audit Log search feature in the following two Microsoft 365 consoles:

Office 365 Security & Compliance
https://protection.office.com/unifiedauditlog

image

Microsoft 365 compliance
https://compliance.microsoft.com/auditlogsearch

image

**I believe the Audit search in the Microsoft 365 compliance portal will be replacing Office 365 Security & Compliance.

I haven’t written scripts for a while so I decided to create one the best that I could and have him modify it as needed. My PowerShell script uses the Search-UnifiedAuditLog cmdlet to export the audit logs of a user and the cmdlet’s documentation can be found here: https://docs.microsoft.com/en-us/powershell/module/exchange/search-unifiedauditlog?view=exchange-ps

Note that in order for the script to work, EXO V2 2.0.3 or later with PowerShell 7 will be required as authenticating with a certificate requires these two components. This example will use EXO V2 2.0.5 with PowerShell 7.1.3.

To allow for the script to export the audit logs of multiple users, create a txt file and add the user names on a line of its own as such:

image

The following is the script and few points describing what it does:

  1. Connects to O365 with Connect-ExchangeOnline and authenticates with a certificate to work around MFA through modern authentication
  2. Gets the first and last day of the month (the assumption is that this script will be ran the last day of the month at 11:59p.m.)
  3. Gets the month name
  4. Loops through each username in the txt file
  5. Uses Search-UnifiedAuditLog to export the audit logs starting at the beginning of the month to the last day of the month for a user into a CSV file
  6. Uses Send-MailMessage to email the CSV to two users by relaying off of an on-premise Exchange server (https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-7.1)

#Install-Module -Name ExchangeOnlineManagement

#Import-Module ExchangeOnlineManagement

Connect-ExchangeOnline -CertificateThumbPrint "3968B23E6A91C8F7FF4A9587341E9B0FDB50DB0E" -AppID "ac28a30a-6e5f-4c2d-9384-17bbb0809d57" -Organization "contoso.onmicrosoft.com"

# Get the first day and the last day of the current month

$date = Get-Date

$year = $date.Year

$month = $date.Month

$startOfMonth = Get-Date -Year $year -Month $month -Day 1 -Hour 0 -Minute 0 -Second 0 -Millisecond 0

$endOfMonth = ($startOfMonth).AddMonths(1).AddTicks(-1)

#Get the current month name

$monthName = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month)

#Loop through each entry in a text file containing usernames and use Search-UnifiedAuditLog to search the unified audit log, export to CSV and email out to user.

foreach ($alias in Get-Content C:\scripts\Users.txt) {

$useralias=$alias

$domain = '@contoso.com'

$user=$userAlias+$domain

$csvFileName=($userAlias + "-O365-Activities-" + $monthName + "-" + $year + ".csv")

Search-UnifiedAuditLog -StartDate $startOfMonth -EndDate $endOfMonth -UserIds $user | Export-Csv $csvFileName -NoTypeInformation

$mailSubject=$monthName + " " + $year + " " + $user + ' O365 Audit Log'

$mailBody="Sending " + $user + " O365 Audit Log for the month of " + $monthName + " " + $year + "."

Send-MailMessage -From 'O365 Audit Job <o365audit@contoso.com>' -To 'Terence Luk <tluk@contoso.com>', 'John Smith <jsmith@contoso.com>' -Subject $mailSubject -Body $mailBody -Attachments $csvFileName -Priority High -DeliveryNotificationOption OnSuccess, OnFailure -SmtpServer 'smtp.contoso.com'

}

The following is an output of the script using EXO V2 (2.0.5) with PowerShell 7.1.3:

image

The following is a sample output in the CSV audit log:

image

Saturday, May 16, 2020

Installing and importing ExchangeOnlineManagement module to connect to Exchange Online with modern authentication

This post serves to quickly demonstrate how to install and import the ExchangeOnlineManagement (Exchange Online PowerShell V2) module to connect to Exchange Online in Microsoft 365 to retrieve data, create new objects, update existing objects, remove objects and configure other Exchange Online features.

Begin by executing the following cmdlet to install the ExchangeOnlineManagement module:

Install-Module -Name ExchangeOnlineManagement

Then use the following cmdlet to import and list the version of the module:

Import-Module ExchangeOnlineManagement; Get-Module ExchangeOnlineManagement

image

If the displayed version is out of date, the following cmdlet can be executed to update the module:

Update-Module -Name ExchangeOnlineManagement

image

With the ExchangeOnlineManagement module installed proceed to connect to Exchange online with:

Connect-ExchangeOnline

image

The following modern authentication prompt supporting MFA will be displayed:

image

Entering valid administrative credentials will successfully connect you to the tenant:

image

Below is example of modifying an account’s default calendar permissions upon successfully connecting:

image