Add startup and persistence analysis tools
Add Get-AutoRun.ps1, Get-ScheduledTasks.ps1, and Get-Services.ps1 for analyzing auto-start programs and persistence mechanisms. Get-AutoRun: Run/RunOnce keys, Startup folders, startup tasks Get-ScheduledTasks: Detailed task analysis with filters Get-Services: Service enumeration using WMI/CIM Uses Get-CimInstance for reliable service enumeration, avoiding Get-Service permission issues. Multiple filters and output modes. Update TODO.md.
This commit is contained in:
156
windows/Get-AutoRun.ps1
Normal file
156
windows/Get-AutoRun.ps1
Normal file
@@ -0,0 +1,156 @@
|
||||
# Get-AutoRun.ps1
|
||||
# Lists programs that auto-start via Run/RunOnce keys and Startup folders
|
||||
|
||||
param(
|
||||
[switch]$IncludeDisabled
|
||||
)
|
||||
|
||||
Write-Host "=== Auto-Start Programs ===" -ForegroundColor Cyan
|
||||
Write-Host "Programs configured to run at startup`n"
|
||||
|
||||
$foundAny = $false
|
||||
|
||||
# Registry Run keys to check
|
||||
$runKeys = @(
|
||||
@{Path="HKLM:\Software\Microsoft\Windows\CurrentVersion\Run"; Scope="System (All Users)"},
|
||||
@{Path="HKLM:\Software\Microsoft\Windows\CurrentVersion\RunOnce"; Scope="System (All Users, Once)"},
|
||||
@{Path="HKCU:\Software\Microsoft\Windows\CurrentVersion\Run"; Scope="Current User"},
|
||||
@{Path="HKCU:\Software\Microsoft\Windows\CurrentVersion\RunOnce"; Scope="Current User (Once)"},
|
||||
@{Path="HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Run"; Scope="System (32-bit on 64-bit)"},
|
||||
@{Path="HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\RunOnce"; Scope="System (32-bit, Once)"}
|
||||
)
|
||||
|
||||
# Check Run/RunOnce registry keys
|
||||
Write-Host "--- Registry Run Keys ---" -ForegroundColor Yellow
|
||||
|
||||
foreach ($key in $runKeys) {
|
||||
if (Test-Path $key.Path) {
|
||||
$entries = Get-ItemProperty -Path $key.Path -ErrorAction SilentlyContinue
|
||||
|
||||
if ($entries) {
|
||||
$props = $entries.PSObject.Properties | Where-Object { $_.Name -notmatch "^PS" }
|
||||
|
||||
if ($props) {
|
||||
$foundAny = $true
|
||||
Write-Host "`n$($key.Scope)" -ForegroundColor Green
|
||||
Write-Host " Path: $($key.Path)" -ForegroundColor Gray
|
||||
|
||||
foreach ($prop in $props) {
|
||||
Write-Host " - $($prop.Name):" -ForegroundColor Cyan
|
||||
Write-Host " $($prop.Value)" -ForegroundColor White
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Startup folders
|
||||
Write-Host "`n--- Startup Folders ---" -ForegroundColor Yellow
|
||||
|
||||
$startupFolders = @(
|
||||
@{Path="$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup"; Scope="Current User"},
|
||||
@{Path="$env:ProgramData\Microsoft\Windows\Start Menu\Programs\Startup"; Scope="All Users"}
|
||||
)
|
||||
|
||||
foreach ($folder in $startupFolders) {
|
||||
if (Test-Path $folder.Path) {
|
||||
$items = Get-ChildItem -Path $folder.Path -File -ErrorAction SilentlyContinue
|
||||
|
||||
if ($items) {
|
||||
$foundAny = $true
|
||||
Write-Host "`n$($folder.Scope)" -ForegroundColor Green
|
||||
Write-Host " Path: $($folder.Path)" -ForegroundColor Gray
|
||||
|
||||
foreach ($item in $items) {
|
||||
Write-Host " - $($item.Name)" -ForegroundColor Cyan
|
||||
Write-Host " $($item.FullName)" -ForegroundColor White
|
||||
|
||||
# If it's a shortcut, try to get target
|
||||
if ($item.Extension -eq ".lnk") {
|
||||
try {
|
||||
$shell = New-Object -ComObject WScript.Shell
|
||||
$shortcut = $shell.CreateShortcut($item.FullName)
|
||||
if ($shortcut.TargetPath) {
|
||||
Write-Host " Target: $($shortcut.TargetPath)" -ForegroundColor Gray
|
||||
if ($shortcut.Arguments) {
|
||||
Write-Host " Arguments: $($shortcut.Arguments)" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($shell) | Out-Null
|
||||
} catch {
|
||||
# Silently fail if can't read shortcut
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Task Scheduler startup tasks (basic check)
|
||||
Write-Host "`n--- Task Scheduler (Run at Startup) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
$startupTasks = Get-ScheduledTask -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
$_.Triggers.CimClass.CimClassName -contains "MSFT_TaskBootTrigger" -or
|
||||
$_.Triggers.CimClass.CimClassName -contains "MSFT_TaskLogonTrigger"
|
||||
} |
|
||||
Where-Object { $_.State -ne "Disabled" -or $IncludeDisabled }
|
||||
|
||||
if ($startupTasks) {
|
||||
$foundAny = $true
|
||||
|
||||
foreach ($task in $startupTasks) {
|
||||
$triggerType = if ($task.Triggers.CimClass.CimClassName -contains "MSFT_TaskBootTrigger") {
|
||||
"At system startup"
|
||||
} else {
|
||||
"At user logon"
|
||||
}
|
||||
|
||||
$state = if ($task.State -eq "Disabled") { " (DISABLED)" } else { "" }
|
||||
|
||||
Write-Host "`n - $($task.TaskName)$state" -ForegroundColor Cyan
|
||||
Write-Host " Path: $($task.TaskPath)" -ForegroundColor Gray
|
||||
Write-Host " Trigger: $triggerType" -ForegroundColor Gray
|
||||
Write-Host " State: $($task.State)" -ForegroundColor Gray
|
||||
|
||||
if ($task.Actions.Execute) {
|
||||
Write-Host " Command: $($task.Actions.Execute)" -ForegroundColor White
|
||||
if ($task.Actions.Arguments) {
|
||||
Write-Host " Arguments: $($task.Actions.Arguments)" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Write-Host " No startup tasks found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Error accessing scheduled tasks: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# Windows Services set to Automatic
|
||||
Write-Host "`n--- Services (Automatic Start) ---" -ForegroundColor Yellow
|
||||
try {
|
||||
# Try WMI method first (more reliable)
|
||||
$autoServices = Get-CimInstance Win32_Service -ErrorAction Stop |
|
||||
Where-Object { $_.StartMode -eq "Auto" }
|
||||
|
||||
if ($autoServices) {
|
||||
$foundAny = $true
|
||||
$running = $autoServices | Where-Object { $_.State -eq "Running" }
|
||||
$stopped = $autoServices | Where-Object { $_.State -ne "Running" }
|
||||
|
||||
Write-Host "`nRunning: $($running.Count) | Stopped: $($stopped.Count) | Total: $($autoServices.Count)" -ForegroundColor Green
|
||||
Write-Host "(Use Get-Services.ps1 for detailed service information)" -ForegroundColor Gray
|
||||
} else {
|
||||
Write-Host " No automatic services found" -ForegroundColor Gray
|
||||
}
|
||||
} catch {
|
||||
Write-Host " Unable to enumerate services" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
if (-not $foundAny) {
|
||||
Write-Host "`nNo auto-start programs found" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Write-Host "`nNote: Use -IncludeDisabled to show disabled scheduled tasks" -ForegroundColor Cyan
|
||||
Write-Host "Forensic value: Shows persistence mechanisms and startup performance impacts" -ForegroundColor Cyan
|
||||
138
windows/Get-ScheduledTasks.ps1
Normal file
138
windows/Get-ScheduledTasks.ps1
Normal file
@@ -0,0 +1,138 @@
|
||||
# Get-ScheduledTasks.ps1
|
||||
# Lists scheduled tasks with details
|
||||
|
||||
param(
|
||||
[ValidateSet("All", "Running", "Ready", "Disabled", "Startup")]
|
||||
[string]$Filter = "All",
|
||||
[int]$MaxResults = 50,
|
||||
[switch]$ShowAll
|
||||
)
|
||||
|
||||
Write-Host "=== Scheduled Tasks ===" -ForegroundColor Cyan
|
||||
|
||||
if ($ShowAll) {
|
||||
$MaxResults = [int]::MaxValue
|
||||
}
|
||||
|
||||
$filterDesc = switch ($Filter) {
|
||||
"Running" { "Currently running tasks" }
|
||||
"Ready" { "Tasks ready to run" }
|
||||
"Disabled" { "Disabled tasks" }
|
||||
"Startup" { "Tasks that run at startup/logon" }
|
||||
default { "All scheduled tasks" }
|
||||
}
|
||||
|
||||
Write-Host "$filterDesc`n" -ForegroundColor Yellow
|
||||
|
||||
try {
|
||||
# Get all scheduled tasks
|
||||
$tasks = Get-ScheduledTask -ErrorAction Stop
|
||||
|
||||
# Apply filter
|
||||
$filteredTasks = switch ($Filter) {
|
||||
"Running" { $tasks | Where-Object { $_.State -eq "Running" } }
|
||||
"Ready" { $tasks | Where-Object { $_.State -eq "Ready" } }
|
||||
"Disabled" { $tasks | Where-Object { $_.State -eq "Disabled" } }
|
||||
"Startup" {
|
||||
$tasks | Where-Object {
|
||||
$_.Triggers.CimClass.CimClassName -contains "MSFT_TaskBootTrigger" -or
|
||||
$_.Triggers.CimClass.CimClassName -contains "MSFT_TaskLogonTrigger"
|
||||
}
|
||||
}
|
||||
default { $tasks }
|
||||
}
|
||||
|
||||
if ($filteredTasks) {
|
||||
# Sort by path and name
|
||||
$sortedTasks = $filteredTasks | Sort-Object TaskPath, TaskName
|
||||
|
||||
Write-Host "Found: $($filteredTasks.Count) tasks" -ForegroundColor Green
|
||||
Write-Host "Showing: $(if ($ShowAll) { "All" } else { "Top $MaxResults" })`n" -ForegroundColor Gray
|
||||
|
||||
$count = 0
|
||||
foreach ($task in ($sortedTasks | Select-Object -First $MaxResults)) {
|
||||
$count++
|
||||
|
||||
# Color based on state
|
||||
$nameColor = switch ($task.State) {
|
||||
"Running" { "Green" }
|
||||
"Ready" { "Cyan" }
|
||||
"Disabled" { "Gray" }
|
||||
default { "Yellow" }
|
||||
}
|
||||
|
||||
Write-Host "$count. $($task.TaskPath)$($task.TaskName)" -ForegroundColor $nameColor
|
||||
Write-Host " State: $($task.State)" -ForegroundColor Gray
|
||||
|
||||
# Show triggers
|
||||
if ($task.Triggers) {
|
||||
$triggerInfo = @()
|
||||
foreach ($trigger in $task.Triggers) {
|
||||
$triggerType = switch ($trigger.CimClass.CimClassName) {
|
||||
"MSFT_TaskBootTrigger" { "At system startup" }
|
||||
"MSFT_TaskLogonTrigger" { "At user logon" }
|
||||
"MSFT_TaskDailyTrigger" { "Daily" }
|
||||
"MSFT_TaskTimeTrigger" { "At specific time" }
|
||||
"MSFT_TaskEventTrigger" { "On event" }
|
||||
"MSFT_TaskIdleTrigger" { "On idle" }
|
||||
default { $trigger.CimClass.CimClassName -replace "MSFT_Task", "" -replace "Trigger", "" }
|
||||
}
|
||||
$triggerInfo += $triggerType
|
||||
}
|
||||
Write-Host " Trigger: $($triggerInfo -join ', ')" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
# Show action
|
||||
if ($task.Actions) {
|
||||
foreach ($action in $task.Actions) {
|
||||
if ($action.Execute) {
|
||||
Write-Host " Execute: $($action.Execute)" -ForegroundColor White
|
||||
if ($action.Arguments) {
|
||||
Write-Host " Arguments: $($action.Arguments)" -ForegroundColor Gray
|
||||
}
|
||||
if ($action.WorkingDirectory) {
|
||||
Write-Host " WorkDir: $($action.WorkingDirectory)" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Show last/next run time
|
||||
$taskInfo = Get-ScheduledTaskInfo -TaskName $task.TaskName -TaskPath $task.TaskPath -ErrorAction SilentlyContinue
|
||||
if ($taskInfo) {
|
||||
if ($taskInfo.LastRunTime -and $taskInfo.LastRunTime.Year -gt 1) {
|
||||
Write-Host " Last Run: $($taskInfo.LastRunTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray
|
||||
}
|
||||
if ($taskInfo.NextRunTime -and $taskInfo.NextRunTime.Year -gt 1) {
|
||||
Write-Host " Next Run: $($taskInfo.NextRunTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Gray
|
||||
}
|
||||
if ($taskInfo.LastTaskResult -ne 0) {
|
||||
Write-Host " Last Result: 0x$($taskInfo.LastTaskResult.ToString('X'))" -ForegroundColor $(if ($taskInfo.LastTaskResult -eq 0) { "Green" } else { "Red" })
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
if ($filteredTasks.Count -gt $MaxResults -and -not $ShowAll) {
|
||||
Write-Host "... and $($filteredTasks.Count - $MaxResults) more (use -ShowAll to see all)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`n=== Summary ===" -ForegroundColor Cyan
|
||||
$states = $filteredTasks | Group-Object State
|
||||
foreach ($state in $states) {
|
||||
Write-Host "$($state.Name): $($state.Count)" -ForegroundColor Green
|
||||
}
|
||||
|
||||
} else {
|
||||
Write-Host "No tasks found matching filter" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
Write-Host "Try running as Administrator for full task access" -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host "`nFilters: -Filter All|Running|Ready|Disabled|Startup" -ForegroundColor Cyan
|
||||
Write-Host "Use -ShowAll to see all tasks (default: top $MaxResults)" -ForegroundColor Cyan
|
||||
111
windows/Get-Services.ps1
Normal file
111
windows/Get-Services.ps1
Normal file
@@ -0,0 +1,111 @@
|
||||
# Get-Services.ps1
|
||||
# Lists Windows services with details
|
||||
|
||||
param(
|
||||
[ValidateSet("All", "Running", "Stopped", "Automatic", "Manual", "Disabled")]
|
||||
[string]$Filter = "All",
|
||||
[int]$MaxResults = 50,
|
||||
[switch]$ShowAll
|
||||
)
|
||||
|
||||
Write-Host "=== Windows Services ===" -ForegroundColor Cyan
|
||||
|
||||
if ($ShowAll) {
|
||||
$MaxResults = [int]::MaxValue
|
||||
}
|
||||
|
||||
$filterDesc = switch ($Filter) {
|
||||
"Running" { "Running services" }
|
||||
"Stopped" { "Stopped services" }
|
||||
"Automatic" { "Services set to start automatically" }
|
||||
"Manual" { "Manual start services" }
|
||||
"Disabled" { "Disabled services" }
|
||||
default { "All services" }
|
||||
}
|
||||
|
||||
Write-Host "$filterDesc`n" -ForegroundColor Yellow
|
||||
|
||||
try {
|
||||
# Use WMI/CIM for reliable service enumeration
|
||||
$services = Get-CimInstance Win32_Service -ErrorAction Stop
|
||||
|
||||
# Apply filter
|
||||
$filteredServices = switch ($Filter) {
|
||||
"Running" { $services | Where-Object { $_.State -eq "Running" } }
|
||||
"Stopped" { $services | Where-Object { $_.State -eq "Stopped" } }
|
||||
"Automatic" { $services | Where-Object { $_.StartMode -eq "Auto" } }
|
||||
"Manual" { $services | Where-Object { $_.StartMode -eq "Manual" } }
|
||||
"Disabled" { $services | Where-Object { $_.StartMode -eq "Disabled" } }
|
||||
default { $services }
|
||||
}
|
||||
|
||||
if ($filteredServices) {
|
||||
# Sort by state then name
|
||||
$sortedServices = $filteredServices | Sort-Object State, DisplayName
|
||||
|
||||
Write-Host "Found: $($filteredServices.Count) services" -ForegroundColor Green
|
||||
Write-Host "Showing: $(if ($ShowAll) { "All" } else { "Top $MaxResults" })`n" -ForegroundColor Gray
|
||||
|
||||
$count = 0
|
||||
foreach ($service in ($sortedServices | Select-Object -First $MaxResults)) {
|
||||
$count++
|
||||
|
||||
# Color based on status
|
||||
$nameColor = switch ($service.State) {
|
||||
"Running" { "Green" }
|
||||
"Stopped" { "Gray" }
|
||||
default { "Yellow" }
|
||||
}
|
||||
|
||||
$statusSymbol = if ($service.State -eq "Running") { "●" } else { "○" }
|
||||
|
||||
Write-Host "$count. $statusSymbol $($service.DisplayName)" -ForegroundColor $nameColor
|
||||
Write-Host " Name: $($service.Name)" -ForegroundColor Gray
|
||||
Write-Host " Status: $($service.State) | Start Mode: $($service.StartMode)" -ForegroundColor Gray
|
||||
|
||||
if ($service.PathName) {
|
||||
Write-Host " Path: $($service.PathName)" -ForegroundColor White
|
||||
}
|
||||
if ($service.Description) {
|
||||
Write-Host " Description: $($service.Description)" -ForegroundColor Gray
|
||||
}
|
||||
if ($service.StartName) {
|
||||
Write-Host " Run As: $($service.StartName)" -ForegroundColor Gray
|
||||
}
|
||||
if ($service.ProcessId -and $service.ProcessId -ne 0) {
|
||||
Write-Host " PID: $($service.ProcessId)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
if ($filteredServices.Count -gt $MaxResults -and -not $ShowAll) {
|
||||
Write-Host "... and $($filteredServices.Count - $MaxResults) more (use -ShowAll to see all)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
# Summary
|
||||
Write-Host "`n=== Summary ===" -ForegroundColor Cyan
|
||||
|
||||
$stateGroups = $filteredServices | Group-Object State
|
||||
Write-Host "By Status:" -ForegroundColor Yellow
|
||||
foreach ($group in $stateGroups) {
|
||||
Write-Host " $($group.Name): $($group.Count)" -ForegroundColor Green
|
||||
}
|
||||
|
||||
$startModeGroups = $filteredServices | Group-Object StartMode
|
||||
Write-Host "`nBy Start Mode:" -ForegroundColor Yellow
|
||||
foreach ($group in $startModeGroups) {
|
||||
Write-Host " $($group.Name): $($group.Count)" -ForegroundColor Green
|
||||
}
|
||||
|
||||
} else {
|
||||
Write-Host "No services found matching filter" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
} catch {
|
||||
Write-Host "Error: $_" -ForegroundColor Red
|
||||
}
|
||||
|
||||
Write-Host "`nFilters: -Filter All|Running|Stopped|Automatic|Manual|Disabled" -ForegroundColor Cyan
|
||||
Write-Host "Use -ShowAll to see all services (default: top $MaxResults)" -ForegroundColor Cyan
|
||||
Write-Host "`nForensic note: Check for suspicious service names, paths, or 'Run As' accounts" -ForegroundColor Cyan
|
||||
Reference in New Issue
Block a user