Cleanup Microsoft.Graph PowerShell Modules

Hi All,

I wanted to check the amount of Commands available in the Microsoft.Graph Powershell Modules

Get-Command -Module Microsoft.Graph* | measure


That seemed a bit much and it turned out, i had multiple Versions of Microsoft.Graph PowerShell Module installed.

Here is a Script do remove the Old Modules and install only the newest Version.

$Modules = Get-Module Microsoft.Graph* -ListAvailable | Where {$_.Name -ne "Microsoft.Graph.Authentication"} | Select-Object Name -Unique
Foreach ($Module in $Modules)
{
    $ModuleName = $Module.Name
    $Versions = Get-Module $ModuleName -ListAvailable
    Foreach ($Version in $Versions)
    {
        $ModuleVersion = $Version.Version
        Write-Host "Uninstall-Module $ModuleName $ModuleVersion"
        Uninstall-Module $ModuleName -RequiredVersion $ModuleVersion
    }
}
#Uninstall Microsoft.Graph.Authentication
$ModuleName = "Microsoft.Graph.Authentication"
$Versions = Get-Module $ModuleName -ListAvailable
Foreach ($Version in $Versions)
{
    $ModuleVersion = $Version.Version
    Write-Host "Uninstall-Module $ModuleName $ModuleVersion"
    Uninstall-Module $ModuleName -RequiredVersion $ModuleVersion
}
Install-Module Microsoft.Graph


Now let's check again

Get-Module Microsoft.Graph* -ListAvailable


When i check now for the available commands it looks more sensable

Get-Command -Module Microsoft.Graph* | measure



Regards
Andres Bohren


New Azure Active Directory Diagnostic settings

Hi All,

Did you notice that there are new Azure AD Diagnostic Settings in AzureAD?
  • NetworkAccessTrafficLogs
  • RiskyServicePrincipals
  • ServicePrincipalRiskEvents


After the Change i've checked the LogAnalytics - did not see any change.


Checked again a few days later and could only see that the Table "AzureDiagnostics" has been addet. But no Data in it.



What is your Experience?Do you see new Tables? Is there Data in it?

Regards
Andres Bohren


ExchangeOnlineManagement v206-Preview5 (Connect-IPPSSession with CBA)

Hi All,

Today the ExchangeOnlineManagement Preview 5 PowerShell Module has been released to the PowerShell Gallery.
As you can see it's the first time you can use Certificate Based Authentication (CBA) to Authenticate with  Connect-IPPSSession.

ExchangeOnlineManagement Preview5


Installing the Module (PowerShell must be startet "As Administrator")

Find-Module ExchangeOnlineManagement -AllowPrerelease
Install-Module ExchangeOnlineManagement -AllowPrerelease -Force



How to set up the Azure AD App i have documented here

Connect to Exchange Online with a Certificate stored in your CurrentUser Certificate Store

$AppID = "f38d26a7-740e-425f-aef5-2da3f3d595db"
$CertificateThumbprint = "4F1C474F862679EC35650824F73903041E1E5742"
$TenantId = "icewolfch.onmicrosoft.com"
Connect-ExchangeOnline -AppID $AppID -CertificateThumbprint $CertificateThumbprint -Organization $TenantId



Connect to Security and Compliance with a Certificate stored in your CurrentUser Certificate Store

$AppID = "f38d26a7-740e-425f-aef5-2da3f3d595db"
$CertificateThumbprint = "4F1C474F862679EC35650824F73903041E1E5742"
$TenantId = "icewolfch.onmicrosoft.com"
Connect-IPPSSession -AppID $AppID -CertificateThumbprint $CertificateThumbprint -Organization $TenantId



Connect to Security and Compliance with a PFX and the PFX Password

$AppID = "f38d26a7-740e-425f-aef5-2da3f3d595db"
$CertificateFilePath = "C:\GIT_WorkingDir\O365PowerShell2.pfx"
$CertificatePassword = ConvertTo-SecureString -String 'YourPFXPassword' -AsPlainText -Force
$TenantId = "icewolfch.onmicrosoft.com"
Connect-IPPSSession -AppID $AppID -CertificateFilePath $CertificateFilePath -CertificatePassword $CertificatePassword -Organization $TenantId




Regards
Andres Bohren


Modern Dynamic Distribution Groups in Exchange Online

Hi All,

