Make interactive

This commit is contained in:
2025-09-22 21:13:21 +00:00
parent 12b2899324
commit aac78893a2

View File

@ -1,44 +1,195 @@
<# <#
.SYNOPSIS .SYNOPSIS
Count the number of received emails in a Microsoft 365 mailbox during a specified time window. Interactive mailbox message counter for Microsoft 365 (Graph).
.DESCRIPTION .DESCRIPTION
This script queries Exchange Online via Microsoft Graph to return the total count of emails Prompts the user to choose "my mailbox" or "another/shared mailbox", gathers the target mailbox,
received by a specific mailbox within a given date range. It searches all folders in the mailbox start date, and end date, then connects to Microsoft Graph with the appropriate delegated scope
(including Inbox, subfolders, Junk, and Deleted Items), ensuring that emails moved after delivery and returns a count of RECEIVED messages (excluding drafts and self-sent) within the specified
are still included in the count. Drafts are excluded, and self-sent messages from the mailbox local time window. It searches ALL folders (Inbox, subfolders, Junk, Deleted Items, etc.) so
owner are not counted as "received." post-delivery moves don't matter.
Date boundaries are applied using local time (Eastern Time in this example). Time boundaries are created using the specified Windows time zone (default: "Eastern Standard Time"
Adjust offsets (-05:00 / -04:00) for daylight savings or your region. for Toronto). The script computes the correct UTC offset for the provided dates (including DST)
and generates ISO 8601 timestamps with offsets (e.g., 2025-01-01T00:00:00-05:00).
.PARAMETER $u .REQUIREMENTS
The target user's email address. Example: 'f@d.org' - PowerShell 5.1+ (Windows) or PowerShell 7+
- Microsoft.Graph PowerShell SDK (will auto-install for CurrentUser if missing)
- For "another/shared mailbox":
* Your signed-in account must have Full Access to that mailbox in Exchange Online.
.PARAMETER $start .PARAMETERS (prompted)
The inclusive start of the time window in ISO 8601 format with time zone offset. - Scope mode: "1 = My mailbox" or "2 = Another/shared mailbox"
Example: '2025-01-01T00:00:00-05:00' for January 1st, 2025, 12:00 AM ET. - Mailbox SMTP address (e.g., user@domain.com)
- Start date (YYYY-MM-DD), inclusive
.PARAMETER $end - End date (YYYY-MM-DD), exclusive
The exclusive end of the time window in ISO 8601 format with time zone offset.
Example: '2025-02-01T00:00:00-05:00' for February 1st, 2025, 12:00 AM ET.
.OUTPUTS .OUTPUTS
Returns a single integer representing the count of received messages. Prints a single integer count and a short summary of inputs.
.NOTES .NOTES
Requirements: Example month window:
- Microsoft.Graph PowerShell module Start: 2025-01-01
- Connect-MgGraph with Mail.Read delegated permission (if signed in as the user) End: 2025-02-01
OR Mail.Read application permission (with admin consent) if run as a service. These will be interpreted at 00:00 local time of the configured time zone.
Install module: Install-Module Microsoft.Graph
Examples to connect:
This is your mailbox: Connect-MgGraph -Scopes Mail.Read
This is a shared mailbox you are a "Full" delegate of: Connect-MgGraph -Scopes Mail.Read.Shared
(c) 2025 Robbie Ferguson. All rights reserved. (c) 2025 Robbie Ferguson. All rights reserved.
#> #>
$u='mailbox@domain.com';$start='2025-01-01T00:00:00-05:00';$end='2025-02-01T00:00:00-05:00';$c=0; Get-MgUserMessage -UserId $u -Filter "receivedDateTime ge $start and receivedDateTime lt $end and isDraft eq false and (from/emailAddress/address ne '$u')" -CountVariable c -PageSize 1 | Out-Null; $c # --------------------------- User-editable settings ---------------------------
# Windows Time Zone ID (use `tzutil /l` to list). "Eastern Standard Time" covers Toronto with DST.
$TimeZoneId = 'Eastern Standard Time'
# -----------------------------------------------------------------------------
# Helper: ensure Microsoft Graph SDK is available
function Ensure-GraphModule {
$moduleName = 'Microsoft.Graph'
if (-not (Get-Module -ListAvailable -Name $moduleName)) {
Write-Host "Microsoft.Graph module not found. Installing for CurrentUser..."
try {
Set-PSRepository PSGallery -InstallationPolicy Trusted -ErrorAction SilentlyContinue
Install-Module $moduleName -Scope CurrentUser -Force -ErrorAction Stop
} catch {
Write-Error "Failed to install Microsoft.Graph: $($_.Exception.Message)"
Read-Host "Press Enter to exit"
exit 1
}
}
Import-Module $moduleName -ErrorAction Stop
}
# Helper: get TimeZoneInfo safely
function Get-TimeZoneInfoSafe {
param([string]$Id)
try {
return [System.TimeZoneInfo]::FindSystemTimeZoneById($Id)
} catch {
Write-Error "Time zone '$Id' not found. Edit `$TimeZoneId at the top (Windows TZ IDs, e.g., 'Eastern Standard Time')."
Read-Host "Press Enter to exit"
exit 1
}
}
# Helper: build ISO timestamp with correct offset for a date at 00:00 local time
function Get-ISOStartOfDayWithOffset {
param(
[datetime]$DateOnly,
[System.TimeZoneInfo]$Tz
)
# Local 00:00 in the TZ
$local = Get-Date -Date "$($DateOnly.ToString('yyyy-MM-dd')) 00:00:00"
$offset = $Tz.GetUtcOffset($local)
$sign = if ($offset -lt [TimeSpan]::Zero) { '-' } else { '+' }
$hh = [math]::Abs($offset.Hours).ToString('00')
$mm = [math]::Abs($offset.Minutes).ToString('00')
$offStr = "$sign$hh`:$mm"
return "{0}T00:00:00{1}" -f $local.ToString('yyyy-MM-dd'), $offStr
}
# Helper: connect to Graph with appropriate scope
function Connect-GraphWithScope {
param([string]$Scope)
try {
Disconnect-MgGraph -ErrorAction SilentlyContinue | Out-Null
} catch {}
try {
Connect-MgGraph -Scopes $Scope -ErrorAction Stop | Out-Null
} catch {
Write-Error "Failed to connect to Microsoft Graph with scope '$Scope': $($_.Exception.Message)"
Read-Host "Press Enter to exit"
exit 1
}
}
# Helper: validate date input (YYYY-MM-DD)
function Read-DateStrict {
param([string]$Prompt,[datetime]$Default)
while ($true) {
$in = Read-Host "$Prompt (YYYY-MM-DD) [Enter for $($Default.ToString('yyyy-MM-dd'))]"
if ([string]::IsNullOrWhiteSpace($in)) { return $Default.Date }
if ([datetime]::TryParseExact($in, 'yyyy-MM-dd', $null, 'None', [ref]([datetime]$out))) {
return $out.Date
}
Write-Host "Invalid date. Please use YYYY-MM-DD." -ForegroundColor Yellow
}
}
# Start
Write-Host "=== M365 Mailbox Message Counter ===" -ForegroundColor Cyan
Ensure-GraphModule
# 1) Which mailbox type?
Write-Host "Select mailbox type:" -ForegroundColor Cyan
Write-Host " 1) My mailbox"
Write-Host " 2) Another/shared mailbox (requires delegation with Full Access)"
$mode = Read-Host "Enter 1 or 2"
if ($mode -notin @('1','2')) {
Write-Error "Invalid selection."
Read-Host "Press Enter to exit"
exit 1
}
# 2) Target mailbox SMTP
$Mailbox = Read-Host "Enter the mailbox SMTP address to check (e.g., user@domain.com)"
if ([string]::IsNullOrWhiteSpace($Mailbox) -or ($Mailbox -notmatch '^[^@\s]+@[^@\s]+\.[^@\s]+$')) {
Write-Error "Invalid email address."
Read-Host "Press Enter to exit"
exit 1
}
# 3) Date range (inclusive start, exclusive end)
# Defaults to January 2025 for convenience; change as needed
$defaultStart = Get-Date '2025-01-01'
$defaultEnd = Get-Date '2025-02-01'
$StartDate = Read-DateStrict -Prompt "Start date (inclusive)" -Default $defaultStart
$EndDate = Read-DateStrict -Prompt "End date (exclusive)" -Default $defaultEnd
if ($EndDate -le $StartDate) {
Write-Error "End date must be AFTER start date."
Read-Host "Press Enter to exit"
exit 1
}
# Prepare TZ and ISO strings with correct offsets for each boundary date
$tz = Get-TimeZoneInfoSafe -Id $TimeZoneId
$startISO = Get-ISOStartOfDayWithOffset -DateOnly $StartDate -Tz $tz
$endISO = Get-ISOStartOfDayWithOffset -DateOnly $EndDate -Tz $tz
# 4) Connect with proper scope
$scope = if ($mode -eq '1') { 'Mail.Read' } else { 'Mail.Read.Shared' }
Connect-GraphWithScope -Scope $scope
# Show who is signed in (helpful for multi-tenant admins)
try {
$ctx = Get-MgContext
if ($ctx) { Write-Host "Connected as: $($ctx.Account) | Tenant: $($ctx.TenantId) | Scope(s): $($ctx.Scopes -join ', ')" -ForegroundColor DarkGray }
} catch {}
# 5) Perform count
try {
$count = 0
# Exclude drafts and self-sent (from == mailbox) to count RECEIVED mail
$filter = "receivedDateTime ge $startISO and receivedDateTime lt $endISO and isDraft eq false and (from/emailAddress/address ne '$Mailbox')"
# Ask Graph for a count; we don't need to page through items (PageSize 1 trick)
Get-MgUserMessage -UserId $Mailbox -Filter $filter -CountVariable count -PageSize 1 | Out-Null
Write-Host ""
Write-Host "Mailbox: $Mailbox" -ForegroundColor Green
Write-Host "Window: $($StartDate.ToString('yyyy-MM-dd')) to $($EndDate.ToString('yyyy-MM-dd')) ($TimeZoneId)" -ForegroundColor Green
Write-Host "Count of RECEIVED messages (all folders, excluding drafts & self-sent):" -ForegroundColor Green
Write-Host $count -ForegroundColor Cyan
} catch {
Write-Host ""
Write-Error "Query failed: $($_.Exception.Message)"
# Common guidance
if ($mode -eq '2') {
Write-Host "If this is another/shared mailbox, ensure:" -ForegroundColor Yellow
Write-Host " - Your account has Full Access to $Mailbox in Exchange Online (Mailbox Delegation)." -ForegroundColor Yellow
} else {
Write-Host "If this is your own mailbox and it still fails, try reconnecting and consenting the scope." -ForegroundColor Yellow
}
}
Write-Host ""
Read-Host "Press Enter to exit"