MGGraph PowerShell

Eigentlich müsste diese Seite im Office 365 Admin-Bereich sein, wo ich schon die MSOnline-PowerShell und AzureAD-PowerShell beschrieben habe. Die Microsoft Graph Powershell löst die beiden anderen administrativen PowerShells ab aber ist auch ein universelles Modul für fast alle Graph Schnittstellen.

Lebenslauf

PowerShell ist die Plattform für die Verwaltung in der Cloud und die MSOnline-PowerShell war in 2021 die erste PowerShell und die AzureAD PowerShell kam 2015. Warum sollte ich dann die Graph PowerShell nutzen? Die erste Antwort: Weil die anderen beiden PowerShells abgekündigt sind:

... our goal is to also provide guidance and tools for migrating existing scripts and PowerShell processes, reliant on the Azure AD Graph API and MSOnline module, to the Microsoft Graph PowerShell SDK.
This is due to the planned deprecation of the two PowerShell modules (MSOL & AAD) after December 2022.
Quelle: Azure AD: Change Management Simplified
https://techcommunity.microsoft.com/t5/azure-active-directory-identity/azure-ad-change-management-simplified/ba-p/2967456

Aber auch der technische Vergleich der verschiedenen Versionen spricht klar für die Graph PowerShell:

Funktion MSOnline AzureAD Graph PowerShell

Released

2021

2015

2022

End of Live

März 2023

März 2023

n.a.

API Abdeckung

Beschränkt

umfangreicher

Alles(1)

Always Uptodate

Nein

Nein

Ja(2)

Cross Plattform

Nein

Nein

Ja (auch Mac, Linux)

Open Source

Nein

Nein

Ja

Dokumentation

OK

OK

Wird besser

Nutzbarkeit

Gut

Gut

Wird besser

PowerShell Basis

2 (?)

5

5.1+

Public Endpoint

https://provisioningapi.microsoftonline.com

https://graph.windows.net

https://graph.microsoft.om

Authentication Library

?

ADAL (abgekündigt)

MSAL (aktuell)

  1. Alles, was per Graph erreichbar ist.
    Leider sind aber nicht alle Funktionen schon in Graph erreichbar aber es wird besser
  2. Auto Generation
    Angeblich wird die Graph PowerShell regelmäßig automatisch aus der Graph Dokumentation generiert und ist daher immer aktuell.

Der Weg ist also klar vorgezeichnet: Die MSOnline PowerShell und die AzureAD PowerShell laufen spätestens Dezember 2022 aus und wer heute schon Skripte zur Automatisierung auf dieser Basis aufsetzt, ist gut beraten den Wechsel anzugehen.

Am 21. Juni 2022 wurde die Graph PowerShell im Rahmen des Microsoft 365 Platform Community Call" vorgestellt.

Microsoft 365 Platform Community Call – 21st of June, 2022
https://youtu.be/tqp_ifocotA?t=959
"Overview of the Microsoft Graph PowerShell SDK - Nik Charlebois -Senior Product Manager"
von Minute 15:59 bis 35:16

Installation

Microsoft stellt die Microsoft Graph als Modul auf der PowerShell PSGallery bereit.

Das Module ist aber kein ZIP oder MSI-File, sondern kann über die PowerShell direkt installiert werden.

Achtung:
Das Gesamtpaket sind über 40 Module mit über 600 MB Umfang. Sie sollten daher überlegen, nur die Module zu installieren, die sie auch benötigen. Das spart auch Datenvolumen und Zeit bei späteren Updates.

Mit dem Kommando "Find-Module -Command <name>" können Sie das passende Modul finden.

PS C:\> Find-Module Microsoft.Graph

Version              Name      Repository      Description
-------              ----      ----------      -----------
1.9.3    Microsoft.Graph       PSGallery       Microsoft Graph PowerShell module

PS C:\> Install-Module Microsoft.Graph

Bei mir hat er aber ca. 680 Megabyte in das Verzeichnis "C:\Users\<username>\SkyDrive\Dokumente\PowerShell\Modules" gepumpt. Dabei ist "Microsoft.Graph" nur ein Sammelmodul, welches viele kleine weitere Module installiert.

PS C:\> Find-Module Microsoft.Graph.*