Did you hear about the "Modern Dynamic Distribution Groups in Exchange Online"?
Little less dynamic but with more caching 😊


Modern Dynamic Distribution Groups in Exchange Online


Create a new Dynamic Distribution Group in Exchange Online

New-DynamicDistributionGroup -Name DDG-Icewolf-UserMailbox -IncludedRecipients MailboxUsers -ConditionalCompany "Icewolf"


Show the Details - note the Recipient Filter

Get-DynamicDistributionGroup -Identity DDG-Icewolf-UserMailbox | fl


If you check for the Members - it's still empty

Get-DynamicDistributionGroupMember -Identity DDG-Icewolf-UserMailbox


You chan check for the Member with the Recipient filter

Get-Recipient -RecipientPreviewFilter "((((Company -eq 'Icewolf') -and (RecipientType -eq 'UserMailbox'))) -and (-not(Name -like'SystemMailbox{*')) -and (-not(Name -like 'CAS_{*')) -and (-not(RecipientTypeDetailsValue -eq 'MailboxPlan')) -and (-not(RecipientTypeDetailsValue -eq 'DiscoveryMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'PublicFolderMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'ArbitrationMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'AuditLogMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'AuxAuditLogMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'SupervisoryReviewPolicyMailbox')) -and (-not(RecipientTypeDetailsValue -eq 'GuestMailUser')))"


After some time, the Members of the Dynamic Distribution Group show up

Get-DynamicDistributionGroupMember -Identity DDG-Icewolf-UserMailbox


No changes in Outlook. The Members of a "normal" Distribution Group can be viewed.


Not in the case of a dynamic distribution group.



Regards
Andres Bohren


Simple Example of Sending Mail via Microsoft Graph

Hi All,

I did feel to write a simple PowerShell Script to demonstrate how to Send a Mail via Microsoft Graph.
You need to create an Azure AD Application with the following Permission "Application -> Mail.Send".
Authentication with a SelfSigned Certificate.


The whole Script is published at my GitHub Repo


###############################################################################
# Limiting application permissions to specific Exchange Online mailboxes
# https://docs.microsoft.com/en-us/graph/auth-limit-mailbox-access
#
# Limit Microsoft Graph Access to specific Exchange Mailboxes
# https://blog.icewolf.ch/archive/2021/02/06/limit-microsoft-graph-access-to-specific-exchange-mailboxes.aspx
###############################################################################
#Mail Enabled Security Group
Get-AzureADGroup -SearchString PostmasterGraphRestriction | Format-Table DisplayName, ObjectId, SecurityEnabled, MailEnabled, Mail

New-ApplicationAccessPolicy -AccessRight RestrictAccess -AppId c1a5903b-cd73-48fe-ac1f-e71bde968412 -PolicyScopeGroupId PostmasterGraphRestriction@icewolf.ch -Description "Restrict this app to members of this Group"

Get-ApplicationAccessPolicy
Test-ApplicationAccessPolicy -AppId c1a5903b-cd73-48fe-ac1f-e71bde968412 -Identity postmaster@icewolf.ch
Test-ApplicationAccessPolicy -AppId c1a5903b-cd73-48fe-ac1f-e71bde968412 -Identity SharedMBX@icewolf.ch


For aquiring the Access Token i use the PowerShell Module MSAL.PS

#Import PS Module
Import-Module MSAL.PS

###############################################################################
# Get AccessToken with MSAL
###############################################################################
#Variables
$TenantId = "icewolfch.onmicrosoft.com"
$AppID = "c1a5903b-cd73-48fe-ac1f-e71bde968412" #DelegatedMail
$CertificateThumbprint = "4F1C474F862679EC35650824F73903041E1E5742" #O365Powershell2.cer
$RedirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient"
$Scope = "https://graph.microsoft.com/.default"

#Authenticate with Certificate
$Certificate = Get-ChildItem -Path cert:\CurrentUser\my\$CertificateThumbprint
$Token = Get-MsalToken -ClientId $AppID -ClientCertificate $Certificate -TenantId $TenantID -Scope $Scope -RedirectUri $RedirectUri
$AccessToken = $Token.AccessToken


Now you have aquired the Access Token and this will be used for the Authentication on the HTTP POST Request to send a Mail

