klanax
Goto Top

Einfache Liste der Office365-Geräte

Hallo an alle!

Im "Microsoft 365 admin center" kann ich mir über
-Benutzer
-Aktive Benutzer
-Anzeigename
-Microsoft 365-Aktivierungen anzeigen
die Geräte anzeigen lassen, auf denen der jeweilige Benutzer sein Office365 installiert hat.

Gibt es eine Möglichkeit, diese Informationen von allen Benutzern auf einer Seite zu sehen oder in einer Exportdatei zu speichern?

Vielen Dank schon mal für eure Antworten.

Viele Grüße

klanax

Content-ID: 7186428459

Url: https://administrator.de/contentid/7186428459

Printed on: October 11, 2024 at 13:10 o'clock

cramtroni
cramtroni Sep 05, 2023 at 12:58:26 (UTC)
Goto Top
Dies sollte über das Admin Center über die Seite Berichte>Nutzung möglich sein. Die Informationen lassen sich auch als CSV-Datei exportieren.

Mfg
cramtroni
NordicMike
NordicMike Sep 05, 2023 at 13:00:11 (UTC)
Goto Top
Da bist du schon richtig:

Im "Microsoft 365 admin center" kann ich mir über
-Benutzer
-Aktive Benutzer

Und schon siehst du die Liste
7907292512
7907292512 Sep 05, 2023 updated at 13:32:11 (UTC)
Goto Top
In der GUI alle markieren, und dann oben "Export" wählen.
Oder über die Powershell automatisiert
https://learn.microsoft.com/en-us/microsoft-365/enterprise/view-account- ...

screenshot


Gruß sid
klanax
klanax Sep 05, 2023 at 13:55:38 (UTC)
Goto Top
Hallo.

Danke für eure Rückmeldungen.

Aber bei allen Ansichten oder Exporten sehe ich nur die Benutzer oder die Anzahl der Aktivierungen, aber nirgends die einzelnen Geräte. Oder übersehe ich da etwas?

Zum Suchen über die PowerShell-Lösung muss ich mir erstmal etwas Zeit nehmen.

Viele Grüße

klanax
7907292512
7907292512 Sep 05, 2023 at 14:06:21 (UTC)
Goto Top
Get-MGUser -All | select Displayname,Mail,RegisteredDevices,OwnedDevices
klanax
klanax Sep 05, 2023 at 14:13:54 (UTC)
Goto Top
Hallo Siddius,
ich werde mir das morgen genauer anschauen.
Vielen Dank.
Gruß
klanax
klanax
klanax Sep 06, 2023 at 10:45:29 (UTC)
Goto Top
Hallo Siddius,
nachdem ich mich jetzt erstmal mit dem Thema Graph beschäftigt habe und die Installation und Anmeldung soweit funktioniert hat, liefert mir das Ganze zwar beispielsweise den Displaynamen oder die ID,

get_mguser

leider aber nicht die gesuchten Informationen zu den "devices" der Benutzer.

get_mguser_selektiert

Gruß
klanax
7907292512
7907292512 Sep 06, 2023 updated at 10:51:52 (UTC)
Goto Top
Die IDs der registrierten Device kannst du ja per Get-MgDevice auflösen face-wink.

Wenn du aber stattdessen die Aktivierungen meinst, an die kommst du per Powershell so auch nicht. Das hat MS nicht vorgesehen.
Sie dazu Office activations pr. user with devices specified

Da könntest du höchstens was mit Selenium über eine Browser-Automation basteln.
colinardo
colinardo Sep 06, 2023, updated at Sep 09, 2023 at 05:49:38 (UTC)
Goto Top
Servus @klanax.
Die Infos konnte ich ebenfalls nicht in der Graph-API und auch nicht in der Management-API Dokumentation ausfindig machen. Aber da die Daten per Admin-Center bereitgestellt werden können wir uns hier bedienen um an die Daten zu kommen.
Habe hier mal ein Browser-Automation-Skript mit Selenium zusammengebaut welches die Daten dann über die Admin-Center API abfragt.