Version  Name                                Repository  Description
-------  ----                                ----------  -----------
1.9.3    Microsoft.Graph.Authentication      PSGallery   Microsoft Graph PowerShell Authenticatio…
1.9.3    Microsoft.Graph.Planner             PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Teams               PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Applications        PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Users               PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Identity.SignIns    PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Devices.CorporateM… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Groups              PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DeviceManagement.A… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DeviceManagement.E… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DeviceManagement    PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Identity.Directory… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Users.Actions       PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.SchemaExtensions    PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Education           PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Bookings            PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.CloudCommunications PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Security            PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Users.Functions     PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Files               PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Identity.Governance PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Mail                PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Reports             PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Sites               PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Financials          PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Search              PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.People              PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Notes               PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.CrossDeviceExperie… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.PersonalContacts    PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DirectoryObjects    PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.ChangeNotifications PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Compliance          PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Calendar            PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Devices.CloudPrint  PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DeviceManagement.A… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.DeviceManagement.F… PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.WindowsUpdates      PSGallery   Microsoft Graph PowerShell Cmdlets
1.9.3    Microsoft.Graph.Devices.ServiceAnn… PSGallery   Microsoft Graph PowerShell Cmdlets
1.5.1    Microsoft.Graph.PlusPlus            PSGallery   Module to work the Microsoft Graph API u…

Jedes Modul bringt natürlich eigne Commandlets mit und bei mir waren es 7431 Commandlets.

PS C:\> (Get-Command *-mg*).count
7431

Da wird es natürlich schwer, das jeweils genaue Commandlet zu finden. Aber der Modulname gibt ja auch den Bereich in Graph vor, so dass Sie entsprechend z.B. auf "Benutzer" filtern können:

Get-Command -Module Microsoft.Graph.Users

Ein anderer Weg ist die Suche nach der URL in der Graph-Beschreibung und die Suche nach der URL

Find-MGGraphCommand -Uri '/security/alerts'

Berechtigungen

Der Zugriff per Graph erfolgt immer authentifiziert. Dabei gibt es zwei Optionen:

  • Delegated
    Das Skript oder der Code nutzt die Anmeldedaten des Benutzers, die dieser mitliefert
  • Application
    Der Admin muss den Code im Tenant registrieren und mit Berechtigungen versehen.

Nicht jede MGGraph-Commandlet unterstützt beide Optionen. Ich schaue dazu einfach in der Graph-Dokumentation nach, welche Methode welche Berechtigungen versteht. Siehe auch Graph und Kennworte. Ich kann aber auch mittels MGGraph ermittlen, welche Berechtigungen ein Befehl braucht:

PS C:\> Find-MgGraphCommand -command Get-MGUserMailFolder | Select -ExpandProperty Permissions

Name           IsAdmin Description                         FullDescription
----           ------- -----------                         ---------------
Mail.Read      False   Read your mail                      Allows the app to read email in your mailbox.
Mail.ReadBasic False   Read user basic mail                Allows the app to read email in the signed-in user's mailbo…
Mail.ReadWrite False   Read and write access to your mail  Allows the app to read, update, create and delete email in …

Eventuell erscheinen Einträge mehrfach, wenn es mehrere API-Versionen (1.0 vs. beta) gibt.

Anmelden als Benutzer

Sie müssen natürlich zuerst eine Verbindung herstellen, ehe sie eines der Commandlets nutzen können. Beim Versuch sehen Sie schon den Fehler:

Ehe Sie nun aber einfach einen "Connect-MgGraph" starten, sollten Sie überlegen, was sie eigentlich vorhanden. Wenn Sie nur "Connect-MgGraph" aufrufen, dann startet ein Browser, in dem Sie sich anmelden können und das war es auch. Sie haben dann ein sehr rudimentäres Token

PS C:\> Connect-MgGraph -Verbose
Welcome To Microsoft Graph!
PS C:\> Get-MgContext

