Public/Start-SystemMonitor.ps1
<#
.SYNOPSIS Monitors system for software and process changes. .COMPONENT QuickSoft .DESCRIPTION Provides real-time monitoring of: - Software installations and uninstallations - Process starts and stops Logs all changes to a specified file and displays them in the console. .PARAMETER OutPath The directory where the log file will be created. Defaults to the system drive (typically C:). .EXAMPLE Start-SystemMonitor Starts monitoring using the default output location. .EXAMPLE Start-SystemMonitor -OutPath "D:\Logs" Starts monitoring with a custom log file location. .OUTPUTS Creates a log file named "SystemMonitor.txt" in the specified directory. .NOTES Name: Start-SystemMonitor Author: AutomateSilent Version: 1.0.0 Last Updated: 2025-01-31 #> function Start-SystemMonitor { [CmdletBinding()] param ( [Parameter(Position = 0)] [string]$OutPath = "$env:HOMEDRIVE" ) try { # Resolve the full path $OutPath = [System.IO.Path]::GetFullPath($OutPath) # Create directory if it doesn't exist if (-not (Test-Path -Path $OutPath -PathType Container)) { $null = New-Item -ItemType Directory -Path $OutPath -Force Write-Verbose "Created directory: $OutPath" } # Define and create the output file $outputFile = Join-Path -Path $OutPath -ChildPath "SystemMonitor.txt" if (-not (Test-Path -Path $outputFile)) { $null = New-Item -ItemType File -Path $outputFile -Force Write-Verbose "Created log file: $outputFile" } # Test write access $testContent = "Testing write access..." Set-Content -Path $outputFile -Value $testContent -ErrorAction Stop Write-Verbose "Verified write access to log file" } catch { Write-Error "Failed to setup logging: $_" throw "Unable to create or access log file at: $outputFile" } # Registry paths to monitor $registryPaths = @( "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*", "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" ) # List of processes to ignore $ignoreProcesses = @( 'svchost', 'RuntimeBroker', 'backgroundTaskHost', 'conhost', 'WmiPrvSE' ) # Helper function to write output function Write-OutputBoth { param( [string]$Message, [string]$ForegroundColor = 'White', [string]$Category = 'Process' ) Write-Host "----------------------------------------" -ForegroundColor Blue Write-Host "-------------$Category-------------" -ForegroundColor Cyan Write-Host "----------------------------------------" -ForegroundColor Blue Write-Host $Message -ForegroundColor $ForegroundColor Write-Host "----------------------------------------" -ForegroundColor Blue try { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Add-Content -Path $outputFile -Value @( "----------------------------------------" "-------------$Category-------------" "----------------------------------------" $Message "----------------------------------------" ) } catch { Write-Warning "Failed to write to log file: $_" } } # Function to get software list function Get-InstalledSoftware { $software = @() foreach ($path in $registryPaths) { $items = Get-ItemProperty -Path $path -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -and $_.UninstallString } foreach ($item in $items) { $GUID = $null if ($item.UninstallString -match "({[A-Z0-9-]+})") { $GUID = $matches[1] } $software += [PSCustomObject]@{ DisplayName = $item.DisplayName Version = $item.DisplayVersion Architecture = if($path -like "*WOW6432Node*") {"32-bit"} else {"64-bit"} GUID = $GUID Publisher = $item.Publisher } } } return $software } # Initialize monitoring try { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" Set-Content -Path $outputFile -Value "System Monitoring Started at: $timestamp" -Force # Get initial states $initialProcesses = Get-Process | Where-Object { $_.ProcessName -notin $ignoreProcesses } | Select-Object Id, ProcessName, Path, StartTime $initialSoftware = Get-InstalledSoftware Write-Host "Monitoring processes and software changes... Press Ctrl+C to stop" -ForegroundColor Cyan Write-Host "Logging to: $outputFile" -ForegroundColor Cyan # Main monitoring loop while ($true) { # Monitor Processes $currentProcesses = Get-Process | Where-Object { $_.ProcessName -notin $ignoreProcesses } | Select-Object Id, ProcessName, Path, StartTime $processComparison = Compare-Object -ReferenceObject $initialProcesses -DifferenceObject $currentProcesses -Property Id # Handle new processes foreach ($process in ($processComparison | Where-Object { $_.SideIndicator -eq '=>' })) { $processDetails = Get-Process -Id $process.Id -ErrorAction SilentlyContinue if ($processDetails) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $message = @" New [+] '$($processDetails.ProcessName)' Detection Time: $timestamp Process Start: $($processDetails.StartTime) Name: $($processDetails.ProcessName) PID: $($processDetails.Id) Path: $($processDetails.Path) "@ Write-OutputBoth -Message $message -ForegroundColor Green -Category 'Process' } } # Handle closed processes foreach ($process in ($processComparison | Where-Object { $_.SideIndicator -eq '<=' })) { $closedProcess = $initialProcesses | Where-Object { $_.Id -eq $process.Id } if ($closedProcess) { $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $message = @" Closed [-] '$($closedProcess.ProcessName)' Detection Time: $timestamp Process Start: $($closedProcess.StartTime) Process End: $timestamp Name: $($closedProcess.ProcessName) PID: $($closedProcess.Id) Path: $($closedProcess.Path) "@ Write-OutputBoth -Message $message -ForegroundColor Yellow -Category 'Process' } } # Monitor Software Changes $currentSoftware = Get-InstalledSoftware $softwareComparison = Compare-Object -ReferenceObject $initialSoftware -DifferenceObject $currentSoftware -Property DisplayName # Handle new software foreach ($software in ($softwareComparison | Where-Object { $_.SideIndicator -eq '=>' })) { $newSoftware = $currentSoftware | Where-Object { $_.DisplayName -eq $software.DisplayName } $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $message = @" ====== Detection Information for: $($newSoftware.DisplayName) ====== Version: $($newSoftware.Version) Architecture: $($newSoftware.Architecture) Detection Time: $timestamp Publisher: $($newSoftware.Publisher) GUID: $($newSoftware.GUID) "@ Write-OutputBoth -Message $message -ForegroundColor Green -Category 'Software' } # Handle removed software foreach ($software in ($softwareComparison | Where-Object { $_.SideIndicator -eq '<=' })) { $removedSoftware = $initialSoftware | Where-Object { $_.DisplayName -eq $software.DisplayName } $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $message = @" ====== Detection Information for: $($removedSoftware.DisplayName) [REMOVED] ====== Version: $($removedSoftware.Version) Architecture: $($removedSoftware.Architecture) Detection Time: $timestamp Publisher: $($removedSoftware.Publisher) GUID: $($removedSoftware.GUID) "@ Write-OutputBoth -Message $message -ForegroundColor Yellow -Category 'Software' } # Update initial states $initialProcesses = $currentProcesses $initialSoftware = $currentSoftware Start-Sleep -Milliseconds 250 } } catch { Write-Warning "Monitoring stopped: $_" } finally { Write-Host "`nMonitoring ended. Log file: $outputFile" -ForegroundColor Cyan } } |