Add Windows forensic artifact collection toolkit
Add PowerShell scripts for collecting forensic artifacts: - USB/storage devices, mounted drives, portable devices - Network history and hotspot connections - Recent documents (OpenSavePidlMRU with PIDL parsing) - System info and user enumeration with multiple output modes Includes TODO.md for planned artifacts and updated README.
This commit is contained in:
67
TODO.md
Normal file
67
TODO.md
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# Forensic Artifacts TODO
|
||||||
|
|
||||||
|
## Windows Forensic Scripts
|
||||||
|
|
||||||
|
### Completed
|
||||||
|
- [x] USB Storage (USBSTOR)
|
||||||
|
- [x] Mounted Devices
|
||||||
|
- [x] USB Devices (VID/PID)
|
||||||
|
- [x] Portable Devices
|
||||||
|
- [x] Network Connection History
|
||||||
|
- [x] Hotspot Connections
|
||||||
|
- [x] Recent Documents (RecentDocs)
|
||||||
|
|
||||||
|
### User Activity Artifacts
|
||||||
|
- [ ] UserAssist - Programs run by user through Windows Explorer
|
||||||
|
- [ ] ShimCache (AppCompatCache) - Executable files that have been run
|
||||||
|
- [ ] AmCache - Program execution with file hashes and timestamps
|
||||||
|
- [ ] Jump Lists - Recently accessed files per application
|
||||||
|
- [ ] Prefetch files - Program execution history with run counts
|
||||||
|
- [ ] BAM/DAM - Background Activity Moderator (program execution timestamps)
|
||||||
|
|
||||||
|
### Browser & Search History
|
||||||
|
- [ ] Browser history - Edge, Chrome, Firefox artifacts
|
||||||
|
- [ ] Typed URLs - URLs manually typed in browsers
|
||||||
|
- [ ] Search terms - Windows Search history
|
||||||
|
|
||||||
|
### File Access
|
||||||
|
- [ ] LNK files - Shortcut files showing file access
|
||||||
|
- [ ] Recycle Bin - Deleted files
|
||||||
|
- [ ] Shell Bags - Folder access history
|
||||||
|
|
||||||
|
### System Information
|
||||||
|
- [ ] Computer name - System identification
|
||||||
|
- [ ] Timezone - System timezone settings
|
||||||
|
- [ ] Last shutdown time
|
||||||
|
- [ ] Installed programs - Software inventory
|
||||||
|
- [ ] System uptime history
|
||||||
|
|
||||||
|
### Persistence Mechanisms
|
||||||
|
- [ ] Run/RunOnce keys - Programs that auto-start
|
||||||
|
- [ ] Scheduled tasks
|
||||||
|
- [ ] Services
|
||||||
|
- [ ] Startup folder contents
|
||||||
|
|
||||||
|
### Network Artifacts
|
||||||
|
- [ ] DNS Cache
|
||||||
|
- [ ] Network shares accessed
|
||||||
|
- [ ] VPN connections
|
||||||
|
- [ ] Remote Desktop connections
|
||||||
|
|
||||||
|
## Other Operating Systems
|
||||||
|
|
||||||
|
### Linux
|
||||||
|
- [ ] User login history
|
||||||
|
- [ ] Command history (bash, zsh)
|
||||||
|
- [ ] Systemd journal logs
|
||||||
|
- [ ] Package installation history
|
||||||
|
- [ ] Cron jobs
|
||||||
|
- [ ] SSH keys and known hosts
|
||||||
|
|
||||||
|
### macOS
|
||||||
|
- [ ] Unified logs (log show)
|
||||||
|
- [ ] LaunchAgents/LaunchDaemons
|
||||||
|
- [ ] Spotlight metadata
|
||||||
|
- [ ] FSEvents (file system events)
|
||||||
|
- [ ] Login/logout history
|
||||||
|
- [ ] Keychain artifacts
|
||||||
113
windows/Get-HotspotConnections.ps1
Normal file
113
windows/Get-HotspotConnections.ps1
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# Get-HotspotConnections.ps1
|
||||||
|
# Collects Windows Mobile Hotspot connection artifacts
|
||||||
|
|
||||||
|
# Check for admin privileges
|
||||||
|
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
|
||||||
|
if (-not $isAdmin) {
|
||||||
|
Write-Host "Error: This script requires Administrator privileges" -ForegroundColor Red
|
||||||
|
Write-Host "Please run PowerShell as Administrator and try again" -ForegroundColor Yellow
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "=== Windows Mobile Hotspot Connection History ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Note: Windows does not maintain persistent logs of past hotspot clients"
|
||||||
|
Write-Host "Only event logs and currently connected devices can be retrieved`n"
|
||||||
|
|
||||||
|
# Get current hotspot status
|
||||||
|
Write-Host "--- Current Hotspot Status ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$hostedNetwork = netsh wlan show hostednetwork 2>$null
|
||||||
|
if ($hostedNetwork) {
|
||||||
|
$hostedNetwork | Write-Host
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting hosted network status" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get currently connected clients via ARP
|
||||||
|
Write-Host "`n--- Currently Connected Devices (ARP Cache) ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$arp = Get-NetNeighbor -AddressFamily IPv4 -ErrorAction SilentlyContinue |
|
||||||
|
Where-Object { $_.State -ne "Unreachable" -and $_.IPAddress -notmatch "^(224\.|239\.)" }
|
||||||
|
|
||||||
|
if ($arp) {
|
||||||
|
$arp | Select-Object IPAddress, LinkLayerAddress, State | Format-Table -AutoSize
|
||||||
|
} else {
|
||||||
|
Write-Host "No connected devices found in ARP cache" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing ARP cache: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract hotspot connection events from WLAN-AutoConfig log
|
||||||
|
Write-Host "`n--- Recent Hotspot Connection Events ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
# Event ID 20019 = Client connection to hotspot
|
||||||
|
# Event ID 20020 = Connection establishment confirmation
|
||||||
|
# Event ID 8005/8006 = Hotspot start/stop
|
||||||
|
$events = Get-WinEvent -FilterHashtable @{
|
||||||
|
LogName = "Microsoft-Windows-WLAN-AutoConfig/Operational"
|
||||||
|
ID = 8005, 8006, 20019, 20020
|
||||||
|
} -MaxEvents 50 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($events) {
|
||||||
|
foreach ($event in $events) {
|
||||||
|
Write-Host "$($event.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan -NoNewline
|
||||||
|
Write-Host " [ID:$($event.Id)]" -ForegroundColor Gray -NoNewline
|
||||||
|
|
||||||
|
# Extract relevant info from message
|
||||||
|
$msg = $event.Message
|
||||||
|
if ($msg -match "MAC Address: ([0-9A-Fa-f:-]+)") {
|
||||||
|
Write-Host " MAC: $($matches[1])" -ForegroundColor Yellow
|
||||||
|
} elseif ($msg -match "SSID: (.+)") {
|
||||||
|
Write-Host " SSID: $($matches[1])" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No hotspot events found in logs" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing event logs: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get wireless authentication events (Event ID 5632)
|
||||||
|
Write-Host "`n--- Wireless Authentication Events (Last 20) ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$authEvents = Get-WinEvent -FilterHashtable @{
|
||||||
|
LogName = "Security"
|
||||||
|
ID = 5632
|
||||||
|
} -MaxEvents 20 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($authEvents) {
|
||||||
|
foreach ($authEvent in $authEvents) {
|
||||||
|
Write-Host "$($authEvent.TimeCreated.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan
|
||||||
|
if ($authEvent.Message -match "Peer MAC Address:\s+([0-9A-Fa-f:-]+)") {
|
||||||
|
Write-Host " Peer MAC: $($matches[1])" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No wireless authentication events found" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Security event log not accessible or no events found" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get hosted network settings from registry
|
||||||
|
Write-Host "`n--- Hosted Network Registry Settings ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$regPath = "HKLM:\SYSTEM\CurrentControlSet\Services\WlanSvc\Parameters\HostedNetworkSettings"
|
||||||
|
if (Test-Path $regPath) {
|
||||||
|
$props = Get-ItemProperty -Path $regPath -ErrorAction SilentlyContinue
|
||||||
|
if ($props) {
|
||||||
|
Write-Host "Registry path exists with configuration data" -ForegroundColor Green
|
||||||
|
Write-Host "(Binary data - use registry editor for details)"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No hosted network settings found in registry" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing registry: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
127
windows/Get-Info.ps1
Normal file
127
windows/Get-Info.ps1
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
# Get-Info.ps1
|
||||||
|
# Displays system and user information
|
||||||
|
|
||||||
|
Write-Host "=== System Information ===" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Current User
|
||||||
|
Write-Host "`n--- Current User ---" -ForegroundColor Yellow
|
||||||
|
Write-Host "Username: $env:USERNAME" -ForegroundColor Green
|
||||||
|
Write-Host "Domain: $env:USERDOMAIN" -ForegroundColor Green
|
||||||
|
Write-Host "User Profile: $env:USERPROFILE" -ForegroundColor Green
|
||||||
|
Write-Host "Home Drive: $env:HOMEDRIVE" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Computer Info
|
||||||
|
Write-Host "`n--- Computer Information ---" -ForegroundColor Yellow
|
||||||
|
Write-Host "Computer Name: $env:COMPUTERNAME" -ForegroundColor Green
|
||||||
|
|
||||||
|
try {
|
||||||
|
$cs = Get-CimInstance Win32_ComputerSystem
|
||||||
|
Write-Host "Full Computer Name: $($cs.DNSHostName).$($cs.Domain)" -ForegroundColor Green
|
||||||
|
Write-Host "Manufacturer: $($cs.Manufacturer)" -ForegroundColor Green
|
||||||
|
Write-Host "Model: $($cs.Model)" -ForegroundColor Green
|
||||||
|
Write-Host "Total RAM: $([math]::Round($cs.TotalPhysicalMemory / 1GB, 2)) GB" -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting computer details: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# OS Info
|
||||||
|
Write-Host "`n--- Operating System ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$os = Get-CimInstance Win32_OperatingSystem
|
||||||
|
Write-Host "OS: $($os.Caption)" -ForegroundColor Green
|
||||||
|
Write-Host "Version: $($os.Version)" -ForegroundColor Green
|
||||||
|
Write-Host "Build: $($os.BuildNumber)" -ForegroundColor Green
|
||||||
|
Write-Host "Architecture: $($os.OSArchitecture)" -ForegroundColor Green
|
||||||
|
Write-Host "Install Date: $($os.InstallDate)" -ForegroundColor Green
|
||||||
|
Write-Host "Last Boot: $($os.LastBootUpTime)" -ForegroundColor Green
|
||||||
|
|
||||||
|
$uptime = (Get-Date) - $os.LastBootUpTime
|
||||||
|
Write-Host "Uptime: $($uptime.Days) days, $($uptime.Hours) hours, $($uptime.Minutes) minutes" -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting OS details: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Timezone
|
||||||
|
Write-Host "`n--- Time & Location ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$timezone = Get-TimeZone
|
||||||
|
Write-Host "Timezone: $($timezone.DisplayName)" -ForegroundColor Green
|
||||||
|
Write-Host "Current Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')" -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host "Timezone: $env:TZ" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Network Info
|
||||||
|
Write-Host "`n--- Network Configuration ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$adapters = Get-NetAdapter | Where-Object { $_.Status -eq "Up" }
|
||||||
|
foreach ($adapter in $adapters) {
|
||||||
|
Write-Host "Adapter: $($adapter.Name)" -ForegroundColor Green
|
||||||
|
Write-Host " MAC Address: $($adapter.MacAddress)" -ForegroundColor Cyan
|
||||||
|
Write-Host " Speed: $($adapter.LinkSpeed)" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
# Get IP addresses
|
||||||
|
$ipConfig = Get-NetIPAddress -InterfaceIndex $adapter.InterfaceIndex -ErrorAction SilentlyContinue
|
||||||
|
foreach ($ip in $ipConfig) {
|
||||||
|
if ($ip.AddressFamily -eq "IPv4") {
|
||||||
|
Write-Host " IPv4: $($ip.IPAddress)" -ForegroundColor Cyan
|
||||||
|
} elseif ($ip.AddressFamily -eq "IPv6" -and $ip.PrefixOrigin -ne "WellKnown") {
|
||||||
|
Write-Host " IPv6: $($ip.IPAddress)" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting network info: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disk Info
|
||||||
|
Write-Host "`n--- Disk Drives ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$disks = Get-PSDrive -PSProvider FileSystem | Where-Object { $_.Used -ne $null }
|
||||||
|
foreach ($disk in $disks) {
|
||||||
|
$usedGB = [math]::Round($disk.Used / 1GB, 2)
|
||||||
|
$freeGB = [math]::Round($disk.Free / 1GB, 2)
|
||||||
|
$totalGB = $usedGB + $freeGB
|
||||||
|
$percentUsed = [math]::Round(($usedGB / $totalGB) * 100, 1)
|
||||||
|
|
||||||
|
Write-Host "$($disk.Name):\ - Total: $totalGB GB, Used: $usedGB GB ($percentUsed%), Free: $freeGB GB" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting disk info: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# User Accounts on System
|
||||||
|
Write-Host "`n--- Local User Accounts ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$users = Get-LocalUser | Select-Object Name, Enabled, LastLogon
|
||||||
|
foreach ($user in $users) {
|
||||||
|
$status = if ($user.Enabled) { "Enabled" } else { "Disabled" }
|
||||||
|
$lastLogon = if ($user.LastLogon) { $user.LastLogon.ToString("yyyy-MM-dd HH:mm:ss") } else { "Never" }
|
||||||
|
Write-Host "$($user.Name) - $status - Last Logon: $lastLogon" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting user accounts: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Environment Variables (useful ones)
|
||||||
|
Write-Host "`n--- Key Environment Variables ---" -ForegroundColor Yellow
|
||||||
|
Write-Host "Temp: $env:TEMP" -ForegroundColor Green
|
||||||
|
Write-Host "Path (first 3): $((($env:PATH -split ';') | Select-Object -First 3) -join '; ')..." -ForegroundColor Green
|
||||||
|
Write-Host "Processor: $env:PROCESSOR_IDENTIFIER" -ForegroundColor Green
|
||||||
|
Write-Host "Number of Processors: $env:NUMBER_OF_PROCESSORS" -ForegroundColor Green
|
||||||
|
|
||||||
|
# Windows Product Info
|
||||||
|
Write-Host "`n--- Windows Product Information ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$productName = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName -ErrorAction SilentlyContinue
|
||||||
|
$displayVersion = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name DisplayVersion -ErrorAction SilentlyContinue
|
||||||
|
$editionID = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name EditionID -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($productName) { Write-Host "Product: $($productName.ProductName)" -ForegroundColor Green }
|
||||||
|
if ($displayVersion) { Write-Host "Display Version: $($displayVersion.DisplayVersion)" -ForegroundColor Green }
|
||||||
|
if ($editionID) { Write-Host "Edition: $($editionID.EditionID)" -ForegroundColor Green }
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting product info: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== End of System Information ===" -ForegroundColor Cyan
|
||||||
16
windows/Get-MountedDevices.ps1
Normal file
16
windows/Get-MountedDevices.ps1
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
# Get-MountedDevices.ps1
|
||||||
|
# Lists mounted devices and drive letter mappings
|
||||||
|
|
||||||
|
Write-Host "=== Mounted Devices ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mounted = Get-ItemProperty -Path "HKLM:\SYSTEM\MountedDevices" -ErrorAction SilentlyContinue
|
||||||
|
if ($mounted) {
|
||||||
|
$mounted.PSObject.Properties | Where-Object { $_.Name -notmatch "^PS" } | ForEach-Object {
|
||||||
|
Write-Host "$($_.Name)" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
37
windows/Get-NetworkHistory.ps1
Normal file
37
windows/Get-NetworkHistory.ps1
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# Get-NetworkHistory.ps1
|
||||||
|
# Lists network connection history
|
||||||
|
|
||||||
|
# Check for admin privileges
|
||||||
|
$isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||||
|
|
||||||
|
if (-not $isAdmin) {
|
||||||
|
Write-Host "Error: This script requires Administrator privileges" -ForegroundColor Red
|
||||||
|
Write-Host "Please run PowerShell as Administrator and try again" -ForegroundColor Yellow
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "=== Network Connection History ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$networks = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList\Profiles" -ErrorAction SilentlyContinue
|
||||||
|
if ($networks) {
|
||||||
|
foreach ($network in $networks) {
|
||||||
|
$props = Get-ItemProperty -Path $network.PSPath -ErrorAction SilentlyContinue
|
||||||
|
Write-Host "$($props.ProfileName)" -ForegroundColor Yellow
|
||||||
|
Write-Host " Description: $($props.Description)"
|
||||||
|
Write-Host " Category: $($props.Category) (0=Public, 1=Private, 2=Domain)"
|
||||||
|
if ($props.DateCreated) {
|
||||||
|
Write-Host " First Connected: $($props.DateCreated)"
|
||||||
|
}
|
||||||
|
if ($props.DateLastConnected) {
|
||||||
|
Write-Host " Last Connected: $($props.DateLastConnected)"
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No network history found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
23
windows/Get-PortableDevices.ps1
Normal file
23
windows/Get-PortableDevices.ps1
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# Get-PortableDevices.ps1
|
||||||
|
# Lists portable devices (phones, cameras, etc.)
|
||||||
|
|
||||||
|
Write-Host "=== Portable Devices ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$portableDevices = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows Portable Devices\Devices" -ErrorAction SilentlyContinue
|
||||||
|
if ($portableDevices) {
|
||||||
|
foreach ($device in $portableDevices) {
|
||||||
|
$props = Get-ItemProperty -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
if ($props.FriendlyName) {
|
||||||
|
Write-Host "$($props.FriendlyName)" -ForegroundColor Yellow
|
||||||
|
Write-Host " $($device.PSChildName)" -ForegroundColor Gray
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No portable devices found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
141
windows/Get-RecentDocs.ps1
Normal file
141
windows/Get-RecentDocs.ps1
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
# Get-RecentDocs.ps1
|
||||||
|
# Lists recently opened documents from OpenSavePidlMRU registry key
|
||||||
|
|
||||||
|
param(
|
||||||
|
[int]$MaxPerType = 10,
|
||||||
|
[switch]$ShowAll
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host "=== Recently Opened Documents ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU"
|
||||||
|
|
||||||
|
if ($ShowAll) {
|
||||||
|
$MaxPerType = [int]::MaxValue
|
||||||
|
Write-Host "Showing all entries`n" -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
Write-Host "Showing top $MaxPerType per type (use -ShowAll or -MaxPerType N to see more)`n" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
function Convert-PidlMRU {
|
||||||
|
param([byte[]]$data)
|
||||||
|
|
||||||
|
if (-not $data -or $data.Length -lt 10) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
# Convert to Unicode string
|
||||||
|
$unicodeText = [System.Text.Encoding]::Unicode.GetString($data)
|
||||||
|
|
||||||
|
# Remove null characters
|
||||||
|
$cleaned = $unicodeText -replace '\x00', ''
|
||||||
|
|
||||||
|
# Try to extract valid file path (Windows path pattern)
|
||||||
|
if ($cleaned -match '([A-Z]:\\(?:[^<>:"|?*\x00-\x1F]+\\)*[^<>:"|?*\x00-\x1F\\]+)') {
|
||||||
|
return $matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Extract filename - match only valid filename characters
|
||||||
|
# This regex looks for a sequence that starts with alphanumeric and includes a file extension
|
||||||
|
if ($cleaned -match '([a-zA-Z0-9][a-zA-Z0-9._\- ]{0,200}\.[a-zA-Z0-9]{1,10})') {
|
||||||
|
return $matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fallback: filter to printable ASCII only and look for pattern
|
||||||
|
$printable = -join ($cleaned.ToCharArray() | Where-Object {
|
||||||
|
($_ -ge 32 -and $_ -le 126)
|
||||||
|
})
|
||||||
|
|
||||||
|
# Try again with printable string
|
||||||
|
if ($printable -match '([a-zA-Z0-9][a-zA-Z0-9._\- ]{0,200}\.[a-zA-Z0-9]{1,10})') {
|
||||||
|
return $matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
} catch {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mruPath = "HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSavePidlMRU"
|
||||||
|
|
||||||
|
if (Test-Path $mruPath) {
|
||||||
|
# Get all extension subkeys
|
||||||
|
$subKeys = Get-ChildItem -Path $mruPath -ErrorAction SilentlyContinue |
|
||||||
|
Sort-Object PSChildName
|
||||||
|
|
||||||
|
if ($subKeys) {
|
||||||
|
$totalFiles = 0
|
||||||
|
$totalStored = 0
|
||||||
|
|
||||||
|
foreach ($subKey in $subKeys) {
|
||||||
|
$extension = $subKey.PSChildName
|
||||||
|
|
||||||
|
$props = Get-ItemProperty -Path $subKey.PSPath -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
# Get MRUListEx for ordering
|
||||||
|
if ($props.MRUListEx) {
|
||||||
|
$files = @()
|
||||||
|
|
||||||
|
for ($i = 0; $i -lt $props.MRUListEx.Length - 4; $i += 4) {
|
||||||
|
$index = [BitConverter]::ToInt32($props.MRUListEx, $i)
|
||||||
|
if ($index -eq -1) { break }
|
||||||
|
|
||||||
|
$propName = "$index"
|
||||||
|
if ($props.$propName) {
|
||||||
|
$fileName = Convert-PidlMRU -data $props.$propName
|
||||||
|
if ($fileName) {
|
||||||
|
$files += $fileName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalStored += $files.Count
|
||||||
|
|
||||||
|
# Only show if we found files
|
||||||
|
if ($files.Count -gt 0) {
|
||||||
|
if ($extension -eq "*") {
|
||||||
|
Write-Host "`n--- All File Types ($($files.Count) total) ---" -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
Write-Host "`n--- .$extension Files ($($files.Count) total) ---" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = 0
|
||||||
|
$displayFiles = $files | Select-Object -First $MaxPerType
|
||||||
|
|
||||||
|
foreach ($file in $displayFiles) {
|
||||||
|
$count++
|
||||||
|
$totalFiles++
|
||||||
|
Write-Host " $count. $file" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($files.Count -gt $MaxPerType) {
|
||||||
|
$remaining = $files.Count - $MaxPerType
|
||||||
|
Write-Host " ... and $remaining more" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Summary ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Total stored: $totalStored files" -ForegroundColor Green
|
||||||
|
Write-Host "Displayed: $totalFiles files" -ForegroundColor Green
|
||||||
|
|
||||||
|
if ($totalFiles -eq 0) {
|
||||||
|
Write-Host "`nNo readable file paths found in MRU data" -ForegroundColor Gray
|
||||||
|
Write-Host "The PIDL binary format may require more advanced parsing" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "`nNo recent file history found" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
Write-Host "`nOpenSavePidlMRU registry key not found" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nNote: PIDL data parsing is limited. For complete analysis, use forensic tools like Registry Explorer" -ForegroundColor Cyan
|
||||||
36
windows/Get-USBDevices.ps1
Normal file
36
windows/Get-USBDevices.ps1
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Get-USBDevices.ps1
|
||||||
|
# Lists all USB devices with vendor/product IDs
|
||||||
|
|
||||||
|
Write-Host "`n=== USB Devices ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$usb = Get-ChildItem -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\USB" -ErrorAction SilentlyContinue
|
||||||
|
if ($usb) {
|
||||||
|
foreach ($device in $usb) {
|
||||||
|
if ($device.PSChildName -match "VID_|vid_") {
|
||||||
|
$instances = Get-ChildItem -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
$hasDevice = $false
|
||||||
|
|
||||||
|
foreach ($instance in $instances) {
|
||||||
|
$props = Get-ItemProperty -Path $instance.PSPath -ErrorAction SilentlyContinue
|
||||||
|
if ($props.DeviceDesc) {
|
||||||
|
if (-not $hasDevice) {
|
||||||
|
Write-Host "$($device.PSChildName)" -ForegroundColor Yellow
|
||||||
|
$hasDevice = $true
|
||||||
|
}
|
||||||
|
# Clean up device description - extract text after semicolon if present
|
||||||
|
$desc = $props.DeviceDesc
|
||||||
|
if ($desc -match ';(.+)$') {
|
||||||
|
$desc = $matches[1]
|
||||||
|
}
|
||||||
|
Write-Host " $desc"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($hasDevice) { Write-Host "" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
135
windows/Get-USBForensics.ps1
Normal file
135
windows/Get-USBForensics.ps1
Normal file
@@ -0,0 +1,135 @@
|
|||||||
|
# Get-USBForensics.ps1
|
||||||
|
# PowerShell script to gather USB and storage forensic artifacts
|
||||||
|
|
||||||
|
Write-Host "`n=== USB Storage Devices (USBSTOR) ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Location: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$usbstor = Get-ChildItem -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR" -ErrorAction SilentlyContinue
|
||||||
|
if ($usbstor) {
|
||||||
|
foreach ($device in $usbstor) {
|
||||||
|
Write-Host "Device: $($device.PSChildName)" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$instances = Get-ChildItem -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
foreach ($instance in $instances) {
|
||||||
|
$props = Get-ItemProperty -Path $instance.PSPath -ErrorAction SilentlyContinue
|
||||||
|
Write-Host " Serial: $($instance.PSChildName)"
|
||||||
|
Write-Host " Friendly Name: $($props.FriendlyName)"
|
||||||
|
Write-Host " Service: $($props.Service)"
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No USB storage devices found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing USBSTOR: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== USB Devices (USB) ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Location: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$usb = Get-ChildItem -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\USB" -ErrorAction SilentlyContinue
|
||||||
|
if ($usb) {
|
||||||
|
foreach ($device in $usb) {
|
||||||
|
if ($device.PSChildName -match "VID_|vid_") {
|
||||||
|
Write-Host "Device: $($device.PSChildName)" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$instances = Get-ChildItem -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
foreach ($instance in $instances) {
|
||||||
|
$props = Get-ItemProperty -Path $instance.PSPath -ErrorAction SilentlyContinue
|
||||||
|
if ($props.DeviceDesc) {
|
||||||
|
Write-Host " Instance: $($instance.PSChildName)"
|
||||||
|
Write-Host " Description: $($props.DeviceDesc)"
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing USB: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Mounted Devices ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Location: HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$mounted = Get-ItemProperty -Path "HKLM:\SYSTEM\MountedDevices" -ErrorAction SilentlyContinue
|
||||||
|
if ($mounted) {
|
||||||
|
$mounted.PSObject.Properties | Where-Object { $_.Name -notmatch "^PS" } | ForEach-Object {
|
||||||
|
Write-Host "Drive: $($_.Name)" -ForegroundColor Yellow
|
||||||
|
# Convert byte array to hex string for readability
|
||||||
|
if ($_.Value -is [byte[]]) {
|
||||||
|
$hexValue = ($_.Value | ForEach-Object { $_.ToString("X2") }) -join " "
|
||||||
|
Write-Host " Value: $hexValue"
|
||||||
|
} else {
|
||||||
|
Write-Host " Value: $($_.Value)"
|
||||||
|
}
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing MountedDevices: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Portable Devices ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Location: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Portable Devices\Devices`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$portableDevices = Get-ChildItem -Path "HKLM:\SOFTWARE\Microsoft\Windows Portable Devices\Devices" -ErrorAction SilentlyContinue
|
||||||
|
if ($portableDevices) {
|
||||||
|
foreach ($device in $portableDevices) {
|
||||||
|
Write-Host "Device: $($device.PSChildName)" -ForegroundColor Yellow
|
||||||
|
$props = Get-ItemProperty -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
Write-Host " Friendly Name: $($props.FriendlyName)"
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No portable devices found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing Portable Devices: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Setup API Device Install Log (Last 20 USB entries) ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Location: C:\Windows\inf\setupapi.dev.log`n"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$setupLog = "C:\Windows\inf\setupapi.dev.log"
|
||||||
|
if (Test-Path $setupLog) {
|
||||||
|
$usbEntries = Select-String -Path $setupLog -Pattern "USB" -Context 0,2 -ErrorAction SilentlyContinue | Select-Object -Last 20
|
||||||
|
foreach ($entry in $usbEntries) {
|
||||||
|
Write-Host $entry.Line -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "Setup log not found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing setup log: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Current USB Devices (via WMI) ===" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
try {
|
||||||
|
$wmiUSB = Get-WmiObject Win32_USBControllerDevice -ErrorAction SilentlyContinue | ForEach-Object {
|
||||||
|
[wmi]($_.Dependent)
|
||||||
|
} | Select-Object Description, DeviceID, Manufacturer | Where-Object { $_.Description -ne $null }
|
||||||
|
|
||||||
|
if ($wmiUSB) {
|
||||||
|
$wmiUSB | ForEach-Object {
|
||||||
|
Write-Host "Description: $($_.Description)" -ForegroundColor Yellow
|
||||||
|
Write-Host " Device ID: $($_.DeviceID)"
|
||||||
|
Write-Host " Manufacturer: $($_.Manufacturer)"
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No USB devices currently connected." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error accessing WMI: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n=== Script Complete ===" -ForegroundColor Green
|
||||||
|
Write-Host "Note: Run as Administrator for complete results.`n"
|
||||||
26
windows/Get-USBStorage.ps1
Normal file
26
windows/Get-USBStorage.ps1
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Get-USBStorage.ps1
|
||||||
|
# Lists USB storage devices from USBSTOR registry key
|
||||||
|
|
||||||
|
Write-Host "=== USB Storage Devices (USBSTOR) ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USBSTOR"
|
||||||
|
|
||||||
|
try {
|
||||||
|
$usbstor = Get-ChildItem -Path "HKLM:\SYSTEM\CurrentControlSet\Enum\USBSTOR" -ErrorAction SilentlyContinue
|
||||||
|
if ($usbstor) {
|
||||||
|
foreach ($device in $usbstor) {
|
||||||
|
Write-Host "Device: $($device.PSChildName)" -ForegroundColor Yellow
|
||||||
|
|
||||||
|
$instances = Get-ChildItem -Path $device.PSPath -ErrorAction SilentlyContinue
|
||||||
|
foreach ($instance in $instances) {
|
||||||
|
$props = Get-ItemProperty -Path $instance.PSPath -ErrorAction SilentlyContinue
|
||||||
|
Write-Host " Serial: $($instance.PSChildName)"
|
||||||
|
if ($props.FriendlyName) { Write-Host " Name: $($props.FriendlyName)" }
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "No USB storage devices found." -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
174
windows/Get-Users.ps1
Normal file
174
windows/Get-Users.ps1
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
# Get-Users.ps1
|
||||||
|
# Lists all users on the system with detailed information
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Position=0)]
|
||||||
|
[ValidateSet("simple", "detailed", "full")]
|
||||||
|
[string]$Mode = "simple"
|
||||||
|
)
|
||||||
|
|
||||||
|
Write-Host "=== System Users ===" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
if ($Mode -eq "simple") {
|
||||||
|
Write-Host "Mode: Simple (use -Mode detailed or -Mode full for more info)`n" -ForegroundColor Yellow
|
||||||
|
} elseif ($Mode -eq "detailed") {
|
||||||
|
Write-Host "Mode: Detailed`n" -ForegroundColor Yellow
|
||||||
|
} else {
|
||||||
|
Write-Host "Mode: Full`n" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
|
||||||
|
# Local Users
|
||||||
|
Write-Host "--- Local User Accounts ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$localUsers = Get-LocalUser
|
||||||
|
|
||||||
|
if ($Mode -eq "simple") {
|
||||||
|
# Simple mode: just list usernames
|
||||||
|
foreach ($user in $localUsers) {
|
||||||
|
$status = if ($user.Enabled) { "" } else { " (Disabled)" }
|
||||||
|
Write-Host "$($user.Name)$status" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
|
||||||
|
} elseif ($Mode -eq "detailed") {
|
||||||
|
# Detailed mode: username, enabled status, last logon
|
||||||
|
foreach ($user in $localUsers) {
|
||||||
|
Write-Host "`n$($user.Name)" -ForegroundColor Green
|
||||||
|
Write-Host " Enabled: $($user.Enabled)" -ForegroundColor Cyan
|
||||||
|
Write-Host " Last Logon: $(if ($user.LastLogon) { $user.LastLogon.ToString('yyyy-MM-dd HH:mm:ss') } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
Write-Host " Password Last Set: $(if ($user.PasswordLastSet) { $user.PasswordLastSet.ToString('yyyy-MM-dd HH:mm:ss') } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
# Full mode: all details
|
||||||
|
foreach ($user in $localUsers) {
|
||||||
|
Write-Host "`nUsername: $($user.Name)" -ForegroundColor Green
|
||||||
|
Write-Host " Full Name: $($user.FullName)" -ForegroundColor Cyan
|
||||||
|
Write-Host " Description: $($user.Description)" -ForegroundColor Cyan
|
||||||
|
Write-Host " Enabled: $($user.Enabled)" -ForegroundColor Cyan
|
||||||
|
Write-Host " Account Expires: $(if ($user.AccountExpires) { $user.AccountExpires } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
Write-Host " Password Last Set: $(if ($user.PasswordLastSet) { $user.PasswordLastSet.ToString('yyyy-MM-dd HH:mm:ss') } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
Write-Host " Password Expires: $(if ($user.PasswordExpires) { $user.PasswordExpires } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
Write-Host " Last Logon: $(if ($user.LastLogon) { $user.LastLogon.ToString('yyyy-MM-dd HH:mm:ss') } else { 'Never' })" -ForegroundColor Cyan
|
||||||
|
Write-Host " Password Required: $($user.PasswordRequired)" -ForegroundColor Cyan
|
||||||
|
Write-Host " User May Change Password: $($user.UserMayChangePassword)" -ForegroundColor Cyan
|
||||||
|
Write-Host " SID: $($user.SID)" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`nTotal Local Users: $($localUsers.Count)" -ForegroundColor Green
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting local users: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only show profile paths in detailed and full modes
|
||||||
|
if ($Mode -ne "simple") {
|
||||||
|
Write-Host "`n--- User Profiles (from Registry) ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$profileListPath = "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList"
|
||||||
|
|
||||||
|
if (Test-Path $profileListPath) {
|
||||||
|
$profiles = Get-ChildItem -Path $profileListPath -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
foreach ($profile in $profiles) {
|
||||||
|
$props = Get-ItemProperty -Path $profile.PSPath -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($props.ProfileImagePath) {
|
||||||
|
$sid = $profile.PSChildName
|
||||||
|
|
||||||
|
# Try to resolve SID to username
|
||||||
|
try {
|
||||||
|
$objSID = New-Object System.Security.Principal.SecurityIdentifier($sid)
|
||||||
|
$objUser = $objSID.Translate([System.Security.Principal.NTAccount])
|
||||||
|
$username = $objUser.Value
|
||||||
|
} catch {
|
||||||
|
$username = "Unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "`n$username" -ForegroundColor Green
|
||||||
|
Write-Host " Profile Path: $($props.ProfileImagePath)" -ForegroundColor Cyan
|
||||||
|
|
||||||
|
if ($Mode -eq "full") {
|
||||||
|
Write-Host " SID: $sid" -ForegroundColor Gray
|
||||||
|
|
||||||
|
if ($props.LocalProfileLoadTimeHigh -and $props.LocalProfileLoadTimeLow) {
|
||||||
|
$loadTime = [DateTime]::FromFileTime(([Int64]$props.LocalProfileLoadTimeHigh -shl 32) -bor $props.LocalProfileLoadTimeLow)
|
||||||
|
Write-Host " Profile Load Time: $($loadTime.ToString('yyyy-MM-dd HH:mm:ss'))" -ForegroundColor Cyan
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error reading profile list: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Currently Logged In Users
|
||||||
|
Write-Host "`n--- Currently Logged In Users ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$loggedInUsers = quser 2>$null
|
||||||
|
|
||||||
|
if ($loggedInUsers) {
|
||||||
|
$loggedInUsers | ForEach-Object {
|
||||||
|
Write-Host $_ -ForegroundColor Green
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Alternative method using WMI
|
||||||
|
$sessions = Get-CimInstance -ClassName Win32_ComputerSystem
|
||||||
|
if ($sessions.UserName) {
|
||||||
|
Write-Host "$($sessions.UserName)" -ForegroundColor Green
|
||||||
|
} else {
|
||||||
|
Write-Host "No users currently logged in" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting logged in users: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
|
||||||
|
# Only show groups in full mode
|
||||||
|
if ($Mode -eq "full") {
|
||||||
|
Write-Host "`n--- Local Groups ---" -ForegroundColor Yellow
|
||||||
|
try {
|
||||||
|
$groups = Get-LocalGroup
|
||||||
|
|
||||||
|
foreach ($group in $groups) {
|
||||||
|
Write-Host "`n$($group.Name)" -ForegroundColor Green
|
||||||
|
Write-Host " Description: $($group.Description)" -ForegroundColor Cyan
|
||||||
|
Write-Host " SID: $($group.SID)" -ForegroundColor Gray
|
||||||
|
|
||||||
|
# Get group members
|
||||||
|
try {
|
||||||
|
$members = Get-LocalGroupMember -Group $group.Name -ErrorAction SilentlyContinue
|
||||||
|
if ($members) {
|
||||||
|
Write-Host " Members:" -ForegroundColor Cyan
|
||||||
|
foreach ($member in $members) {
|
||||||
|
Write-Host " - $($member.Name) ($($member.ObjectClass))" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host " Members: None" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host " Members: Unable to retrieve" -ForegroundColor Gray
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error getting local groups: $_" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Summary
|
||||||
|
if ($Mode -ne "simple") {
|
||||||
|
Write-Host "`n=== Summary ===" -ForegroundColor Cyan
|
||||||
|
try {
|
||||||
|
$enabledUsers = (Get-LocalUser | Where-Object { $_.Enabled -eq $true }).Count
|
||||||
|
$disabledUsers = (Get-LocalUser | Where-Object { $_.Enabled -eq $false }).Count
|
||||||
|
$totalGroups = (Get-LocalGroup).Count
|
||||||
|
|
||||||
|
Write-Host "Enabled Users: $enabledUsers" -ForegroundColor Green
|
||||||
|
Write-Host "Disabled Users: $disabledUsers" -ForegroundColor Green
|
||||||
|
Write-Host "Total Groups: $totalGroups" -ForegroundColor Green
|
||||||
|
} catch {
|
||||||
|
Write-Host "Error generating summary" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user