IME Log summarizer

IME Log Summarizer für Microsoft Intune

In diesem kurzen Blog möchte ich dir zeigen, wie du mit GPT eine Zusammenfassung des Intune Management Extension Logs erstellen kannst. Dieses Skript liest die Logdatei der Intune Management Extension im Ordner ProgramData/Microsoft/IntuneManagementExtension/Logs aus und übergibt den aktuellsten Inhalt des Logs an GPT, sodass du weniger Zeit damit verbringst, dich durch tausende unübersichtliche Logzeilen zu scrollen.

Die Fehlersuche bei der App- und Richtlinienverteilung auf Windows-Endgeräten landet fast immer bei genau dieser einen Logdatei, und sie von Hand zu lesen ist mühsam. Ein IME Log Summarizer macht aus dem rohen, ausführlichen Log einen kurzen, gut lesbaren Bericht, der hervorhebt, was auf dem Gerät tatsächlich schiefgelaufen ist. Wenn du deine Geräte bereits mit Microsoft Intune verwaltest, ist das ein schneller Mehrwert, den du in wenigen Minuten einrichten kannst.

IME Log Summarizer

Wie funktioniert das

GPT verwendet den Inhalt des Logs und erstellt eine Zusammenfassung, weist dich aber auch auf mögliche Fehler auf dem Gerät hin. Das ist ein sehr einfacher Ansatz, doch mein Ziel ist es, dir zu zeigen, wie du KI im Device Management einsetzen kannst, um mehr Einblicke zu gewinnen und Zeit zu sparen. Statt nach Schlüsselwörtern zu suchen, liest der IME Log Summarizer den aktuellsten Teil des Logs und erklärt in verständlicher Sprache, welche Apps oder Richtlinien fehlgeschlagen sind und warum.

Der Ablauf ist bewusst minimal gehalten: die Logdatei einlesen, sie auf den neuesten Inhalt kürzen, damit sie in das Kontextfenster des Modells passt, an ein Azure OpenAI Deployment senden und das Ergebnis ausgeben. Du kannst das Skript lokal auf einem einzelnen Gerät ausführen oder in der fortgeschrittenen Variante das Log remote für jedes registrierte Gerät abrufen.

Vorbereitung und Voraussetzungen

Du musst ein Azure OpenAI Deployment erstellen. Sobald das erledigt ist, musst du den azure_endpoint und den api_key in das Skript eintragen. Für die fortgeschrittene Remote-Variante benötigst du außerdem eine Entra-ID-App-Registrierung mit Graph-Berechtigungen, damit der IME Log Summarizer die Log-Sammlung von Intune anfordern und herunterladen kann.

Einfacher Ansatz

Hier findest du ein einfaches Skript, das lokal auf einem Gerät funktioniert. Dieser lokale IME Log Summarizer eignet sich perfekt für schnelle Prüfungen, während du bereits an dem Rechner angemeldet bist, den du untersuchst.

Github

import os
from openai import AzureOpenAI

file_path = os.path.join('C:\\', 'ProgramData', 'Microsoft', 'IntuneManagementExtension', 'Logs', 'IntuneManagementExtension.log')
with open(file_path, 'r') as file:
    log_content = file.read()

log_content = log_content[-128000:]

prompt = f"""
You are an senior intune engineer. Your task is to find errors in the [Intune Management Extension log]. Give the user a summary of the log an point him to potential errors on an structured way. Explain to the user what is mean and how he can check and troubleshoot this.

[Intune Management Extension log]
{log_content}
[END Intune Management Extension log]
"""

client = AzureOpenAI(
    azure_endpoint="https://YOUR_ENDPOINT.openai.azure.com/",
    api_key="YOUR_APIKEY",
    api_version="2024-02-01",
)

completion = client.chat.completions.create(
    model="gpt-4o",
    temperature=0,
    messages=[
        {
            "role": "user",
            "content": prompt,
        }
    ]
)

print(completion.choices[0].message.content)

Fortgeschrittener Ansatz

Bei diesem Ansatz ermöglichen wir es dem Skript zusätzlich, remote zu arbeiten. Dafür müssen wir die Logdatei vom Gerät hochladen und für die Zusammenfassung verwenden. Das macht den IME Log Summarizer auch im großen Maßstab nützlich, denn so kannst du ein Gerät analysieren, auf das du keinen physischen Zugriff hast. Das funktioniert folgendermaßen:

IME Log Summarizer

Bevor wir das Skript ausführen, müssen wir eine Voraussetzung erfüllen. Wir benötigen eine App-Registrierung mit den folgenden Berechtigungen:

IME Log Summarizer

Das ist das vollständige Skript:

Github

"""This script is used to summarize the Intune Management Extension (IME) logs for a given device."""

import os
import urllib.request
import ssl
import zipfile
import requests
import msal

from openai import AzureOpenAI

from loguru import logger

CLIENT_ID = "CLIENT_ID"
TENANT_ID = "TENANT_ID"
CLIENT_SECRET = "CLIENT_SECRET"

OPEN_AI_API_KEY = "YOUR_API_KEY"
OPEN_AI_ENDPOINT = "https://YOUR_ENDPOINT.openai.azure.com/"

DEVICE_ID = "INTUNE_DEVICE_ID"


def get_access_token(client_id, client_secret, tenant_id):
    """Get an access token for the Microsoft Graph API using the"""
    authority = f"https://login.microsoftonline.com/{tenant_id}"
    app = msal.ConfidentialClientApplication(
        client_id,
        authority=authority,
        client_credential=client_secret,
    )
    result = app.acquire_token_for_client(
        scopes=["https://graph.microsoft.com/.default"]
    )
    if "access_token" in result:
        return result["access_token"]
    else:
        raise Exception("Could not obtain access token")  # pylint: disable=broad-exception-raised


def collect_logs(device_id, client_id, client_secret, tenant_id):
    """Load all apps from the Microsoft Graph API"""
    token = get_access_token(client_id, client_secret, tenant_id)
    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    response = requests.post(
        f"https://graph.microsoft.com/beta/deviceManagement/managedDevices('{device_id}')/createDeviceLogCollectionRequest",
        json={"templateType": 0},
        headers=headers,
    )
    print(response.json())
    response.raise_for_status()
    return response.json()["value"]


def get_log_status(device_id, client_id, client_secret, tenant_id):
    """Load all apps from the Microsoft Graph API"""
    token = get_access_token(client_id, client_secret, tenant_id)
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
        "consistencylevel": "eventual",
    }
    response = requests.get(
        f"https://graph.microsoft.com/beta/deviceManagement/managedDevices('{device_id}')/logCollectionRequests?$select=id,status,managedDeviceId,errorCode,requestedDateTimeUTC,receivedDateTimeUTC,initiatedByUserPrincipalName&",
        headers=headers,
    )
    response.raise_for_status()
    logs = response.json()["value"]
    logs.sort(key=lambda x: x["requestedDateTimeUTC"])
    return logs[-1]


def download_logs(device_id, log_id, client_id, client_secret, tenant_id):
    """Load all apps from the Microsoft Graph API"""
    token = get_access_token(client_id, client_secret, tenant_id)
    headers = {
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json",
    }
    response = requests.post(
        f"https://graph.microsoft.com/beta/deviceManagement/managedDevices('{device_id}')/logCollectionRequests('{log_id}')/createDownloadUrl",
        headers=headers,
        json={},
    )
    response.raise_for_status()
    return response.json()["value"]


def summarize_logs(file_path):
    """Summarize the Intune Management Extension logs"""
    with open(file_path, "r") as file:
        log_content = file.read()

    log_content = log_content[-128000:]

    prompt = f"""
    You are an senior intune engineer. Your task is to find errors in the [Intune Management Extension log]. Give the user a summary of the log an point him to potential errors on an structured way. Explain to the user what is mean and how he can check and troubleshoot this.

    [Intune Management Extension log]
    {log_content}
    [END Intune Management Extension log]
    """

    client = AzureOpenAI(
        azure_endpoint=OPEN_AI_ENDPOINT,
        api_key=OPEN_AI_API_KEY,
        api_version="2024-02-01",
    )

    completion = client.chat.completions.create(
        model="gpt-4o",
        temperature=0,
        messages=[
            {
                "role": "user",
                "content": prompt,
            }
        ],
    )

    print(completion.choices[0].message.content)