ClientId              : 14d82eec-204b-4c2f-b7e8-296a70dab67e
TenantId              : eef62a09-7718-4063-82db-d7582dc8916f
CertificateThumbprint :
Scopes                : {openid, profile, User.Read, email}
AuthType              : Delegated
AuthProviderType      : InteractiveAuthenticationProvider
CertificateName       :
Account               : frank@carius.de
AppName               : Microsoft Graph PowerShell
ContextScope          : CurrentUser
Certificate           :
PSHostVersion         : 7.2.2
ClientTimeout         : 00:05:00

PS C:\> Get-MgUser
Get-MgUser_List1: Insufficient privileges to complete the operation.

Selbst bei einer Anmeldung als "Global Admin" an einem Tenant bekomme ich nur die Berechtigungen, die mir schon eingeräumt wurden.. Die Microsoft Graph PowerShell nutzt das Prinzip der "minimalen Rechte" und wenn Sie mehr Berechtigungen benötigen, dann müssen Sie diese beim "Connect-MGGraph" mit angeben. Wenn ich also z.B. die Liste der Benutzer haben möchte, dann schaue ich, welches Recht ich benötige

In meinem Fall begnüge ich mich mal mi "User.Read.All".

Connect-MgGraph -Scopes User.Read.All

Es startet wieder ein Browserfenster und nach der Anmeldung kann es sein, dass ich erst den angeforderten Berechtigungen zustimmen muss:

Danach kann ich auch Get-MGuser ausführen. Wenn ich ich später erneut anmelde, dann sieht aber mein Token etwas anders aus:

PS C:\> Get-MgContext

ClientId              : 14d82eec-204b-4c2f-b7e8-296a70dab67e
TenantId              : 3c6855ff-e39f-4d09-a473-33807598ce4b
CertificateThumbprint :
Scopes                : {openid, profile, User.Read, User.Read.All…}
AuthType              : Delegated
AuthProviderType      : InteractiveAuthenticationProvider
CertificateName       :
Account               : fcarius.admin@fcarius.onmicrosoft.com
AppName               : Microsoft Graph PowerShell
ContextScope          : CurrentUser
Certificate           :
PSHostVersion         : 7.2.2
ClientTimeout         : 00:05:00


PS C:\> (Get-MgContext).scopes
openid
profile
User.Read
User.Read.All
email

Durch den Consent hat mein Benutzer für die App "Microsoft Graph PowerShell" die erweiterte Berechtigungen zugestimmt.

Sie können natürlich auch direkt der App "Microsoft Graph PowerShell" die Berechtigungen als Administrator für die komplette Organisation geben.

Achtung: Der Grant gilt für die Graph PowerShell und damit für alle Skripte, die durch die Anwender diese API nutzen.

Da Sie die App aber nicht selbst entwickelt haben, sondern von Microsoft bereitgestellt wird, können Sie nur die dort hinterlegten Berechtigungen für den Tenant zulassen. Am 29. März 2022 waren dies:

Nach der erneuten Anmeldung, habe ich dann diese Berechtigungen:

PS C:\> (Get-MgContext).scopes
Chat.Create
Chat.Read
Chat.ReadBasic
Chat.ReadWrite
ChatMessage.Read
ChatMessage.Send
openid
profile
User.Read
User.Read.All
email

Mit den Berechtigungen können Sie nun alle Microsoft Graph PowerShell Commandlets für ihren Anwender nutzen, für die Sie berechtigt sind.

Anmelden als App

Sie können aber auch natürlich eine eigene App in ihrem Tenant registrieren und z.B. mit App-Permissions arbeiten. Ich habe eine App mit folgenden Eckdaten angelegt:

Displayname:      MSXFAQ MGGraph
ApplicationID:    ffeebff4-5acd-4fed-b8e9-4ec075562401
TenantID:         604d9047-44e5-443a-ad8f-98abe5748b0a
Authentication:   Single Tenant
Certificates:     Client Certificate
API-Permissions:  Graph/Application/CallRecords.Read.All          +AdminConsent
API-Permissions:  Graph/Application/CallRecord-PstnCalls.Read.All +AdminConsent

Anscheinend unterstützt die "MicrosoftGraph Powershell " keine App-Anmeldung oder Client-Secret (AppID+Kennwort). Ich habe daher ein Zertifikat angelegt:

