#Requires -Version 7.2 <# .SYNOPSIS Sets up Entra Policy Suite's mail (framework MAIL-1): a shared mailbox the engine sends its alerts from - and the right to send as THAT mailbox only. .DESCRIPTION Creates the shared mailbox (or uses the one you name), registers the engine's managed identity in Exchange, creates a management scope matching exactly that mailbox and gives the identity 'Application Mail.Send' on it - Exchange RBAC for applications, so the engine can send as this mailbox and as no other. A tenant-wide Graph Mail.Send grant on the identity is removed (it would win beside the scope). Every step is read back. Then it stores the mail settings (Mail.Mode = sharedMailbox, the sender, the recipients) in the Entra Policy Suite database. You sign in in a browser (no module). Needs an Exchange Online plan in the tenant. -WhatIf: the plan, nothing changed. .EXAMPLE ./Initialize-EpsMailSender.ps1 -TenantId -SubscriptionId -Sender eps-alerts@contoso.com -Recipients soc@contoso.com -WhatIf .LINK https://invardia.com/docs/eps/scripts/Initialize-EpsMailSender #> # PUBLISHED as a self-contained launcher of Initialize-EpsMailSender.ps1 (EntraPolicySuite 2.0.107, Publish-EpsHandover): it runs release 2.0.107 unless -EpsVersion picks another. [CmdletBinding(SupportsShouldProcess)] param( [Parameter(Mandatory)][guid]$TenantId, [Parameter(Mandatory)][guid]$SubscriptionId, [Parameter(Mandatory)][string]$Sender, [Parameter(Mandatory)][string[]]$Recipients, [string]$ResourceGroup = '', [string]$EnvironmentName, [ValidatePattern('^$|^2\.\d+\.\d+$')][string]$EpsVersion = '2.0.107' ) $ErrorActionPreference = 'Stop' # A self-contained launcher of Initialize-EpsMailSender.ps1 (invardia.com/support/eps/): it downloads the EntraPolicySuite release this script # was handed over for (2.0.107 - the version of your install's ring; -EpsVersion picks another, -EpsVersion '' the # latest), checks it against the release's published SHA-256 digest and runs the release's own Initialize-EpsMailSender.ps1 with the # parameters you gave. Nothing is installed on this machine; the download goes to a temporary folder. $what = [bool]$WhatIfPreference; $WhatIfPreference = $false $repo = 'KnudsenMorten/EntraPolicySuite'; $h = @{ 'User-Agent' = 'EntraPolicySuite-support' } $rel = Invoke-RestMethod -Uri $(if ($EpsVersion) { "https://api.github.com/repos/$repo/releases/tags/v$EpsVersion" } else { "https://api.github.com/repos/$repo/releases?per_page=30" }) -Headers $h $rel = @($rel | Where-Object { $_.tag_name -match '^v2\.' -and -not $_.draft -and -not $_.prerelease } | Sort-Object { [version]($_.tag_name.TrimStart('v') -replace '[^0-9.].*$', '') } -Descending)[0] if (-not $rel) { Write-Host 'No EntraPolicySuite v2 release found.' -ForegroundColor Red; exit 3 } $asset = @($rel.assets | Where-Object { $_.name -match '^EntraPolicySuite-v2[0-9A-Za-z.+-]*\.zip$' })[0] if (-not $asset) { Write-Host "Release $($rel.tag_name) has no EntraPolicySuite-v2*.zip." -ForegroundColor Red; exit 3 } $dir = Join-Path ([IO.Path]::GetTempPath()) "eps-$($rel.tag_name)-$([guid]::NewGuid().ToString('N').Substring(0, 6))" New-Item -ItemType Directory -Path $dir | Out-Null $zip = Join-Path $dir $asset.name Invoke-WebRequest -Uri $asset.browser_download_url -OutFile $zip -Headers $h $got = (Get-FileHash -LiteralPath $zip -Algorithm SHA256).Hash.ToLowerInvariant() $published = if ("$($asset.digest)" -match '^(?i)sha256:([0-9a-f]{64})$') { $Matches[1].ToLowerInvariant() } else { '' } if (-not $published -or $got -ne $published) { [IO.Directory]::Delete($dir, $true); Write-Host "The download does not match the release's SHA-256 - deleted, nothing run." -ForegroundColor Red; exit 3 } Write-Host "Release $($rel.tag_name), SHA-256 $got (matches the release)" Expand-Archive -LiteralPath $zip -DestinationPath $dir -Force $script = Get-ChildItem -LiteralPath $dir -Recurse -Filter 'Initialize-EpsMailSender.ps1' -File | Select-Object -First 1 if (-not $script) { Write-Host 'The release has no Initialize-EpsMailSender.ps1.' -ForegroundColor Red; exit 3 } $pass = @{} foreach ($k in @($PSBoundParameters.Keys)) { if ($k -notin 'EpsVersion', 'WhatIf', 'Confirm') { $pass[$k] = $PSBoundParameters[$k] } } if ($what) { $pass.WhatIf = $true } & $script.FullName @pass exit $LASTEXITCODE