An AI-Integrated, Self-Healing Forensic Engine for Active Directory
The following script will be needed, you are welcome to add, remove and improve it, note that you don't need to have a Cisco secure endpoint account.
Script 1: Invoke-AIAnalyst.ps1 (The Engine)
Description: This file contains all the backend functions: Cisco API integration, the AbuseIPDB lookup, the "Shield" logic, and the connection to the local LLM.
Script 2: Get-SOCReport.ps1 (The Command Center)
Description: This is the main entry point. It handles the "Self-Healing" Sysmon installation, pulls the DC logs, and orchestrates the remote forensic connection.
"Prerequisites:
Ollama: Installed with llama3.2:1b pulled. (on the main computer where you will be running the scripts)
PowerShell 5.1+ running as Administrator.
API Keys: you will need API keys for Cisco and AbuseIPDB (VirusTotal) with your own keys.
Directory Structure: The scripts expect to live in an a path like D:\AD-SOC\ (or whatever path you choose, but make sure it is changed in the script.)
"Disclaimer: This tool is for educational and authorized security testing purposes only. Automated blocking of IP addresses can impact network availability. Always test in a lab environment before deploying to production."
This is the SOC report: make a note of the names I mentioned above.
param(
[string]$TargetWorkstation = "localhost"
)
. "D:\AD-SOC\SOC_Tool\Invoke-AIAnalyst.ps1"
$DC = "srv-dc3"
Write-Host "`n--- [!] SOC COMMAND CENTER: SCANNING $TargetWorkstation ---" -ForegroundColor Cyan
# 1. Credentials for Remote Access
$Creds = Get-Credential -Message "Admin Access for $TargetWorkstation and $DC"
# 2. Cisco & DC Intelligence
$Cloud = Get-CiscoAlerts
Write-Host "[*] Harvesting DC Identity Logs..." -ForegroundColor Gray
$DCLogs = Get-WinEvent -ComputerName $DC -Credential $Creds -FilterHashtable @{LogName='Security'; ID=4624,4625} -MaxEvents 10 | ForEach-Object {
[PSCustomObject]@{ Time=$_.TimeCreated; User=$_.Properties[5].Value; IP=$_.Properties[18].Value }
}
# 3. REMOTE FORENSICS (Corrected Logic)
Write-Host "[*] Reaching out to $TargetWorkstation for Sysmon Forensics..." -ForegroundColor Magenta
try {
$Forensics = Invoke-Command -ComputerName $TargetWorkstation -Credential $Creds -ScriptBlock {
$Logs = Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 5 -ErrorAction SilentlyContinue | Where-Object {$_.Id -eq 1}
# We assign the loop to a variable then return the variable
$Captured = foreach ($L in $Logs) {
$Xml = [xml]$L.ToXml()
[PSCustomObject]@{
Time = $L.TimeCreated
Process = ($Xml.Event.EventData.Data | Where-Object {$_.Name -eq "Image"}).'#text' -split "\\" | Select-Object -Last 1
Command = ($Xml.Event.EventData.Data | Where-Object {$_.Name -eq "CommandLine"}).'#text'
}
}
return $Captured
} -ErrorAction Stop
Write-Host "[✓] Remote Forensics Captured from $TargetWorkstation." -ForegroundColor Green
} catch {
Write-Host "[X] Remote Forensic Link Failed: $($_.Exception.Message)" -ForegroundColor Red
}
# 4. AI Analysis
Write-Host "[*] Analyzing Hybrid Intel..." -ForegroundColor Yellow
$Report = "--- DC LOGS ---`n$($DCLogs | Out-String)`n--- REMOTE SYS-FORENSICS ($TargetWorkstation) ---`n$($Forensics | Out-String)`n--- CLOUD ---`n$Cloud"
$Verdict = Get-AIAnalysis -LogData $Report
# 5. Shield Logic
if ($Verdict -match "ACTION: BLOCK \[?([\d\.\w\-]+)\]?") {
$T = $Matches[1]
if ($T -match "^(10\.|192\.168\.|172\.|100\.)" -or $T -match "DC|Okta|srv") {
Write-Host "[!] SHIELD: Block on $T Prevented." -ForegroundColor White -BackgroundColor Red
} else {
New-GuardrailBlock -Target $T -Node $TargetWorkstation -Reason $Verdict
}
}
Write-Host "`n--- FINAL VERDICT ---`n$Verdict" -ForegroundColor Green
******************************************************************************************************
This is the Invoke-AIAnalyst Script:
# ==============================================================================
# --- SOC ENGINE: INVOKE-AIANALYST.PS1 (BUILD 37.0 - COMMAND CENTER) ---
# ==============================================================================
$CiscoClientID = "YOUR_CISCO_CLIENT_ID"
$CiscoAPIKey = "YOUR_CISCO_API_KEY"
$CiscoHost = "api.amp.cisco.com"
$AbuseIPDBKey = "VirusTotal key"
$AssetFilePath = "D:\AD-SOC\Known_Assets.csv" # this is a list of assets that will be use as a reference to have less false positives.
# --- ASSET CONTEXT ---
function Get-AssetContext {
if (Test-Path $AssetFilePath) {
return Import-Csv $AssetFilePath | Select-Object -First 50 | Out-String
}
return "No Asset Reference Found."
}
# --- CISCO CLOUD ---
function Get-CiscoAlerts {
$Pair = "${CiscoClientID}:${CiscoAPIKey}"; $Bytes = [System.Text.Encoding]::ASCII.GetBytes($Pair); $Base64 = [Convert]::ToBase64String($Bytes)
$Headers = @{ "Authorization" = "Basic $Base64"; "Accept" = "application/json" }
try {
$Events = (Invoke-RestMethod -Method Get -Uri "https://$CiscoHost/v1/events?limit=5" -Headers $Headers -TimeoutSec 10).data
if ($Events) { return $Events | ForEach-Object { "[CISCO] Host: $($_.computer.hostname) | Threat: $($_.detection)" } }
return "Cisco: Clean."
} catch { return "Cisco: Offline." }
}
# --- IP INTEL ---
function Get-IPIntel {
param([string]$IPAddress)
if ($IPAddress -match "^(10\.|192\.168\.|172\.|100\.)" -or $IPAddress -eq "::1") { return "Internal (Safe)" }
try {
$Resp = Invoke-RestMethod -Method Get -Uri "https://api.abuseipdb.com/api/v2/check?ipAddress=$IPAddress" -Headers @{"Key"=$AbuseIPDBKey}
return "Abuse Score: $($Resp.data.abuseConfidenceScore)%"
} catch { return "Intel Offline" }
}
# --- THE SHIELD (FIREWALL BLOCK) ---
function New-GuardrailBlock {
param([string]$Target, [string]$Node, [string]$Reason)
Write-Host "`n[!!!] BLOCK AUTHORIZATION REQUIRED [!!!]" -ForegroundColor Red -BackgroundColor Yellow
Write-Host "Target: $Target | Node: $Node | Reason: $Reason"
$Choice = Read-Host "Apply Block? (Y/N)"
if ($Choice -eq "Y") {
Invoke-Command -ComputerName $Node -ScriptBlock { param($T) New-NetFirewallRule -DisplayName "SOC-BLOCK-$T" -Direction Inbound -Action Block -RemoteAddress $T } -ArgumentList $Target
return "SUCCESS: $Target Blocked."
}
return "SKIPPED."
}
# --- AI ADVISOR ---
function Get-AIAnalysis {
param([string]$LogData)
$SystemPrompt = @"
You are a Senior SOC Manager.
CRITICAL OUTPUT RULES:
1. If healthy, ONLY write 'SYSTEM HEALTHY' and a 1-sentence summary.
2. DO NOT list every authorized user.
3. If threat exists, start with 'ACTION: BLOCK [IP/Host]'.
4. Explain HOW a threat is moving via LOCAL/REMOTE PROCESSES.
5. IGNORE all 10.x, 172.x, 192.x IPs for blocking.
"@
$Body = @{ model="llama3.2:1b"; messages=@(@{role="system";content=$SystemPrompt},@{role="user";content=$LogData}); stream=$false } | ConvertTo-Json -Compress
try {
return (Invoke-RestMethod -Method Post -Uri "http://localhost:11434/api/chat" -Body $Body -ContentType "application/json").message.content
} catch { return "AI Engine Offline." }
}
#######################################################################################################
Remember to do this test in a lab and not in a working environment, this is a great way to learn scripting and troubleshoot, you are going to run into issues while running these two scripts but that is the purpose, it is to learn!! good hunting.