# Selbst signiertes Zertifikat erstellen
$appcert = New-SelfSignedCertificate `
              -Subject "CN=MSXFAQ_MGGraph" `
              -CertStoreLocation "Cert:\CurrentUser\My"  `
              -KeyExportPolicy Exportable  `
              -KeySpec Signature  `
              -KeyLength 2048  `
              -KeyAlgorithm RSA  `
              -HashAlgorithm SHA256

# Als Datei exportieren
Export-Certificate `
   -Cert $appcert `
   -FilePath "MSXFAQ_MGGraph.cer"

Die CER-Datei lade ich dann im Azure Portal hoch. Das Portal braucht nicht meinen privaten Schlüssel.

Die Nutzung eines Zertifikats macht die weitere Dokumentation hier auf der Webseite einfach, da ich ja nur den Thumbprint oder Name des Zertifikats nutze aber damit nie Credentials aus versehen veröffentliche. Allerdings ist das Zertifikat by Default nur 1 Jahre gültig, wenn Sie nicht z.B. per Parameter " -NotAfter (Get-Date).AddYears(5)" das Endedatum verlängern.

Danach kann ich eine Graph-Session als App starten:

PS C:\>Connect-MgGraph `
   -AppId ffeebff4-5acd-4fed-b8e9-4ec075562401 `
   -TenantId 604d9047-44e5-443a-ad8f-98abe5748b0a `
   -CertificateName "MSXFAQ_MGGraph"

#Oder

PS C:\>Connect-MgGraph `
   -AppId ffeebff4-5acd-4fed-b8e9-4ec075562401 `
   -TenantId 604d9047-44e5-443a-ad8f-98abe5748b0a `
   -CertificateThumbprint e9d7e3e804ac9e23a319b269ebeb990648bde268


PS C:\>Get-MgContext

ClientId              : ffeebff4-5acd-4fed-b8e9-4ec075562401
TenantId              : 604d9047-44e5-443a-ad8f-98abe5748b0a
CertificateThumbprint : e9d7e3e804ac9e23a319b269ebeb990648bde268
Scopes                : {CallRecords.Read.All, CallRecord-PstnCalls.Read.All}
AuthType              : AppOnly
AuthProviderType      : ClientCredentialProvider
CertificateName       :
Account               :
AppName               : MSXFAQ MGGraph
ContextScope          : Process
Certificate           :
PSHostVersion         : 7.2.2
ClientTimeout         : 00:05:00

Call-Details mit Graph

Nun habe ich mir leider nicht das einfachste Thema mit den PSTN-Calls ausgesucht, denn es gibt zwar ein PowerShell Modul aber keines zum Auflisten der Calls.

Function        Get-MgCommunicationCall                            1.9.3      Microsoft.Graph.CloudCommunications
Function        Get-MgCommunicationCallAudioRoutingGroup           1.9.3      Microsoft.Graph.CloudCommunications
Function        Get-MgCommunicationCallOperation                   1.9.3      Microsoft.Graph.CloudCommunications
Function        Get-MgCommunicationCallParticipant                 1.9.3      Microsoft.Graph.CloudCommunications
Function        Get-MgCommunicationCallRecord                      1.9.3      Microsoft.Graph.CloudCommunications
Function        Get-MgCommunicationCallRecordSession               1.9.3      Microsoft.Graph.CloudCommunications

Die Commandlets haben eher das Ziel, aktuell aktive Calls zu erhalten und zu manipulieren. In dem Fall kann ich mir dann aber mit Invoke-MGGraphRequest behelfen.

$calls= Invoke-mggraphrequest `
           -Method GET `
           -Uri "https://graph.microsoft.com/v1.0/communications/callRecords/getDirectRoutingCalls(fromDateTime=2022-03-10,toDateTime=2022-03-30)"


$calls.value[0]

Name                           Value
----                           -----
mediaBypassEnabled             True
callerNumber                   +495251304613
trunkFullyQualifiedDomainName  sbc.uclabor.de
userPrincipalName              frank.carius@uclabor.de
calleeNumber                   +49160906
signalingLocation              EUWE
failureDateTime                10.03.2022 06:30:59
finalSipCodePhrase             LocalUserInitiated
duration                       0
callEndSubReason               0
successfulCall                 False
userId                         f2564fa9-fdc6-4db0-9d2a-a2dc940fbce4
correlationId                  578c7283-6992-43b9-8dc3-8560767452ca
endDateTime
mediaPathLocation              EUWE
userDisplayName                Frank Carius
startDateTime
inviteDateTime                 10.03.2022 06:30:21
finalSipCode                   487
id                             8cb8e505-7276-43bb-ac92-46698235b50f 
callType                       ByotOut

Interessant ist hier die "id", welche die CallID ist, über die ich dann weitere API-Aufrufe starten kann. Entweder direkt:

$calldetail= Invoke-mggraphrequest `
           -Method GET `
           -Uri "https://graph.microsoft.com/v1.0/communications/callRecords/8cb8e505-7276-43bb-ac92-46698235b50f"


PS C:\> $calldetail

Name                           Value
----                           -----
id                             8cb8e505-7276-43bb-ac92-46698235b50f
version                        5
participants                   {System.Collections.Hashtable, System.Collections.Hashtable, System.Collections.Hashtab…
joinWebUrl                     https://teams.microsoft.com/l/meetup-join/19%3ameeting_NWIxMTdiNzItYjNiYi00MzI1LTkxMmIt…
type                           groupCall
@odata.context                 https://graph.microsoft.com/v1.0/$metadata#communications/callRecords/$entity
lastModifiedDateTime           29.03.2022 17:50:17
endDateTime                    29.03.2022 16:15:31
modalities                     {audio, video, videoBasedScreenSharing}
organizer                      {encrypted, acsApplicationInstance, device, spoolUser…}
startDateTime                  29.03.2022 15:23:47

Oder mittels Get-MgCommunicationCallRecord

$calldetail= Get-MgCommunicationCallRecord `
   -CallRecordId "8cb8e505-7276-43bb-ac92-46698235b50f" `
   -ExpandProperty "sessions(`$expand=segments)"