###############################################################################
# Sends Mail via Microsoft Graph API
# https://docs.microsoft.com/en-us/graph/api/user-sendmail?view=graph-rest-1.0&tabs=http
###############################################################################
#Delegated (work or school account)    Mail.Send
#Delegated (personal Microsoft account)    Mail.Send
#Application    Mail.Send

#Create HTML Body
[string]$body = @"
<html>
    <head>
        <style>
        p {
            text-align: Left;
            color: green;
            font-size: 12px;
            font-family: Arial
        }

        table, th, td {
            border: 1px solid;
            font-size: 12px;
            font-family: Arial           
        }
        </style>
    </head>
<body>
    <h3>HTML Header</h3>
    <p>the quick brown fox jumps over the lazy dog</p>
</body>
</html>
"@


Now we can send the Acutal Mail

$Mailbox = "postmaster@icewolf.ch"
$URI = "https://graph.microsoft.com/v1.0/users/$Mailbox/sendMail"
$ContentType = "application/json"
$Headers = @{"Authorization" = "Bearer "+ $AccessToken}
$Body = @"
{
    "message": {
        "subject": "Microsoft Graph API Mail DEMO",
        "body": {
            "contentType": "HTML",
            "content": "$Body"
        },
        "toRecipients": [
            {
                "emailAddress": {
                    "address": "a.bohren@icewolf.ch"
                }
            }
        ]
    }
}
"@

#Send Actual Mail
$result = Invoke-RestMethod -Method "POST" -Uri $uri -Body $Body -Headers $Headers -ContentType $ContentType
If ($null -ne $result)
{
    Write-Host "Mail has been sucessufully sent"
}



The HTML Mail looks like this



Regards
Andres Bohren


Azure Automation: PSGallery Version Check

Hi All,

I don't check daily if there are any new PowerShell modules in PSGallery.
So i wrote me a Script of my most used Modules to Inform me if there are any new Modules available.

With the following Code i check for the current Version of the Modules and put them into a PSCustomObject with the Attributes Release, Module, Version (for GA and Prerelease Versions).

###############################################################################
# Check PSGallery Modules
###############################################################################
#Create Empty Array
$MyArray = @()

$Modules = @("AZ","MSOnline", "AzureADPreview", "ExchangeOnlineManagement", "Icewolf.EXO.SpamAnalyze", "MicrosoftTeams", "Microsoft.Online.SharePoint.PowerShell","PnP.PowerShell" , "ORCA", "O365CentralizedAddInDeployment", "MSCommerce", "WhiteboardAdmin", "Microsoft.Graph", "MSAL.PS", "MSIdentityTools" )
foreach ($Module in $Modules)
{
    #Check GA Version
    $Result = Find-Module -Name $Module
    $Version = $Result.Version
    Write-Output "GA: $Module $Version"

    #Create Custom Object to Store Information
    $myObject = [PSCustomObject]@{
        Release     = 'GA'
        Module = $Module
        Version    = $Version
    }
    #Add to Array
    $MyArray += $myObject

    #Check PreRelease Version
    $Result = Find-Module -Name $Module -AllowPrerelease
    $Version = $Result.Version
    Write-Output "PreRelease: $Module $Version"

    #Create Custom Object to Store Information
    $myObject = [PSCustomObject]@{
        Release     = 'PreRelease'
        Module = $Module
        Version    = $Version
    }
    #Add to Array
    $MyArray += $myObject
}



I have saved this PSCustomObject into a CSV

$MyArray | Export-CSV -Path $DestinationFile -encoding UTF8 -NoTypeInformation


If i import the CSV i can compare the two Versions

$CSV = Import-CSV -Path $PathToCSV
$Compare = Compare-Object -ReferenceObject $MyArray -DifferenceObject $CSV -Property Release,Module,Version
$Compare



I did write me a Azure Automate PowerShell 7 Script to run daily and send me a Mail

And these are the Mails i receive



Regards
Andres Bohren


Exchange Security Updates March 2022

Hi All,

It's that time of the Month again and Microsoft has released Patches for Exchange 2013 up to Exchange 2019

Released: March 2022 Exchange Server Security Updates

Description of the security update for Microsoft Exchange Server 2019 and 2016: March 8, 2022 (KB5012698)

Security Update For Exchange Server 2016 CU22 (KB5012698)

Don't forget to start the msp from an elevated cmd Prompt








Regards
Andres Bohren