279 lines
7.7 KiB
PowerShell
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
|