EndDateTime          : 29.03.2022 16:15:31
Id                   : 8cb8e505-7276-43bb-ac92-46698235b50f
JoinWebUrl           : https://teams.microsoft.com/l/meetup-join/19%3ameeting_NWIxMTdiNzItYjNiYi00MzI1LTk
LastModifiedDateTime : 29.03.2022 17:50:17
Modalities           : {audio, video, videoBasedScreenSharing}
Organizer            : Microsoft.Graph.PowerShell.Models.MicrosoftGraphIdentitySet
Participants         : {Microsoft.Graph.PowerShell.Models.MicrosoftGraphIdentitySet,
                       Microsoft.Graph.PowerShell.Models.MicrosoftGraphIdentitySet,
                       Microsoft.Graph.PowerShell.Models.MicrosoftGraphIdentitySet,
                       Microsoft.Graph.PowerShell.Models.MicrosoftGraphIdentitySet…}
Sessions             : {0145bce7-3da6-4270-9c29-b62c320c3713, 04e18759-9cba-4c59-bdee-538caef52d06,
                       05f4c6e9-e8b9-47f3-aa13-99306b885c9c, 07ebc54a-4046-4f70-aa66-e5f5f9c6d047…}
StartDateTime        : 29.03.2022 15:23:47
Type                 : groupCall
Version              : 5
AdditionalProperties : {[@odata.context, https://graph.microsoft.com/v1.0/$metadata#communications/callRecords(sessions
                       (segments()))/$entity], [sessions@odata.context, https://graph.microsoft.com/v1.0/$metadata#comm
                       unications/callRecords('8cb8e505-7276-43bb-ac92-46698235b50f')/sessions(segments())]}

Sie sehen hier aber auch, dass die Rückgaben nicht identisch sind.

Filter

Zu jeder Abfrage einer Datenschnittstelle gehören entsprechende Filtermöglichkeiten. Es macht keinen Sinn, sich erst alle Daten vom Server zum Client liefern zu lassen und erst dann die relevanten Inhalte zu selektieren. Auch Microsoft Graph kennt entsprechende Filtermöglichkeiten. Die Microsoft Graph PowerShell nutzt dazu mit OPATH eine Filtersyntax, die besonders den Exchange Administratoren bekannt sein dürfte. Auch Exchange Commandlets nutzen seit Exchange 2007 diese Syntax.

Weitere Links