def main():
    """Main function for the Streamlit app"""
    logger.info("Starting IME Summarizer")
    log_status = get_log_status(DEVICE_ID, CLIENT_ID, CLIENT_SECRET, TENANT_ID)
    logger.info(log_status)
    if log_status["status"] != "completed":
        logger.error("Log collection is not completed yet")
        return
    log_id = log_status["id"].replace(f"{DEVICE_ID}_", "")
    log_download_url = download_logs(
        DEVICE_ID, log_id, CLIENT_ID, CLIENT_SECRET, TENANT_ID
    ).replace('"', "")
    # Download zip
    logger.info(log_download_url)

    ssl._create_default_https_context = ssl._create_unverified_context
    urllib.request.urlretrieve(log_download_url, "logs.zip")
    # uzip logs.zip
    with zipfile.ZipFile("logs.zip", "r") as zip_ref:
        zip_ref.extractall("logs")

    # find folder
    log_folder = None
    for folder in os.listdir("logs"):
        if "ProgramData_Microsoft_IntuneManagementExtension_Logs" in folder:
            log_folder = folder
            break
    logger.info(log_folder)
    # Summarize logs
    summarize_logs(f"logs/{log_folder}/intunemanagementextension.log")

if __name__ == "__main__":
    main()

Um die Log-Sammlung zu starten, kannst du vorab Folgendes ausführen:

def main():
    """Start log collection"""
    log = collect_logs(DEVICE_ID, CLIENT_ID, CLIENT_SECRET, TENANT_ID)
    logger.info(log)

Die Ausgabe:

IME Log Summarizer

Fazit zum IME Log Summarizer

Mehr braucht es nicht, um einen funktionierenden IME Log Summarizer für Microsoft Intune aufzusetzen. Mit ein paar Zeilen Python und einem Azure OpenAI Deployment erhältst du ein Werkzeug, das das unübersichtliche Log für dich liest und dir eine klare Zusammenfassung der Fehler zurückgibt. Wenn du weitere Ideen zur Intune-Automatisierung suchst, schau dir die anderen Beiträge auf jannikreinhard.com an und passe diesen IME Log Summarizer an deinen eigenen Workflow an.

Zwei häufige Stolperfallen solltest du im Blick behalten. Die erste ist das Kontextfenster: Das Skript behält nur die letzten 128.000 Zeichen des Logs, sodass ein Fehler, der früher am Tag aufgetreten ist, eventuell bereits abgeschnitten wurde. Wenn du einem bestimmten Fehler nachgehst, notiere dir zuerst den Zeitstempel und stelle sicher, dass er in den Ausschnitt fällt, den du an das Modell sendest. Die zweite betrifft das Vertrauen: GPT erkennt Muster gut, kann einen unbekannten Fehlercode aber falsch deuten, prüfe seine Ergebnisse daher immer gegen das rohe Log, bevor du danach handelst.

2 thoughts on “IME Log Summarizer für Microsoft Intune

  1. This script is not working at all, the error msg is pasted below for you reference

    At line:10 char:1

    • from openai import AzureOpenAI
    • ~~~~
      The ‘from’ keyword is not supported in this version of the language.
      At line:12 char:1
    • from loguru import logger
    • ~~~~
      The ‘from’ keyword is not supported in this version of the language.
      At line:24 char:31
    • def get_access_token(client_id, client_secret, tenant_id):
    • ~
      Missing argument in parameter list.
      At line:28 char:18
    • client_id,
    • ~
      Missing argument in parameter list.
      At line:30 char:41
    • client_credential=client_secret,
    • ~
      Missing expression after ‘,’ in pipeline element.
      At line:35 char:7
    • if “access_token” in result:
    • ~
      Missing ‘(‘ after ‘if’ in if statement.
      At line:35 char:23
    • if “access_token” in result:
    • ~~
      Unexpected token ‘in’ in expression or statement.
      At line:41 char:27
    • def collect_logs(device_id, client_id, client_secret, tenant_id):
    • ~
      Missing argument in parameter list.
      At line:43 char:39
    • token = get_access_token(client_id, client_secret, tenant_id)
    • ~
      Missing argument in parameter list.
      At line:44 char:31
    • headers = {“Authorization”: f”Bearer {token}”, “Content-Type”: “a …
    • ~ Unexpected token ‘:’ in expression or statement. Not all parse errors were reported. Correct the reported errors and try again.

      • CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
      • FullyQualifiedErrorId : ReservedKeywordNotAllowed

Comments are closed.