mail-organizer/scripts/GraphHelper.psm1

279 lines
7.7 KiB
PowerShell

# GraphHelper.psm1 -- Basis-Modul fuer Microsoft Graph API Zugriff
# Verwendet Client Credentials Flow (Azure App Registration)
$script:GraphToken = $null
$script:TokenExpiry = [DateTime]::MinValue
function Get-GraphToken {
<#
.SYNOPSIS
Holt oder erneuert das OAuth2-Token fuer Microsoft Graph.
.PARAMETER Settings
Hashtable mit TenantId, ClientId, ClientSecret
#>
param(
[Parameter(Mandatory)]
[hashtable]$Settings
)
# Token wiederverwenden wenn noch gueltig (5 Min Puffer)
if ($script:GraphToken -and $script:TokenExpiry -gt (Get-Date).AddMinutes(5)) {
return $script:GraphToken
}
$body = @{
grant_type = "client_credentials"
client_id = $Settings.ClientId
client_secret = $Settings.ClientSecret
scope = "https://graph.microsoft.com/.default"
}
$uri = "https://login.microsoftonline.com/$($Settings.TenantId)/oauth2/v2.0/token"
try {
$response = Invoke-RestMethod -Uri $uri -Method POST -Body $body -ContentType "application/x-www-form-urlencoded"
$script:GraphToken = $response.access_token
$script:TokenExpiry = (Get-Date).AddSeconds($response.expires_in)
Write-Log "Token erfolgreich geholt (gueltig bis $($script:TokenExpiry))" -Level Debug
return $script:GraphToken
}
catch {
Write-Log "FEHLER beim Token-Abruf: $_" -Level Error
throw "Graph API Authentifizierung fehlgeschlagen: $_"
}
}
function Invoke-GraphRequest {
<#
.SYNOPSIS
Fuehrt einen authentifizierten Request gegen die Graph API aus.
.PARAMETER Endpoint
Relativer Pfad (z.B. "/users/user@domain.com/messages")
.PARAMETER Method
HTTP-Methode (GET, POST, PATCH, DELETE)
.PARAMETER Body
Optionaler Request-Body als Hashtable
.PARAMETER Settings
Zugangsdaten-Hashtable
#>
param(
[Parameter(Mandatory)]
[string]$Endpoint,
[string]$Method = "GET",
[hashtable]$Body = $null,
[Parameter(Mandatory)]
[hashtable]$Settings
)
$token = Get-GraphToken -Settings $Settings
$headers = @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
}
$uri = "https://graph.microsoft.com/v1.0$Endpoint"
$params = @{
Uri = $uri
Method = $Method
Headers = $headers
}
if ($Body) {
$params.Body = ($Body | ConvertTo-Json -Depth 10)
}
try {
$response = Invoke-RestMethod @params
return $response
}
catch {
$statusCode = $_.Exception.Response.StatusCode.value__
Write-Log "Graph API Fehler ($statusCode) bei $Method $Endpoint : $_" -Level Error
throw
}
}
function Get-MailMessages {
<#
.SYNOPSIS
Liest E-Mails aus einer Mailbox, optional gefiltert.
.PARAMETER Filter
OData-Filter (z.B. "categories/any(c:c eq 'Wartung')")
.PARAMETER Top
Anzahl der E-Mails (Standard: 50)
#>
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[string]$Filter = $null,
[int]$Top = 50,
[switch]$UnreadOnly
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/mailFolders/inbox/messages?`$top=$Top&`$orderby=receivedDateTime desc"
$endpoint += "&`$select=id,subject,from,receivedDateTime,categories,hasAttachments,isRead,body"
if ($UnreadOnly) {
$filterParts = @("isRead eq false")
} else {
$filterParts = @()
}
if ($Filter) {
$filterParts += $Filter
}
if ($filterParts.Count -gt 0) {
$endpoint += "&`$filter=" + ($filterParts -join " and ")
}
return Invoke-GraphRequest -Endpoint $endpoint -Settings $Settings
}
function Get-MailAttachments {
<#
.SYNOPSIS
Laedt Anhaenge einer bestimmten E-Mail herunter.
.PARAMETER MessageId
Die ID der E-Mail
.PARAMETER TargetPath
Zielverzeichnis fuer die Dateien
#>
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[Parameter(Mandatory)]
[string]$MessageId,
[Parameter(Mandatory)]
[string]$TargetPath
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/messages/$MessageId/attachments"
$result = Invoke-GraphRequest -Endpoint $endpoint -Settings $Settings
if (-not (Test-Path $TargetPath)) {
New-Item -ItemType Directory -Path $TargetPath -Force | Out-Null
}
$savedFiles = @()
foreach ($att in $result.value) {
if ($att.'@odata.type' -eq '#microsoft.graph.fileAttachment') {
$filePath = Join-Path $TargetPath $att.name
$bytes = [Convert]::FromBase64String($att.contentBytes)
[IO.File]::WriteAllBytes($filePath, $bytes)
$savedFiles += $filePath
Write-Log "Anhang gespeichert: $filePath" -Level Info
}
}
return $savedFiles
}
function Send-NotificationMail {
<#
.SYNOPSIS
Sendet eine Benachrichtigungs-E-Mail ueber Graph API.
#>
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[Parameter(Mandatory)]
[string]$To,
[Parameter(Mandatory)]
[string]$Subject,
[Parameter(Mandatory)]
[string]$Body
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/sendMail"
$mailBody = @{
message = @{
subject = $Subject
body = @{
contentType = "HTML"
content = $Body
}
toRecipients = @(
@{ emailAddress = @{ address = $To } }
)
}
saveToSentItems = $false
}
Invoke-GraphRequest -Endpoint $endpoint -Method POST -Body $mailBody -Settings $Settings
Write-Log "Benachrichtigung gesendet an $To : $Subject" -Level Info
}
function Set-MessageRead {
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[Parameter(Mandatory)]
[string]$MessageId
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/messages/$MessageId"
Invoke-GraphRequest -Endpoint $endpoint -Method PATCH -Body @{ isRead = $true } -Settings $Settings | Out-Null
}
function Add-MessageCategory {
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[Parameter(Mandatory)]
[string]$MessageId,
[Parameter(Mandatory)]
[string[]]$Categories
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/messages/$MessageId"
# Bestehende Kategorien lesen und ergaenzen
$msg = Invoke-GraphRequest -Endpoint $endpoint -Settings $Settings
$existing = @($msg.categories)
$merged = ($existing + $Categories) | Select-Object -Unique
Invoke-GraphRequest -Endpoint $endpoint -Method PATCH -Body @{ categories = $merged } -Settings $Settings
}
function Move-Message {
<#
.SYNOPSIS
Moves a message to a destination folder via Graph API.
.PARAMETER DestinationFolder
Well-known folder name (e.g. "archive", "inbox", "drafts") or folder ID.
#>
param(
[Parameter(Mandatory)]
[hashtable]$Settings,
[Parameter(Mandatory)]
[string]$MessageId,
[Parameter(Mandatory)]
[string]$DestinationFolder
)
$user = $Settings.MailboxUser
$endpoint = "/users/$user/messages/$MessageId/move"
Invoke-GraphRequest -Endpoint $endpoint -Method POST -Body @{ destinationId = $DestinationFolder } -Settings $Settings | Out-Null
Write-Log "Nachricht verschoben nach '$DestinationFolder'" -Level Info
}
Export-ModuleMember -Function Get-GraphToken, Invoke-GraphRequest, Get-MailMessages,
Get-MailAttachments, Send-NotificationMail, Set-MessageRead, Add-MessageCategory, Move-Message