Voraussetzung ist ein installiertes Graph Module (Microsoft.Graph.Users) für die Abfrage der User. Der zu nutzende Browser für die Abfrage muss in den Variablen im Kopf an einen momentan installierten Browser angepasst werden, ebenso wie der Ausgabepfad für eine CSV-Datei. Bei Ausführung des Skriptes wird man aufgefordert sich erst bei MS Graph zu authentifizieren, ist das erfolgreich gibt das Skript einen Hinweis das nun ein Browserfenster geöffnet wird in dem man sich mit seinen Credentials am M365 Admin-Center anmelden muss, das Skript wartet dabei so lange bis man sich erfolgreich eingeloggt hat. Dann fährt das Skript von selbst fort und exportiert die Daten aller User in eine CSV-Datei.

(Skript bitte nicht in der Powershell ISE ausführen sondern in einer echten Konsole)
#requires -Modules Microsoft.Graph.Users
# path to save the report to
$EXPORTPATH = '.\office_activations.csv'  
# set your desired browser, valid values are "Firefox","Chrome" or "Edge" (the browser must be installed on the current system!) 
$selenium_browser = 'Firefox'  
# --------------------------------------
$ErrorActionPreference = "Stop"  
if ($host.Version.Major -ne 5){
    throw "PowerShell Version 5 required."  
    return
}
# function to create selenium browser
function Create-Browser {
    param(
        [Parameter(mandatory=$true)][ValidateSet('Chrome','Edge','Firefox')][string]$browser,  
        [Parameter(mandatory=$false)][bool]$HideCommandPrompt = $true,
        [Parameter(mandatory=$false)][string]$driverversion = ''  
    )
    $driver = $null

    function Load-NugetAssembly {
	    [CmdletBinding()]
	    param(
		    [string]$url,
		    [string]$name,
		    [string]$zipinternalpath,
		    [switch]$downloadonly
	    )
	    if($psscriptroot -ne ''){  
		    $localpath = join-path $psscriptroot $name
	    }else{
		    $localpath = join-path $env:TEMP $name
	    }
	    $tmp = "$env:TEMP\$([IO.Path]::GetRandomFileName())"  
	    $zip = $null
	    try{
		    if(!(Test-Path $localpath)){
			    Add-Type -A System.IO.Compression.FileSystem
			    write-host "Downloading and extracting required library '$name' ... " -F Green -NoNewline  
			    (New-Object System.Net.WebClient).DownloadFile($url, $tmp)
			    $zip = [System.IO.Compression.ZipFile]::OpenRead($tmp)
			    $zip.Entries | ?{$_.Fullname -eq $zipinternalpath} | %{
				    [System.IO.Compression.ZipFileExtensions]::ExtractToFile($_,$localpath)
			    }
			    write-host "OK" -F Green  
		    }
		    if (Get-Item $localpath -Stream zone.identifier -ea SilentlyContinue){
			    Unblock-File -Path $localpath
		    }
		    if(!$downloadonly.IsPresent){
			    Add-Type -Path $localpath -EA Stop
		    }
	    }catch{
		    throw "Error: $($_.Exception.Message)"  
	    }finally{
		    if ($zip){$zip.Dispose()}
		    if(Test-Path $tmp){del $tmp -Force -EA 0}
	    }
    }

    # Load Selenium Webdriver .NET Assembly
    Load-NugetAssembly 'https://www.nuget.org/api/v2/package/Selenium.WebDriver/4.11.0' -name 'WebDriver.dll' -zipinternalpath 'lib/net45/WebDriver.dll' -EA Stop  

    if($psscriptroot -ne ''){  
        $driverpath = $psscriptroot
    }else{
        $driverpath = $env:TEMP
    }
    switch($browser){
        'Chrome' {  
            $chrome = Get-Package -Name 'Google Chrome' -EA SilentlyContinue | select -F 1  
            if (!$chrome){
                throw "Google Chrome Browser not installed."  
                return
            }
            Load-NugetAssembly "https://www.nuget.org/api/v2/package/Selenium.WebDriver.ChromeDriver/$driverversion" -name 'chromedriver.exe' -zipinternalpath 'driver/win32/chromedriver.exe' -downloadonly -EA Stop  
            # create driver service
            $dService = [OpenQA.Selenium.Chrome.ChromeDriverService]::CreateDefaultService($driverpath)
            # hide command prompt window
            $dService.HideCommandPromptWindow = $HideCommandPrompt
            # create driver object
            $driver = New-Object OpenQA.Selenium.Chrome.ChromeDriver $dService
        }
        'Edge' {  
            $edge = Get-Package -Name 'Microsoft Edge' -EA SilentlyContinue | select -F 1  
            if (!$edge){
                throw "Microsoft Edge Browser not installed."  
                return
            }
            Load-NugetAssembly "https://www.nuget.org/api/v2/package/Selenium.WebDriver.MSEdgeDriver/$driverversion" -name 'msedgedriver.exe' -zipinternalpath 'driver/win64/msedgedriver.exe' -downloadonly -EA Stop  
            # create driver service
            $dService = [OpenQA.Selenium.Edge.EdgeDriverService]::CreateDefaultService($driverpath)
            # hide command prompt window
            $dService.HideCommandPromptWindow = $HideCommandPrompt
            # create driver object
            $driver = New-Object OpenQA.Selenium.Edge.EdgeDriver $dService
        }
        'Firefox' {  
            $ff = Get-Package -Name "Mozilla Firefox*" -EA SilentlyContinue | select -F 1  
            if (!$ff){
                throw "Mozilla Firefox Browser not installed."  
                return
            }
            Load-NugetAssembly "https://www.nuget.org/api/v2/package/Selenium.WebDriver.GeckoDriver/$driverversion" -name 'geckodriver.exe' -zipinternalpath 'driver/win64/geckodriver.exe' -downloadonly -EA Stop  
            # create driver service
            $dService = [OpenQA.Selenium.Firefox.FirefoxDriverService]::CreateDefaultService($driverpath)
            # hide command prompt window
            $dService.HideCommandPromptWindow = $HideCommandPrompt
            # create driver object
            $driver = New-Object OpenQA.Selenium.Firefox.FirefoxDriver $dService
        }
    }
    return $driver
}

