Das Plus und Minus eines SaaS-Systems ist, dass es nicht von uns gesteuert wird und wir (in den meisten Fällen) den Aktualisierungszyklus der Hauptfunktionalität und das Hinzufügen neuer Funktionen nicht beeinflussen können. Diese Updates können jedoch sowohl informativ sein als auch keine wesentlichen Änderungen in der Funktionalität mit sich bringen, oder sie können für die Infrastruktur von entscheidender Bedeutung sein, was wiederum zusätzliche Risiken für das Unternehmen und damit für unsere Sicherheit wie für IT-Ingenieure mit sich bringt unterstütze die ganze Sache. In diesem Artikel erfahren Sie, wie Sie alle erforderlichen Meldungen zu Updates in Microsoft 365 abrufen, ohne zusätzliche Anwendungen zu installieren. Wir benötigen lediglich eine registrierte Anwendung für den API-Zugriff in Azure Active Directory, Azure Automation, PowerShell und einen Bot in Telegram.
Eine Aufgabe:
, API M365, Teams Telegram.
:
Microsoft 365 Roadmap
Microsoft 365 Message Center
, , .. RSS feed, RSS Telegram . .
, Roadmap , , , Microsoft Message Center . , , .
, PowerShell, . . Azure Automation . , Azure Active Directory .
1. Azure Active Directory
2. Manage App registrations
3. New Registration Azure Active Directory
4. Name , .
5. Register . , , :
Application ID
Directory ID
.
6. , Client Secret, . Certificates & Secrets New Client Secret. , Client Secret.
7. Description .
8. Value , , .
9. Message Center. API Permissions
10. Graph API User.Read, .
.
M365 , Delegated Permissions, , Application Permissions . , - , MFA , Application Permissions Global . User.Read , . Remove permission.
Message Center. Add Permission > Office 365 Management API
11. Application Permissions > ServiceHealth.Read Add Permissions
12. Global Admin, Grant admin consent, ,
13. , Granted for <tenant name>
.
, M365 API, Get-APIToken. :
Application ID
Tenant ID (directory ID)
App Secret (Client Secret)
5
Rest URL :
“https://login.microsoftonline.com/” + $TenantID + “/oauth2/v2.0/token”
Function Get-ApiToken {
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[String]
$AppId, $AppSecret, $TenantID
)
$AuthUrl = "https://login.microsoftonline.com/$TenantID/oauth2/v2.0/token"
$Scope = "https://manage.office.com/.default"
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
Body = $Body
Uri = $AuthUrl
}
try {
Invoke-RestMethod @PostSplat -ErrorAction Stop
}
catch {
Write-Warning "$(Get-Date): Exception was caught: $($_.Exception.Message)"
}
}
Token .
try {
$Token = Get-ApiToken -AppId $ClientId -AppSecret $ClientSecret -TenantID $TenantId -ErrorAction Stop
Write-Output "$(Get-Date): Token successfully issued"
}
catch {
Write-Error "$(Get-Date): Can't get the token!"
break
}
:
, Message Center , Get-MCMessages Get-ApiRequestResult
Get-ApiRequestResult.
URL , .
header Splat.
Function Get-ApiRequestResult {
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
[String]
$Url, $Method, $Token
)
$Header = @{
Authorization = "$($Token.token_type) $($Token.access_token)"
}
$PostSplat = @{
ContentType = 'application/json'
Method = $Method
Header = $Header
Uri = $Url
}
try {
Invoke-RestMethod @PostSplat -ErrorAction Stop
}
catch {
$Ex = $_.Exception
$ErrorResponse = $ex.Response.GetResponseStream()
$Reader = New-Object System.IO.StreamReader($errorResponse)
$Reader.BaseStream.Position = 0
$Reader.DiscardBufferedData()
$ResponseBody = $Reader.ReadToEnd();
Write-Output "$(Get-Date): Response content:`n$responseBody" -f Red
throw Write-Error "$(Get-Date): Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
}
}
Message Center.
Get https://manage.office.com/api/ServiceComms/Messages
Function Get-MCMessages {
[CmdletBinding()]
param (
[Parameter(Mandatory=$True)]
$APIUrl, $TenantId
)
$ApiVersion = "v1.0"
$MS_resource = "ServiceComms/Messages?&`$filter=MessageType%20eq%20'MessageCenter'"
$Uri = "$APIUrl/$ApiVersion/$($TenantId)/$MS_resource"
$Method = "GET"
try {
Get-ApiRequestResult -Url $Uri -Token $Token -Method $Method -ErrorAction Stop
Write-Output "$(Get-Date): New messages successfully collected"
}
catch {
$Ex = $_.Exception
$ErrorResponse = $ex.Response.GetResponseStream()
$Reader = New-Object System.IO.StreamReader($errorResponse)
$Reader.BaseStream.Position = 0
$Reader.DiscardBufferedData()
$ResponseBody = $Reader.ReadToEnd();
Write-Output "$(Get-Date): Response content:`n$responseBody" -f Red
throw Write-Error "$(Get-Date): Request to $Uri failed with HTTP Status $($ex.Response.StatusCode) $($ex.Response.StatusDescription)"
}
}
? , API M365 , , , . , $MS_Resource $URL Get-MCMessages. Intune, Get-IntuneManagedDevices, MS_Resource "deviceManagement/managedDevices", URL https://graph.microsoft.com, .
:
, Azure Automation, . , - «» , . LastUpdatedTime, .
Runbook Azure Automation 1 , . , : , . :
$CurrentTime = Get-Date
$ontrolTime = ($CurrentTime).AddMinutes(-60)
Get-MCMessages.
$Messages = Get-MCmessages -APIUrl $APIUrl -TenantId $TenantId
,
$NewMessages = $Messages.value | Where-Object {$(Get-date $($_.LastUpdatedTime)) -ge $controlTime}
$NewMessagesCount = $NewMessages.id.count
if ($NewMessagesCount -gt 0) {
Write-Output "$(Get-Date): There are $NewMessagesCount new messages"
}
else {
Write-Output "$(Get-Date): There is no new messages"
break
}
, , . .
if ($NewMessagesCount -gt 0) {
foreach ($NewMessage in $NewMessages){
}
}
.
$MessagePreview = $NewMessage.Messages.MessageText
$MessageID = $NewMessage.id
$MessageTitle = $NewMessage.Title
$MessageType = $NewMessage.actiontype
$PublishedTime = Get-date $($NewMessage.Messages.publishedTime)
$UpdatedTime = Get-Date $($NewMessage.LastUpdatedTime)
MessageText html, , Telegram . , , , Telegram . Remove-HtmlTags, html , .
. :
- .
- , .
- - .
, , . :
Function Remove-HtmlTags {
param (
$Text
)
$SimpleTags = @(
'p',
'i',
'span',
'div',
'ul',
'ol',
'h1',
'h2',
'h3',
'div'
)
$TagsToRemove = (
"\<\/?font[^>]*\>",
'\<br\s?\/?\>',
'\&rarr',
'style=""',
' target\=\"_blank\"'
)
$TagsToReplace = @(
@('\[','<b>'),
@('\]','</b>'),
@('\<A','<a'),
@('\<\/A\>','</a>'),
@('\<img[^>]*\>','[There was an image]'),
@(' ',' '),
@('\<li\>',' -'),
@('\<\/li\>',"`n")
)
foreach($Tag in $SimpleTags){
$Pattern = "\<\/?$tag\>"
$Text = $Text -replace $Pattern
}
foreach($Tag in $TagsToRemove){
$Text = $Text -replace $Tag
}
foreach($Tag in $TagsToReplace){
$Text = $Text -replace $Tag
}
foreach($Tag in $SimpleTags){
$Pattern = "\<\/?$Tag\>"
$Text = $Text -replace $Pattern
}
$Text
}
, , , , , - . - , , , .
, . , , Microsoft , . </p>, , , html . .
$MessageTextWithHtmlString = $MessagePreview -split ('\<\/p\>')
$FormattedMesssageText = $(Remove-HtmlTags $MessageTextWithHtmlString) -creplace '(?m)^\s*\r?\n',''
. Title .
$PublishingInfo = "Published: $PublishedTime `nUpdated: $UpdatedTime"
$TgmMessage = "$BoldMessageTitle `n$MessageDescription `n$PublishingInfo `n$FormattedMesssageText"
Microsoft , , . .
$MessageActionRequiredByDate = $NewMessage.ActionRequiredByDate
$MessageAdditionalInformation = $NewMessage.ExternalLink
$MessageBlogLink = $NewMessage.BlogLink
if($MessageActionRequiredByDate){
$TgmMessage += "`nAction required by date: $MessageActionRequiredByDate"
}
elseif ($MessageAdditionalInformation) {
$TgmMessage += "`n$MessageAdditionalInformation'>Additional info"
}
elseif ($MessageBlogLink) {
$TgmMessage += "`n$MessageBlogLink'>Blog"
}
. , .
ChatID, Token, ParsingType, - , .
function Send-TelegramMessage {
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[string]
$MessageText,$TokenTelegram,$ChatID
[Parameter(Mandatory=$true)]
[ValidateSet("html","markdown")]
[string]$ParsingType
)
$URL_set = "https://api.telegram.org/bot$TokenTelegram/sendMessage"
$Body = @{
text = $MessageText
parse_mode = $ParsingType
chat_id = $chatID
}
$MessageJson = $body | ConvertTo-Json
try {
Invoke-RestMethod $URL_set -Method Post -ContentType 'application/json; charset=utf-8' -Body $MessageJson -ErrorAction Stop
Write-Output "$(Get-Date): Message has been sent"
}
catch {
Write-Error "$(Get-Date): Can't sent message"
Write-Output "$(Get-Date): StatusCode:" $_.Exception.Response.StatusCode.value__
Write-Output "$(Get-Date): StatusDescription:" $_.Exception.Response.StatusDescription
throw
}
}
, , :
Send-TelegramMessage -MessageText $TgmMessage -TokenTelegram $TokenTelegram -ChatID $chatID -ParsingType 'html'
:
, ID, , . Azure Automation Secure Assets. .
Link zum Kanal mit dem laufenden Bot
PS Ich freue mich über Mitwirkende und Vorschläge zur Verbesserung des Bots.