diff --git a/ee/allowedcmd/cmd_windows.go b/ee/allowedcmd/cmd_windows.go index 5425a5926..c2fed5cd1 100644 --- a/ee/allowedcmd/cmd_windows.go +++ b/ee/allowedcmd/cmd_windows.go @@ -31,6 +31,10 @@ func Ipconfig(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "ipconfig.exe"), arg...) } +func MdmDiagnosticsTool(ctx context.Context, arg ...string) (*exec.Cmd, error) { + return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "mdmdiagnosticstool.exe"), arg...) +} + func Powercfg(ctx context.Context, arg ...string) (*exec.Cmd, error) { return validatedCommand(ctx, filepath.Join(os.Getenv("WINDIR"), "System32", "powercfg.exe"), arg...) } diff --git a/ee/debug/checkups/checkups.go b/ee/debug/checkups/checkups.go index 2cbbbd4e8..43566bb5c 100644 --- a/ee/debug/checkups/checkups.go +++ b/ee/debug/checkups/checkups.go @@ -119,6 +119,7 @@ func checkupsFor(k types.Knapsack, target targetBits) []checkupInt { {&osqConfigConflictCheckup{}, doctorSupported | flareSupported}, {&serverDataCheckup{k: k}, doctorSupported | flareSupported | logSupported}, {&osqDataCollector{k: k}, doctorSupported | flareSupported}, + {&intuneCheckup{}, flareSupported}, } checkupsToRun := make([]checkupInt, 0) diff --git a/ee/debug/checkups/intune_other.go b/ee/debug/checkups/intune_other.go new file mode 100644 index 000000000..ce3b51f1d --- /dev/null +++ b/ee/debug/checkups/intune_other.go @@ -0,0 +1,35 @@ +//go:build !windows +// +build !windows + +package checkups + +import ( + "context" + "io" +) + +type intuneCheckup struct{} + +func (i *intuneCheckup) Name() string { + return "" +} + +func (i *intuneCheckup) Run(_ context.Context, _ io.Writer) error { + return nil +} + +func (i *intuneCheckup) ExtraFileName() string { + return "" +} + +func (i *intuneCheckup) Status() Status { + return Informational +} + +func (i *intuneCheckup) Summary() string { + return "" +} + +func (i *intuneCheckup) Data() any { + return nil +} diff --git a/ee/debug/checkups/intune_windows.go b/ee/debug/checkups/intune_windows.go new file mode 100644 index 000000000..b84805bc1 --- /dev/null +++ b/ee/debug/checkups/intune_windows.go @@ -0,0 +1,115 @@ +//go:build windows +// +build windows + +package checkups + +import ( + "archive/zip" + "context" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/kolide/launcher/ee/agent" + "github.com/kolide/launcher/ee/allowedcmd" +) + +type intuneCheckup struct { + summary string +} + +func (i *intuneCheckup) Name() string { + return "Intune" +} + +func (i *intuneCheckup) Run(ctx context.Context, extraWriter io.Writer) error { + // Other areas of interest: https://learn.microsoft.com/en-us/mem/intune/remote-actions/collect-diagnostics + + zipWriter := zip.NewWriter(extraWriter) + defer zipWriter.Close() + + if err := agentLogs(zipWriter); err != nil { + i.summary += fmt.Sprintf("Failed to collect Intune agent logs: %v. ", err) + } + + if err := installLogs(zipWriter); err != nil { + i.summary += fmt.Sprintf("Failed to collect Intune install logs: %v. ", err) + } + + if err := diagnostics(ctx, zipWriter); err != nil { + i.summary += fmt.Sprintf("Failed to collect Intune diagnostics: %v. ", err) + } + + i.summary = strings.TrimSpace(i.summary) + + return nil +} + +func agentLogs(zipWriter *zip.Writer) error { + agentLogsPathPattern := filepath.Join(os.Getenv("SYSTEMROOT"), "ProgramData", "Microsoft", "IntuneManagementExtension", "Logs", "*") + matches, err := filepath.Glob(agentLogsPathPattern) + if err != nil { + return fmt.Errorf("globbing for agent logs at %s: %w", agentLogsPathPattern, err) + } + + for _, match := range matches { + if err := addFileToZip(zipWriter, match); err != nil { + return fmt.Errorf("adding %s to zip: %w", match, err) + } + } + + return nil +} + +func installLogs(zipWriter *zip.Writer) error { + installLogsPathPattern := filepath.Join(os.Getenv("WINDIR"), "System32", "config", "systemprofile", "AppData", "Local", "mdm", "*.log") + matches, err := filepath.Glob(installLogsPathPattern) + if err != nil { + return fmt.Errorf("globbing for install logs at %s: %w", installLogsPathPattern, err) + } + + for _, match := range matches { + if err := addFileToZip(zipWriter, match); err != nil { + return fmt.Errorf("adding %s to zip: %w", match, err) + } + } + + return nil +} + +func diagnostics(ctx context.Context, zipWriter *zip.Writer) error { + tempDir, err := agent.MkdirTemp("mdm-diagnostics") + if err != nil { + return fmt.Errorf("creating temp dir: %w", err) + } + defer os.RemoveAll(tempDir) + + tempOutfile := filepath.Join(tempDir, "MdmDiagnosticReport.zip") + + cmd, err := allowedcmd.MdmDiagnosticsTool(ctx, "-zip", tempOutfile) + if cmd == nil { + return nil + } else if err != nil { + return fmt.Errorf("creating diagnostics command: %w", err) + } + + return addFileToZip(zipWriter, tempOutfile) +} + +func (i *intuneCheckup) ExtraFileName() string { + return "intune.zip" +} + +func (i *intuneCheckup) Status() Status { + return Informational +} + +func (i *intuneCheckup) Summary() string { + return i.summary +} + +func (i *intuneCheckup) Data() any { + return nil +}