# connect to MG
Connect-MGGraph -Scopes User.Read.All

write-host "Script will now open a webbrowser instance, please login to the M365 Admin-Center with your credentials.`nScript will wait until you finish the login.`n`nPress any key to continue" -F Green  
[void][console]::ReadKey()

# create selenium browser instance
$browser = Create-Browser -browser $selenium_browser
# Navigate to admin center
$browser.Url = "https:/admin.microsoft.com"  
$browser.Navigate()
# wait until user has finished login procedure
do {
    write-host "Waiting for login to complete ..." -F Cyan  
    sleep 1
}until($browser.url -like 'https://admin.microsoft.com/Adminportal/Home#/*')  
write-host "Login completed. Extracting statistics for users, please wait ..." -F Green  
# for each user call api function to get office-install statistics
$result = foreach ($user in Get-MGUser -All){
    try{
        $browser.url = "https://admin.microsoft.com/admin/api/users/$($user.id)/officeInstalls"  
        ([xml]$browser.PageSource).ManageOfficeInstallsModel.SoftwareMachineDetails.SoftwareMachineDetails.MachineDetails.Machines.OlsMachineDetail | select @{n='Username';e={$user.DisplayName}},MachineName,MachineOS,OfficeMajorVersion,LastLicenseRequestedDate,LicenseExpiryDate,LicenseStatus,MachineKey,MachineStatus  
    }catch{}
}
# export statistics to csv
$result | export-csv -LiteralPath $EXPORTPATH -Delimiter ";" -NoTypeInformation -Encoding UTF8 -verbose  
# quit browser and disconnect MG
$browser.Quit()
Disconnect-MgGraph | out-null
Den Login im Browser kann man natürlich auch automatisieren (habe ich hier auch schon vorliegen), da es hier aber mehrere Möglichkeiten gibt (2FA & Co.) und ich nicht weiß welche davon be euch zum Einsatz kommt, habe ich das hier der Einfachheit weg gelassen.

