Graph 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

2022

2022

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.

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.

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 MByte 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
-------              ----                                ----------           -----------
6.1907.1.0           Microsoft.Graph.Intune              PSGallery            PowerShell SDK for Microsoft Intune Grap…
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

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 $cert `
   -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:\Users\fcarius> $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