src/OfficeScrubC2R.Core/PreflightService.cs

using System;
using System.Diagnostics;
using System.Linq;
using System.Security.Principal;
using Microsoft.Win32;
 
namespace OfficeScrubC2R
{
    public sealed class PreflightService
    {
        private readonly OfficeDetectionService _detectionService;
        private readonly RegistryAccess _registry;
 
        public PreflightService()
            : this(CreateDefaultRegistry())
        {
        }
 
        private PreflightService(RegistryAccess registry)
            : this(new OfficeDetectionService(registry), registry)
        {
        }
 
        public PreflightService(OfficeDetectionService detectionService, RegistryAccess registry)
        {
            _detectionService = detectionService;
            _registry = registry;
        }
 
        public OfficeC2RState GetState()
        {
            var state = new OfficeC2RState
            {
                Is64BitOperatingSystem = Environment.Is64BitOperatingSystem
            };
 
            AddIdentityState(state);
            AddProducts(state);
            AddPackagePaths(state);
            AddRunningProcesses(state);
            AddServiceEvidence(state);
            AddPendingRebootDeletes(state);
            AddRegistryDiagnostics(state);
 
            if (!state.IsElevated)
            {
                state.Issues.Add(OperationResult.Blocked(
                    "Preflight",
                    "CheckElevation",
                    "Privilege",
                    "Administrator",
                    "Administrator privileges are required before destructive Office cleanup can be enabled.",
                    "OfficeScrubC2R.AdminRequired"));
            }
 
            state.PreflightResults.Add(OperationResult.Completed(
                "Preflight",
                "CollectState",
                "OfficeC2RState",
                "LocalComputer",
                "Collected Office Click-to-Run state."));
 
            return state;
        }
 
        private static void AddIdentityState(OfficeC2RState state)
        {
            try
            {
                var identity = WindowsIdentity.GetCurrent();
                var principal = new WindowsPrincipal(identity);
                state.IsElevated = principal.IsInRole(WindowsBuiltInRole.Administrator);
                state.IsSystem = identity.User != null && identity.User.IsWellKnown(WellKnownSidType.LocalSystemSid);
            }
            catch (Exception exception)
            {
                state.Issues.Add(OperationResult.FromException(
                    "Preflight",
                    "CheckIdentity",
                    "Privilege",
                    "CurrentUser",
                    exception));
            }
        }
 
        private void AddProducts(OfficeC2RState state)
        {
            foreach (var product in _detectionService.GetInstalledProducts())
            {
                state.InstalledProducts.Add(product);
            }
        }
 
        private void AddPackagePaths(OfficeC2RState state)
        {
            foreach (var path in _detectionService.GetPackagePaths())
            {
                state.PackagePaths.Add(path);
            }
        }
 
        private static void AddRunningProcesses(OfficeC2RState state)
        {
            try
            {
                foreach (var process in Process.GetProcesses())
                {
                    try
                    {
                        if (OfficeConstants.OfficeProcesses.Contains(process.ProcessName, StringComparer.OrdinalIgnoreCase))
                        {
                            state.RunningOfficeProcesses.Add(process.ProcessName);
                        }
                    }
                    finally
                    {
                        process.Dispose();
                    }
                }
            }
            catch (Exception exception)
            {
                state.Issues.Add(OperationResult.FromException(
                    "Preflight",
                    "EnumerateProcesses",
                    "Process",
                    "OfficeProcesses",
                    exception));
            }
        }
 
        private void AddServiceEvidence(OfficeC2RState state)
        {
            foreach (var serviceName in OfficeConstants.ClickToRunServiceNames)
            {
                var path = @"SYSTEM\CurrentControlSet\Services\" + serviceName;
                if (_registry.KeyExists(RegistryHive.LocalMachine, path, RegistryView.Default))
                {
                    state.ClickToRunServices.Add(serviceName);
                }
            }
        }
 
        private void AddPendingRebootDeletes(OfficeC2RState state)
        {
            const string keyPath = @"SYSTEM\CurrentControlSet\Control\Session Manager";
            var value = _registry.GetValue(
                RegistryHive.LocalMachine,
                keyPath,
                "PendingFileRenameOperations",
                RegistryView.Default) as string[];
 
            if (value == null)
            {
                return;
            }
 
            foreach (var item in value.Where(item =>
                         !string.IsNullOrWhiteSpace(item) &&
                         (item.IndexOf("Office", StringComparison.OrdinalIgnoreCase) >= 0 ||
                          item.IndexOf("ClickToRun", StringComparison.OrdinalIgnoreCase) >= 0)))
            {
                state.PendingRebootDeletes.Add(item);
            }
        }
 
        private void AddRegistryDiagnostics(OfficeC2RState state)
        {
            foreach (var diagnostic in _registry.Diagnostics)
            {
                state.Issues.Add(diagnostic);
            }
        }
 
        private static RegistryAccess CreateDefaultRegistry()
        {
            return new RegistryAccess(Environment.Is64BitOperatingSystem);
        }
    }
}