Probiere es mal aus. Hier hat das so in meinem Testlab-Tenant einwandfrei geklappt.

Das Ergebnis der CSV sieht dann in etwa so aus
"Username";"MachineName";"MachineOs";"OfficeMajorVersion";"LastLicenseRequestedDate";"LicenseExpiryDate";"LicenseStatus";"MachineKey";"MachineStatus"  
"Max Muster";"PC#11";"Microsoft Windows 10 Enterprise";"16";"2023-08-02T07:59:23.122043Z";"1900-01-01T00:00:00Z";"1";"EWW_xxxxxxxxxxxxxxxxxxxxxxxxxxx";"1"  
"Ariane Musterfrau";"PC#12";"Microsoft Windows 10 Enterprise";"16";"2023-08-01T07:59:24.6377168Z";"1900-01-01T00:00:00Z";"1";"EWW_xxxxxxxxxxxxxxxxxxxxxxxxx";"1"  

Grüße Uwe
klanax
klanax Sep 08, 2023 at 20:56:34 (UTC)
Goto Top
Hallo Uwe / colinardo

Ich bin erst heute dazu gekommen, dein umfangreiches Script auszuprobieren (vielen Dank dafür!)

Mein Test erfolgte auf einem PC mit
-aktuellem Windows 11 22H2 10.0.22621.2215
-PowerShell 5.1.22621.1778
-PowerShell 7.3.6
-Google Chrome
-Firefox
-Edge (Chromium)

Ich habe dein Script weisungsgemäß angepasst (CSV-Pfad, Browser) und es einmal in PS 5.xxx und PS 7.xxx ausgeführt. Jedes Mal kam eine Fehlermeldung, aber nicht an der gleichen Stelle bzw. mit der gleichen Ursache.
Hier die entsprechenden Meldungsschnipsel:

====================
MIT POWERSHELL 7.3.6
====================

PS C:\Users\Test> [void][console]::ReadKey()
PS C:\Users\Test>
PS C:\Users\Test> # create selenium browser instance
PS C:\Users\Test> $browser = Create-Browser -browser $selenium_browser
Exception:
Line |
  75 |                  throw "Microsoft Edge Browser not installed."  
     |                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | Microsoft Edge Browser not installed.
PS C:\Users\Test> # Navigate to admin center
PS C:\Users\Test> $browser.Url = "https:/admin.microsoft.com"  
InvalidOperation: The property 'Url' cannot be found on this object. Verify that the property exists and can be set.  
PS C:\Users\Test> $browser.Navigate()
InvalidOperation: You cannot call a method on a null-valued expression.
PS C:\Users\Test> # wait until user has finished login procedure
PS C:\Users\Test> do {
>>     write-host "Waiting for login to complete ..." -F Cyan  
>>     sleep 1




==============================
MIT POWERSHELL  5.1.22621.1778
==============================

PS C:\Users\Test> $result = foreach ($user in Get-MGUser -All){
>>     try{
>>         $browser.url = "https://admin.microsoft.com/admin/api/users/$($user.id)/officeInstalls"  
>>         ([xml]$browser.PageSource).ManageOfficeInstallsModel.SoftwareMachineDetails.SoftwareMachineDetails.MachineDetails.Machines.OlsMachineDetail | select @{n='Username';e={$user.DisplayName}},MachineName,MachineOS,OfficeMajorVersion,LastLicenseRequestedDate,LicenseExpiryDate,LicenseStatus,MachineKey,MachineStatus  
>>     }catch{}
>> }
Get-MGUser : Die Benennung "Get-MGUser" wurde nicht als Name eines Cmdlet, einer Funktion, einer Skriptdatei oder  
eines ausführbaren Programms erkannt. Überprüfen Sie die Schreibweise des Namens, oder ob der Pfad korrekt ist (sofern
enthalten), und wiederholen Sie den Vorgang.
In Zeile:1 Zeichen:29
+ $result = foreach ($user in Get-MGUser -All){
+                             ~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (Get-MGUser:String) [], ParentContainsErrorRecordException
    + FullyQualifiedErrorId : CommandNotFoundException

PS C:\Users\Test> # export statistics to csv
PS C:\Users\Test> $result | export-csv -LiteralPath $EXPORTPATH -Delimiter ";" -NoTypeInformation -Encoding UTF8 -verbose  
AUSFÜHRLICH: Ausführen des Vorgangs "Export-Csv" für das Ziel "C:\Users\Public\office_activations.csv".  
Export-Csv : Das Argument kann nicht an den Parameter "InputObject" gebunden werden, da es NULL ist.  
In Zeile:1 Zeichen:11
+ $result | export-csv -LiteralPath $EXPORTPATH -Delimiter ";" -NoTypeI ...  
+           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidData: (:) [Export-Csv], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.ExportCsvCo
   mmand

PS C:\Users\Test> # quit browser and disconnect MG
PS C:\Users\Test> $browser.Quit()
PS C:\Users\Test> Disconnect-MgGraph | out-null


Vielleicht hast du mal etwas Zeit, dir das anzusehen.

Ich werde allerdings in den nächsten Tagen nicht dazu kommen, an dem Problem weiter zu arbeiten.

Viele Grüße
klanax
colinardo
Solution colinardo Sep 09, 2023 updated at 07:28:05 (UTC)
Goto Top
Zu Fehler 1: Bitte zuerst einmal ausschließlich die PS 5 benutzen nicht die 7er, denn die Create-Browser Funktion ist noch nicht "Version 7 ready".

Zu Fehler 2: Bei dir fehlt offensichtlich das Microsoft Graph Users Module, du hast es wohl statt als richtiges Skript per Copy n Paste ausgeführt, denn ansonsten hätte das Skript schon wegen der Requires Zeile 1 angemeckert das bei dir das Modul Microsoft.Graph.Users fehlt! Achtung die Microsoft Graph Module sind granular aufgesplittet es ist also erforderlich das genau dieses Modul installiert ist.
Install-Module -Name Microsoft.Graph.Users
Bedenke auch das PowerShell 5 und 7 separate Modulspeicher haben, wenn du also vorher das Graph Modul unter PS7 installiert hast ist es nicht auch automatisch unter PS5 installiert!
Läuft hier im Test auf Windows 10 und 11 mit Firefox, Chrome und Edge mit PS5 ansonsten einwandfrei.
klanax
klanax Sep 19, 2023 at 13:17:26 (UTC)
Goto Top
Hallo colinardo!

Nachdem ich den PC komplett neu aufgesetzt und die Komponenten wie von dir empfohlen installiert habe, konnte ich tatsächlich die CSV-Dateien erzeugen.

Vielen Dank für deine Hilfe und Geduld und viele Grüße

klanax


BTW:
Dass es von Seiten Microsofts keine bzw. keine einfache Möglichkeit gibt, die Geräte zu ermitteln, auf denen die MS-Produkte aktiviert sind, finde ich nicht gut. Wie soll ich ohne derartige Programmierkenntnisse feststellen können, ob unsere Lizenzen gemäß den MS-Richtlinien aktiviert sind oder ob irgendwo zu viel lizenziert wurde. Im Falle eines Audits würde ich da möglicherweise ganz schön blöd dastehen.