Skip to content

Output Reference

Ryan edited this page Mar 4, 2026 · 6 revisions

Output Reference

Comprehensive guide to understanding and using the audit report outputs.

Table of Contents


Output Formats Overview

The Windows Security Audit Script generates reports in multiple formats, plus real-time console output:

Format Best For File Extension Typical Size
HTML Human review, management reporting, interactive analysis .html 300-600 KB
JSON Automation, remediation files, API integration .json 100-300 KB
CSV Excel analysis, tracking, dashboards .csv 50-150 KB
XML SIEM integration, compliance systems .xml 150-400 KB
JSON (auto-generated) Machine-readable companion file .json 200-500 KB
Console Real-time monitoring, quick checks N/A N/A

File Naming Convention

Security-Audit-Report-YYYYMMDD-HHMMSS.{html|json|csv|xml}

Examples:
Security-Audit-Report-20241230-143022.html
Security-Audit-Report-20241230-143022.json
Security-Audit-Report-20241230-143022.csv
Security-Audit-Report-20241230-143022.xml

Naming Pattern:

  • YYYYMMDD - Date (Year, Month, Day)
  • HHMMSS - Time (Hour, Minute, Second in 24-hour format)
  • Same timestamp for all formats from single execution

HTML Report

Overview

The HTML report is a self-contained, interactive web application designed for human consumption. It requires no external resources and opens in any modern web browser with advanced features for analysis and export.

Key Features (New in v6.0)

Interactive Features:

  • 🌙 Dark mode toggle with persistent preference
  • 🔍 Per-column filtering (real-time search)
  • ↕️ Column sorting (click headers)
  • ☑️ Row selection for targeted exports
  • 📊 Collapsible module sections
  • 📤 Built-in export functionality (5 formats)
  • 🎨 Color-coded status indicators

Opening the HTML Report

Method 1: Automatic (Default)

  • Script automatically opens report in default browser after completion
  • Skip with: .\Windows-Security-Audit.ps1 -OutputFormat JSON (or other non-HTML format)

Method 2: Manual

# Double-click the .html file in file explorer

# Or open via PowerShell
Start-Process ".\Security-Audit-Report-*.html"

# Specify browser
Start-Process "chrome.exe" ".\Security-Audit-Report-*.html"
Start-Process "msedge.exe" ".\Security-Audit-Report-*.html"
Start-Process "firefox.exe" ".\Security-Audit-Report-*.html"

HTML Report Structure

1. Header Section

Banner:

========================================================================================================
                        Windows Security Audit Report
                   Comprehensive Multi-Framework Security Assessment
========================================================================================================

Dark Mode Toggle:

  • Located in top-right corner
  • Click to switch between light and dark themes
  • Preference saved in browser's local storage

2. System Information Panel

┌────────────────────────────────────────────────────────────────────────────┐
│ Computer Name      │ WORKSTATION01                                          │
│ Operating System   │ Microsoft Windows 11 Pro (Build 22631)                 │
│ Scan Date          │ 2024-12-30 14:30:22                                    │
│ Duration           │ 00:05:34                                                │
│ Modules Executed   │ Core, STIG, NIST, CIS, NSA, CISA, MS                   │
└────────────────────────────────────────────────────────────────────────────┘

3. Executive Summary Dashboard

Visual Status Cards:

┌──────────────┐  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐
│     3199     │  │     487      │  │      34      │  │      18      │
│ Total Checks │  │    Passed    │  │    Failed    │  │   Warnings   │
└──────────────┘  └──────────────┘  └──────────────┘  └──────────────┘

┌──────────────┐  ┌──────────────┐
│      9       │  │      2       │
│     Info     │  │    Errors    │
└──────────────┘  └──────────────┘

Color Coding:

  • Blue - Total Checks
  • Green - Passed (success)
  • Red - Failed (critical)
  • Yellow/Orange - Warnings
  • Cyan - Informational
  • Purple - Errors

4. Global Export Options (New)

Located below the summary dashboard:

┌────────────────────────────────────────────────────────────────┐
│              Global Export Options                             │
│  [Export All]  [Export Selected]                               │
└────────────────────────────────────────────────────────────────┘

Automatic JSON Companion - Every audit automatically generates a structured JSON file alongside the HTML report, regardless of the -OutputFormat setting.

Export All - Exports all findings across all modules Export Selected - Exports only rows with checked checkboxes from all modules

New Report Features (v6.1)

  • Severity Cards — Row of 5 cards below status summary showing Critical/High/Medium/Low/Informational distribution; click to filter
  • Category Detail Tables — Each module section includes an expanded table showing every check category with pass/fail/warn/info/error counts and per-category compliance percentage
  • Overall Compliance Cards — 4 color-coded cards: Weighted Score (color-coded by result), Overall Rating, Simple Score, Severity-Adjusted Score
  • Remediation Priority Ranking (Top 50) — Collapsible section after all modules listing the 50 most critical findings ranked by severity
  • Deep Navy Dark Theme — Theme toggle in top-right banner corner; dark mode uses #0b0e14, #111822, #1a2332 matching the Linux Security Audit report
  • Table of Contents — Collapsible section below host info cards with links to all modules and Remediation Priority

5. Module Results Sections

Each module section includes:

Module Header (Collapsible):

┌────────────────────────────────────────────────────────────────┐
│ MODULE: STIG                    Pass: 78 | Fail: 8 | Warning: 4 | Info: 2   ▼│
└────────────────────────────────────────────────────────────────┘
  • Click header to collapse/expand section
  • Arrow indicator (▼/▶) shows current state

Results Table:

┌───┬────────┬─────────────────────────┬──────────────────────────────────┐
│ ☑ │ Status │ Category                │ Finding                          │
├───┼────────┼─────────────────────────┼──────────────────────────────────┤
│ ☐ │ FAIL   │ STIG - V-220929 (CAT I) │ Guest account is ENABLED         │
│ ☐ │ PASS   │ STIG - V-220718 (CAT II)│ Minimum password length: 14 chars│
│ ☐ │ WARN   │ STIG - V-220930 (CAT II)│ Administrator account not renamed│
└───┴────────┴─────────────────────────┴──────────────────────────────────┘

Filter boxes under each column header:
┌───┬────────┬─────────────────────────┬──────────────────────────────────┐
│   │[Filter]│[Filter]                 │[Filter]                          │
└───┴────────┴─────────────────────────┴──────────────────────────────────┘

Expandable Details: Click any row to expand inline details:

┌────────────────────────────────────────────────────────────────────────┐
│ STIG - V-220929 (CAT I)                                                  │
│ Guest account is ENABLED                                                 │
├────────────────────────────────────────────────────────────────────────┤
│ Details:                                                                 │
│ STIG CAT I: Guest account must be disabled to prevent anonymous access. │
│ This is a critical security control.                                    │
│                                                                          │
│ REMEDIATION:                                                             │
│ Disable-LocalUser -Name Guest                                           │
│                                                                          │
│ Timestamp: 2024-12-25 14:30:25                                          │
└────────────────────────────────────────────────────────────────────────┘

Module Export Buttons: Each module section has its own export options:

  • [Export Module] - Export all findings from this module
  • [Export Selected from Module] - Export checked rows from this module

Interactive Features Guide

Dark Mode

Activation:

  1. Click "Toggle Dark Mode" button (top-right)
  2. Page theme switches instantly
  3. Preference saved automatically

Benefits:

  • Easier on eyes during long review sessions
  • Reduces eye strain
  • Professional appearance for presentations

Column Filtering

Real-Time Search:

  1. Type in filter box under any column header
  2. Results filter instantly as you type
  3. Case-insensitive matching
  4. Multiple filters work together (AND logic)

Example Use Cases:

Status filter: "fail" → Shows only failures
Category filter: "CAT I" → Shows only Category I findings
Finding filter: "password" → Shows all password-related findings

Sorting

How to Sort:

  1. Click any column header
  2. First click: Ascending sort
  3. Second click: Descending sort
  4. Visual arrow indicator (↑/↓) shows sort direction

Recommended Sorting:

  • Sort by Status to group Pass/Fail/Warning
  • Sort by Category to group by compliance framework
  • Sort by Finding to alphabetically organize results

Row Selection

Selecting Rows:

  • ☐ Click checkbox to select individual row
  • ☑ Click "Select All" checkbox in header to select all visible rows
  • Works with filters (selects only filtered results)

Use Cases:

  1. Select specific findings to remediate
  2. Export subset of results
  3. Create targeted reports for specific teams

Export Modal (New Feature)

Workflow:

  1. Click any Export button (Global or Module-level)
  2. Modal dialog appears with format options
  3. Click desired format
  4. File downloads automatically

Available Export Formats:

Format Description Best For
CSV Comma-delimited spreadsheet Excel analysis, pivot tables
Excel Formatted HTML table (.xls) Presentations, formatted reports
JSON Machine-readable data Remediation files, automation
XML Standards-compliant structure SIEM ingestion, compliance systems
TXT Fixed-width plain text Documentation, email, tickets

Export Workflows

Workflow 1: Export All Failures

Steps:

  1. Open HTML report
  2. Click "Status" column header to sort
  3. Use Status filter box, type: "fail"
  4. Click "Export All" button
  5. Select "Excel" format
  6. Send to management

Result: Formatted Excel report with only failed checks

Workflow 2: Create Remediation Plan

Steps:

  1. Open HTML report
  2. Review findings carefully
  3. Check boxes next to issues you want to fix
  4. Click "Export Selected" button
  5. Select "JSON" format
  6. Save as remediation-plan.json

Use Remediation File:

.\Windows-Security-Audit.ps1 -AutoRemediate -RemediationFile "remediation-plan.json"

Result: Only selected issues are remediated

Workflow 3: Module-Specific Report

Steps:

  1. Navigate to STIG module section
  2. Click "Export Module" button
  3. Select "TXT" format
  4. Include in compliance documentation

Result: Clean text report of all STIG findings

Workflow 4: Selected Issues from Module

Steps:

  1. Filter STIG module to show "CAT I" findings
  2. Select all filtered results (checkboxes)
  3. Click "Export Selected from Module"
  4. Select "CSV"
  5. Import to project tracking tool

Result: CSV of only critical STIG findings

HTML Report Tips and Tricks

Browser Compatibility

Fully Supported:

  • Google Chrome (v90+)
  • Microsoft Edge (v90+)
  • Mozilla Firefox (v88+)
  • Safari (v14+)

⚠️ Limited Support:

  • Internet Explorer (not recommended, lacks modern features)
  • Older browsers (may lack dark mode, export features)

Keyboard Shortcuts

Ctrl+F (Cmd+F on Mac) - Browser's find function
Ctrl+P (Cmd+P on Mac) - Print dialog (save to PDF)
Ctrl+S (Cmd+S on Mac) - Save HTML file
Ctrl+Click - Open link in new tab (if external links present)

Advanced Searching

Browser Find (Ctrl+F) Use Cases:

Search: "CAT I"      → Find all Category I STIG findings
Search: "Fail"       → Jump through all failures
Search: "BitLocker"  → Find encryption-related findings
Search: "V-220929"   → Find specific STIG V-ID
Search: "password"   → Find all password-related checks

Printing to PDF

High-Quality PDF Export:

1. Open HTML report
2. Press Ctrl+P (Cmd+P on Mac)
3. Destination: "Save as PDF"
4. Settings:
   - Layout: Portrait
   - Margins: Default
   - Scale: 100%
   - Background graphics: On (for colors)
5. Click "Save"

Result: Professional PDF with full formatting, colors, and tables

Sharing Reports

Best Practices:

Do:

  • Share complete HTML file (self-contained)
  • Use secure file transfer methods
  • Add date/context in email subject
  • Include summary of key findings
  • Encrypt if sending externally

Don't:

  • Email to untrusted recipients
  • Post to public file shares
  • Modify HTML manually (regenerate instead)
  • Share without management approval
  • Include in public repositories

Secure Sharing Example:

# Compress report with password
Compress-Archive -Path "Security-Audit-Report-*.html" -DestinationPath "Audit-Report.zip"
# Use 7-Zip or similar to add password protection

# Send via secure email
Send-MailMessage `
    -To "security-team@company.com" `
    -From "auditor@company.com" `
    -Subject "Security Audit - $env:COMPUTERNAME - $(Get-Date -Format 'yyyy-MM-dd')" `
    -Body "Please find attached security audit report. Password will be sent separately." `
    -Attachments "Audit-Report.zip" `
    -Priority High

Accessibility Features

Screen Reader Support:

  • Semantic HTML structure
  • ARIA labels on interactive elements
  • Keyboard navigation support
  • High contrast in dark mode

Keyboard Navigation:

  • Tab through interactive elements
  • Enter to activate buttons
  • Space to toggle checkboxes
  • Arrow keys in filter boxes

JSON Report

Overview

The JSON report contains structured, machine-readable data designed for automation, integration, and programmatic analysis. It can also be used as a remediation file with the -RemediationFile parameter.

JSON Structure (v6.0)

{
  "ExecutionInfo": {
    "ComputerName": "WORKSTATION01",
    "OSVersion": "Microsoft Windows 11 Pro",
    "ScanDate": "2024-12-30 14:30:22",
    "Duration": "00:05:34",
    "ModulesRun": ["Core", "STIG", "NIST", "CIS", "NSA", "CISA", "MS"],
    "TotalChecks": 3199,
    "PassCount": 487,
    "FailCount": 34,
    "WarningCount": 18,
    "InfoCount": 9,
    "ErrorCount": 2
  },
  "Results": [
    {
      "Module": "STIG",
      "Category": "STIG - V-220929 (CAT I)",
      "Status": "Fail",
      "Message": "Guest account is ENABLED",
      "Details": "STIG CAT I: Guest account must be disabled to prevent anonymous access",
      "Remediation": "Disable-LocalUser -Name Guest",
      "Timestamp": "2024-12-30 14:30:25"
    },
    {
      "Module": "STIG",
      "Category": "STIG - V-220718 (CAT II)",
      "Status": "Pass",
      "Message": "Minimum password length: 14 characters",
      "Details": "STIG: Passwords must be at least 14 characters to resist brute force",
      "Remediation": "",
      "Timestamp": "2024-12-30 14:30:25"
    }
  ]
}

Remediation File Format (Exported from HTML)

When you export selected issues from the HTML report, the JSON structure is optimized for use with -RemediationFile:

{
  "exportDate": "2024-12-30T14:30:22Z",
  "modules": [
    {
      "moduleName": "STIG",
      "results": [
        {
          "Status": "Fail",
          "Category": "STIG - V-220929 (CAT I)",
          "Finding": "Guest account is ENABLED"
        },
        {
          "Status": "Fail",
          "Category": "STIG - V-220968 (CAT II)",
          "Finding": "SMBv1 protocol is ENABLED"
        }
      ]
    },
    {
      "moduleName": "CIS",
      "results": [
        {
          "Status": "Fail",
          "Category": "CIS - Account Policy",
          "Finding": "Minimum password length is 8 characters"
        }
      ]
    }
  ]
}

Usage:

# Export selected issues from HTML report to JSON
# Then use for targeted remediation:
.\Windows-Security-Audit.ps1 -AutoRemediate -RemediationFile "selected-issues.json"

Reading JSON in PowerShell

Basic Analysis

# Load JSON file
$report = Get-Content ".\Security-Audit-Report-*.json" -Raw | ConvertFrom-Json

# Access execution information
$report.ExecutionInfo.ComputerName
$report.ExecutionInfo.TotalChecks
$report.ExecutionInfo.FailCount

# Get all results
$report.Results

# Filter by status
$failures = $report.Results | Where-Object { $_.Status -eq "Fail" }
$warnings = $report.Results | Where-Object { $_.Status -eq "Warning" }

# Display failures
$failures | Format-Table Module, Category, Message -AutoSize

Advanced Filtering

# Get CAT I STIG findings
$catI = $report.Results | Where-Object { $_.Category -like "*CAT I*" }

# Get all password-related findings
$passwordIssues = $report.Results | Where-Object { 
    $_.Message -like "*password*" -or $_.Category -like "*password*"
}

# Filter by module
$stigResults = $report.Results | Where-Object { $_.Module -eq "STIG" }
$cisResults = $report.Results | Where-Object { $_.Module -eq "CIS" }

# Get findings with remediation available
$remediable = $report.Results | Where-Object { 
    $_.Status -eq "Fail" -and $_.Remediation -ne ""
}

# Count findings by module and status
$report.Results | 
    Group-Object Module, Status | 
    Select-Object Count, Name | 
    Sort-Object Name

Statistical Analysis

# Calculate compliance rate
$totalChecks = $report.ExecutionInfo.TotalChecks
$passCount = $report.ExecutionInfo.PassCount
$complianceRate = [math]::Round(($passCount / $totalChecks) * 100, 2)

Write-Host "Compliance Rate: $complianceRate%"

# Status distribution
$statusCounts = $report.Results | Group-Object Status
foreach ($status in $statusCounts) {
    $percentage = [math]::Round(($status.Count / $totalChecks) * 100, 1)
    Write-Host "$($status.Name): $($status.Count) ($percentage%)"
}

# Module performance
$moduleStats = $report.Results | Group-Object Module | ForEach-Object {
    $moduleName = $_.Name
    $total = $_.Count
    $pass = ($_.Group | Where-Object Status -eq "Pass").Count
    $fail = ($_.Group | Where-Object Status -eq "Fail").Count
    $compliance = [math]::Round(($pass / $total) * 100, 1)
    
    [PSCustomObject]@{
        Module = $moduleName
        Total = $total
        Pass = $pass
        Fail = $fail
        Compliance = "$compliance%"
    }
}
$moduleStats | Format-Table -AutoSize

Export and Transform

# Export failures to CSV for tracking
$failures | 
    Select-Object Module, Category, Message, Remediation |
    Export-Csv "Failures-ToRemediate.csv" -NoTypeInformation

# Create remediation checklist
$failures | ForEach-Object {
    [PSCustomObject]@{
        Priority = if ($_.Category -like "*CAT I*") { "HIGH" } 
                   elseif ($_.Category -like "*CAT II*") { "MEDIUM" } 
                   else { "LOW" }
        Module = $_.Module
        Issue = $_.Message
        Remediation = $_.Remediation
        AssignedTo = ""
        Status = "Open"
        DueDate = (Get-Date).AddDays(7).ToString("yyyy-MM-dd")
    }
} | Export-Csv "Remediation-Checklist.csv" -NoTypeInformation

# Generate executive summary
$summary = @"
Security Audit Summary - $($report.ExecutionInfo.ComputerName)
Date: $($report.ExecutionInfo.ScanDate)

Overall Compliance: $complianceRate%

Critical Issues (Fail): $($report.ExecutionInfo.FailCount)
Warnings: $($report.ExecutionInfo.WarningCount)

Top Issues:
$($failures | Select-Object -First 5 | ForEach-Object { "- $($_.Message)" } | Out-String)

Full report: Security-Audit-Report-$(Get-Date -Format 'yyyyMMdd-HHmmss').html
"@

$summary | Out-File "Executive-Summary.txt"

JSON in Python

import json
from datetime import datetime

# Load JSON
with open('Security-Audit-Report-20241230-143022.json', 'r') as f:
    report = json.load(f)

# Access data
exec_info = report['ExecutionInfo']
print(f"Computer: {exec_info['ComputerName']}")
print(f"Total Checks: {exec_info['TotalChecks']}")
print(f"Failures: {exec_info['FailCount']}")
print(f"Compliance: {(exec_info['PassCount']/exec_info['TotalChecks']*100):.1f}%")

# Filter failures
failures = [r for r in report['Results'] if r['Status'] == 'Fail']
print(f"\nFailures ({len(failures)}):")
for fail in failures:
    print(f"  [{fail['Module']}] {fail['Message']}")

# Group by module
from collections import defaultdict
by_module = defaultdict(lambda: {'total': 0, 'pass': 0, 'fail': 0})

for result in report['Results']:
    module = result['Module']
    by_module[module]['total'] += 1
    if result['Status'] == 'Pass':
        by_module[module]['pass'] += 1
    elif result['Status'] == 'Fail':
        by_module[module]['fail'] += 1

print("\nModule Summary:")
for module, stats in by_module.items():
    compliance = (stats['pass'] / stats['total'] * 100)
    print(f"  {module}: {compliance:.1f}% ({stats['pass']}/{stats['total']})")

# Create remediation list
remediation_list = [
    {
        'priority': 'HIGH' if 'CAT I' in r['Category'] else 'MEDIUM',
        'module': r['Module'],
        'issue': r['Message'],
        'remediation': r['Remediation']
    }
    for r in failures if r['Remediation']
]

# Export to JSON
with open('remediation-plan.json', 'w') as f:
    json.dump(remediation_list, f, indent=2)

JSON in JavaScript/Node.js

const fs = require('fs');

// Load JSON
const report = JSON.parse(
  fs.readFileSync('Security-Audit-Report-20241230-143022.json', 'utf8')
);

// Access data
const { ExecutionInfo, Results } = report;
console.log(`Computer: ${ExecutionInfo.ComputerName}`);
console.log(`Total Checks: ${ExecutionInfo.TotalChecks}`);
console.log(`Failures: ${ExecutionInfo.FailCount}`);

// Calculate compliance
const compliance = ((ExecutionInfo.PassCount / ExecutionInfo.TotalChecks) * 100).toFixed(1);
console.log(`Compliance: ${compliance}%`);

// Filter and group
const failures = Results.filter(r => r.Status === 'Fail');
const byModule = Results.reduce((acc, r) => {
  if (!acc[r.Module]) {
    acc[r.Module] = { total: 0, pass: 0, fail: 0 };
  }
  acc[r.Module].total++;
  if (r.Status === 'Pass') acc[r.Module].pass++;
  if (r.Status === 'Fail') acc[r.Module].fail++;
  return acc;
}, {});

console.log('\nModule Summary:');
Object.entries(byModule).forEach(([module, stats]) => {
  const moduleCompliance = ((stats.pass / stats.total) * 100).toFixed(1);
  console.log(`  ${module}: ${moduleCompliance}% (${stats.pass}/${stats.total})`);
});

// Create issue tickets
const tickets = failures.map(f => ({
  title: f.Message,
  description: f.Details,
  priority: f.Category.includes('CAT I') ? 'Critical' : 'High',
  category: f.Category,
  remediation: f.Remediation,
  module: f.Module
}));

// Export
fs.writeFileSync('tickets.json', JSON.stringify(tickets, null, 2));

JSON Use Cases

Browser Export Formats (from HTML Report)

The HTML report provides 6 browser-based export formats via the "Export All" / "Export Selected" modal:

Format Description Use Case
CSV Workbook Comma-separated values with all fields Spreadsheet analysis, data import
Excel (XLS) HTML-based Excel workbook format Direct opening in Microsoft Excel
JSON Structured Data Formatted JSON with metadata envelope API integration, programmatic analysis
XML Workbook XSL-styled self-rendering XML Browser viewing, XML-based tools, data interchange
XML SIEM-Compatible Event-based XML with severity/timestamp SIEM ingestion (Splunk, QRadar, ArcSight)
TXT Plain Text Human-readable plain text report Email, documentation, log archival

The XML Workbook format uses an embedded XSLT stylesheet that renders the XML as a styled HTML table when opened in any modern browser. The data remains valid XML within the urn:windows-security-audit namespace, parseable by XML tools.

The XML SIEM-Compatible format produces raw XML without styling, optimized for secondary processing by SIEM appliances and log aggregation platforms.

1. SIEM Integration (Splunk)

# Index JSON files
/opt/splunk/bin/splunk add oneshot /path/to/reports/*.json \
  -sourcetype windows:security:audit \
  -index security

Splunk Search Queries:

# Find all failures
sourcetype="windows:security:audit" ExecutionInfo.FailCount>0
| table ExecutionInfo.ComputerName, ExecutionInfo.FailCount

# Track compliance over time
sourcetype="windows:security:audit"
| eval compliance=(ExecutionInfo.PassCount/ExecutionInfo.TotalChecks)*100
| timechart avg(compliance) by ExecutionInfo.ComputerName

# Alert on critical failures
sourcetype="windows:security:audit" Results{}.Status="Fail" Results{}.Category="*CAT I*"
| table ExecutionInfo.ComputerName, Results{}.Message

2. Ticketing System (ServiceNow)

// Create incidents from failures
const report = require('./Security-Audit-Report-20241230.json');
const failures = report.Results.filter(r => r.Status === 'Fail');

failures.forEach(fail => {
  const priority = fail.Category.includes('CAT I') ? '1' : 
                   fail.Category.includes('CAT II') ? '2' : '3';
  
  createIncident({
    short_description: `[${fail.Module}] ${fail.Message}`,
    description: fail.Details,
    work_notes: `Remediation: ${fail.Remediation}`,
    priority: priority,
    category: 'Security',
    subcategory: fail.Module,
    assigned_to: 'security-team',
    configuration_item: report.ExecutionInfo.ComputerName
  });
});

3. Dashboard/Metrics (Grafana/InfluxDB)

from influxdb import InfluxDBClient
import json

client = InfluxDBClient(host='localhost', port=8086, database='security_metrics')

with open('Security-Audit-Report-20241230.json') as f:
    report = json.load(f)

# Write metrics to InfluxDB
points = [{
    "measurement": "security_audit",
    "tags": {
        "hostname": report['ExecutionInfo']['ComputerName'],
        "os_version": report['ExecutionInfo']['OSVersion']
    },
    "time": report['ExecutionInfo']['ScanDate'],
    "fields": {
        "total_checks": report['ExecutionInfo']['TotalChecks'],
        "pass_count": report['ExecutionInfo']['PassCount'],
        "fail_count": report['ExecutionInfo']['FailCount'],
        "warning_count": report['ExecutionInfo']['WarningCount'],
        "compliance_rate": (report['ExecutionInfo']['PassCount'] / 
                           report['ExecutionInfo']['TotalChecks'] * 100)
    }
}]

# Add per-module metrics
for module in set(r['Module'] for r in report['Results']):
    module_results = [r for r in report['Results'] if r['Module'] == module]
    pass_count = sum(1 for r in module_results if r['Status'] == 'Pass')
    
    points.append({
        "measurement": "security_audit_module",
        "tags": {
            "hostname": report['ExecutionInfo']['ComputerName'],
            "module": module
        },
        "time": report['ExecutionInfo']['ScanDate'],
        "fields": {
            "total": len(module_results),
            "pass": pass_count,
            "compliance": (pass_count / len(module_results) * 100)
        }
    })

client.write_points(points)

4. Email Alerts

$report = Get-Content ".\Security-Audit-Report-*.json" -Raw | ConvertFrom-Json
$failures = $report.Results | Where-Object { $_.Status -eq "Fail" }

# Alert on critical failures
$criticalFailures = $failures | Where-Object { $_.Category -like "*CAT I*" }

if ($criticalFailures.Count -gt 0) {
    $body = @"
CRITICAL SECURITY ALERT
=======================

System: $($report.ExecutionInfo.ComputerName)
Date: $($report.ExecutionInfo.ScanDate)

Critical Failures ($($criticalFailures.Count)):

$(foreach ($fail in $criticalFailures) {
    "• [$($fail.Module)] $($fail.Message)`n  Remediation: $($fail.Remediation)`n"
})

Full Report: \\FileServer\Security\Audits\$($report.ExecutionInfo.ComputerName)\
"@

    Send-MailMessage `
        -To "security-team@company.com", "manager@company.com" `
        -From "security-audit@company.com" `
        -Subject "🚨 CRITICAL: Security Failures on $($report.ExecutionInfo.ComputerName)" `
        -Body $body `
        -Priority High `
        -SmtpServer "smtp.company.com"
}

CSV Report

Overview

The CSV report provides tabular data optimized for spreadsheet analysis, tracking remediation over time, and creating dashboards.

CSV Structure

Module,Category,Status,Message,Details,Remediation,Timestamp
STIG,"STIG - V-220929 (CAT I)",Fail,Guest account is ENABLED,"STIG CAT I: Guest account must be disabled to prevent anonymous access",Disable-LocalUser -Name Guest,2024-12-30 14:30:25
STIG,"STIG - V-220718 (CAT II)",Pass,Minimum password length: 14 characters,"STIG: Passwords must be at least 14 characters to resist brute force",,2024-12-30 14:30:25
CIS,"CIS - Account Policy",Fail,Minimum password length is 8 characters,"CIS Benchmark: Set minimum password length to 14 or more characters",net accounts /minpwlen:14,2024-12-30 14:30:26

Field Descriptions:

  • Module - Framework name (Core, STIG, NIST, CIS, NSA, CISA, MS)
  • Category - Specific control or requirement ID
  • Status - Result status (Pass, Fail, Warning, Info, Error)
  • Message - Brief description of the finding
  • Details - Extended information about the check
  • Remediation - PowerShell command or instructions to fix
  • Timestamp - When the check was performed

Opening in Excel

Method 1: Double-Click

  • Navigate to CSV file
  • Double-click to open in Excel
  • Columns auto-detected

Method 2: Import Data Wizard

Excel → Data → From Text/CSV
→ Select file
→ Delimiter: Comma
→ Text qualifier: " (double quote)
→ Click "Load"

Method 3: Power Query

Excel → Data → Get Data → From File → From Text/CSV
→ Select file
→ Click "Transform Data" for advanced options
→ Data Types detected automatically
→ Click "Close & Load"

Excel Analysis Examples

1. Filter and Sort

Show Only Failures:

1. Select data range (Ctrl+A)
2. Data → Filter
3. Click Status column dropdown
4. Uncheck all except "Fail"
5. Click OK

Sort by Priority:

1. Add helper column: Priority
2. Formula: =IF(ISNUMBER(SEARCH("CAT I",B2)),"Critical",IF(ISNUMBER(SEARCH("CAT II",B2)),"High","Medium"))
3. Sort by Priority column (Critical → High → Medium)

2. PivotTable Analysis

Create Status Summary by Module:

1. Select data range
2. Insert → PivotTable
3. Drag "Module" to Rows
4. Drag "Status" to Columns
5. Drag "Status" to Values (Count)
6. Result: Cross-tab showing Pass/Fail/Warning counts per module

Compliance Percentage Calculation:

1. In PivotTable
2. Add Calculated Field: Compliance
3. Formula: =Pass/(Pass+Fail+Warning)*100
4. Format as percentage

3. Conditional Formatting

Color-Code Status Column:

1. Select Status column
2. Home → Conditional Formatting → New Rule
3. Format cells that contain:
   - "Fail" → Red background, white text
   - "Pass" → Green background, white text
   - "Warning" → Yellow background, black text
   - "Info" → Blue background, white text
4. Apply to range

Highlight Priority Issues:

1. Select Category column
2. Conditional Formatting → Highlight Cell Rules → Text that Contains
3. Enter "CAT I" → Red fill with dark red text
4. Repeat for "CAT II" → Orange fill

4. Dashboard Creation

Compliance Dashboard Template:

A1: Security Audit Dashboard
A2: System: [=B2]
A3: Date: [=B3]

A5: Overall Statistics
A6: Total Checks: [=COUNTA(Status column)]
A7: Passed: [=COUNTIF(Status,"Pass")]
A8: Failed: [=COUNTIF(Status,"Fail")]
A9: Compliance Rate: [=A7/A6] (format as %)

A11: [Pie Chart: Status Distribution]
A20: [Bar Chart: Failures by Module]
A30: [Line Chart: Trend over time (if multiple audits)]

B5: Top 5 Critical Issues
B6: [Table filtered to CAT I failures, top 5]

Charts to Create:

  1. Pie Chart - Status distribution (Pass/Fail/Warning/Info/Error)
  2. Bar Chart - Count of failures by module
  3. Stacked Bar - Pass/Fail/Warning per module
  4. Line Chart - Compliance trend over time (requires multiple audit files)

Tracking Remediation Progress

Initial Setup

Step 1: Run Baseline Audit

.\Windows-Security-Audit.ps1 -OutputFormat CSV

Step 2: Create Tracking Spreadsheet

1. Open baseline CSV in Excel
2. Filter to show only "Fail" status
3. Copy filtered results to new sheet: "Remediation Tracking"
4. Add columns:
   - Column H: Assigned To
   - Column I: Priority (High/Medium/Low)
   - Column J: Due Date
   - Column K: Status (Open/In Progress/Complete)
   - Column L: Completion Date
   - Column M: Notes
5. Save as "Remediation-Tracker-2024-12.xlsx"

Tracking Workflow

Week 1: Assign issues
  - Assign critical (CAT I) to security team
  - Set due dates (7 days for critical, 30 for others)
  - Status: Open

Week 2: Begin remediation
  - Update Status to "In Progress"
  - Add notes on progress/blockers

Week 3: Verify fixes
  - Run new audit
  - Compare results
  - Mark items "Complete" with completion date

Week 4: Management report
  - Generate summary metrics
  - Show improvement trend
  - Identify remaining issues

Comparison Formula

Compare Current vs Baseline:

// In current audit sheet, add column:
=VLOOKUP(B2,Baseline!B:C,2,FALSE)
// Returns status from baseline for same finding

// Conditional format:
// If previous = "Fail" AND current = "Pass" → Green (Fixed)
// If previous = "Fail" AND current = "Fail" → Red (Not Fixed)

Progress Metrics

// Overall improvement
Total Issues (Baseline): [=COUNTIF(Baseline!C:C,"Fail")]
Resolved Issues: [=COUNTIF(Current!C:C,"Pass")-COUNTIF(Baseline!C:C,"Pass")]
Remaining Issues: [=COUNTIF(Current!C:C,"Fail")]
Resolution Rate: [=Resolved/Total*100]%

// By module
Module: STIG
Baseline Failures: [=COUNTIFS(Baseline!A:A,"STIG",Baseline!C:C,"Fail")]
Current Failures: [=COUNTIFS(Current!A:A,"STIG",Current!C:C,"Fail")]
Improvement: [=Baseline-Current]

CSV in PowerShell

# Import CSV
$audit = Import-Csv ".\Security-Audit-Report-*.csv"

# Basic statistics
$total = $audit.Count
$pass = ($audit | Where-Object Status -eq "Pass").Count
$fail = ($audit | Where-Object Status -eq "Fail").Count
$compliance = [math]::Round(($pass / $total) * 100, 1)

Write-Host "Compliance: $compliance% ($pass/$total)"

# Group by module
$byModule = $audit | Group-Object Module | ForEach-Object {
    $moduleTotal = $_.Count
    $modulePass = ($_.Group | Where-Object Status -eq "Pass").Count
    $moduleCompliance = [math]::Round(($modulePass / $moduleTotal) * 100, 1)
    
    [PSCustomObject]@{
        Module = $_.Name
        Total = $moduleTotal
        Pass = $modulePass
        Fail = ($_.Group | Where-Object Status -eq "Fail").Count
        Compliance = "$moduleCompliance%"
    }
}

$byModule | Format-Table -AutoSize

# Export failures for remediation
$failures = $audit | Where-Object { $_.Status -eq "Fail" }
$failures | Select-Object Module, Category, Message, Remediation |
    Export-Csv "Remediation-List.csv" -NoTypeInformation

# Create summary report
$summary = @"
Security Audit Summary
Date: $(Get-Date -Format 'yyyy-MM-dd')

Overall: $compliance% compliant
- Total: $total
- Pass: $pass
- Fail: $fail

By Module:
$($byModule | Format-Table -AutoSize | Out-String)
"@

$summary | Out-File "Summary-Report.txt"

CSV Use Cases

1. SQL Database Import

-- Create table
CREATE TABLE audit_results (
    id INT IDENTITY(1,1) PRIMARY KEY,
    audit_date DATE,
    hostname VARCHAR(50),
    module VARCHAR(50),
    category VARCHAR(100),
    status VARCHAR(20),
    message VARCHAR(500),
    details TEXT,
    remediation VARCHAR(500),
    timestamp DATETIME
);

-- Bulk import CSV
BULK INSERT audit_results
FROM 'C:\Audits\Security-Audit-Report-20241230.csv'
WITH (
    FORMAT = 'CSV',
    FIRSTROW = 2,
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n'
);

-- Query compliance trend
SELECT 
    audit_date,
    COUNT(*) as total_checks,
    SUM(CASE WHEN status = 'Pass' THEN 1 ELSE 0 END) as passed,
    SUM(CASE WHEN status = 'Fail' THEN 1 ELSE 0 END) as failed,
    CAST(SUM(CASE WHEN status = 'Pass' THEN 1 ELSE 0 END) * 100.0 / COUNT(*) AS DECIMAL(5,2)) as compliance_rate
FROM audit_results
GROUP BY audit_date
ORDER BY audit_date;

2. PowerBI Dashboard

Setup:

1. Open PowerBI Desktop
2. Get Data → CSV
3. Select Security-Audit-Report-*.csv
4. Transform Data:
   - Set data types (Module=Text, Status=Text, etc.)
   - Add calculated column: Priority
     = IF([Category] CONTAINS "CAT I", "Critical", 
          IF([Category] CONTAINS "CAT II", "High", "Medium"))
5. Load data

6. Create visualizations:
   - Card: Total Checks, Pass Count, Fail Count, Compliance %
   - Donut Chart: Status distribution
   - Bar Chart: Failures by module
   - Table: Top 10 critical failures
   - Line Chart: Compliance trend (requires multiple imports over time)

DAX Measures:

Compliance Rate = 
    DIVIDE(
        CALCULATE(COUNT('audit'[Status]), 'audit'[Status] = "Pass"),
        COUNT('audit'[Status])
    )

Critical Failures = 
    CALCULATE(
        COUNT('audit'[Status]),
        'audit'[Status] = "Fail",
        'audit'[Priority] = "Critical"
    )

3. Compliance Tracking Database

# Create tracking database
$trackingData = Import-Csv ".\Security-Audit-Report-*.csv" | 
    Where-Object { $_.Status -eq "Fail" } |
    Select-Object @{N='AuditDate';E={Get-Date -Format 'yyyy-MM-dd'}},
                  @{N='Hostname';E={$env:COMPUTERNAME}},
                  Module,
                  Category,
                  Message,
                  @{N='Priority';E={
                      if ($_.Category -like "*CAT I*") { "Critical" }
                      elseif ($_.Category -like "*CAT II*") { "High" }
                      else { "Medium" }
                  }},
                  @{N='AssignedTo';E={''}},
                  @{N='DueDate';E={(Get-Date).AddDays(7).ToString('yyyy-MM-dd')}},
                  @{N='Status';E={'Open'}},
                  @{N='CompletionDate';E={''}},
                  @{N='Notes';E={''}}

$trackingData | Export-Csv "Remediation-Tracking-$(Get-Date -Format 'yyyyMMdd').csv" -NoTypeInformation

XML Report

Overview

The XML report provides standards-compliant, hierarchical data specifically optimized for SIEM ingestion, compliance management systems, and enterprise security tools.

XML Structure (New in v6.0)

<?xml version="1.0" encoding="UTF-8"?>
<security_audit>
  <metadata>
    <export_date>2024-12-30T14:30:22Z</export_date>
    <computer_name>WORKSTATION01</computer_name>
    <operating_system>Microsoft Windows 11 Pro</operating_system>
    <scan_date>2024-12-30 14:30:22</scan_date>
    <duration>00:05:34</duration>
    <total_checks>3199</total_checks>
    <pass_count>487</pass_count>
    <fail_count>34</fail_count>
    <warning_count>18</warning_count>
    <info_count>9</info_count>
    <error_count>2</error_count>
  </metadata>
  <events>
    <event>
      <timestamp>2024-12-30T14:30:25Z</timestamp>
      <module>STIG</module>
      <status>Fail</status>
      <category>STIG - V-220929 (CAT I)</category>
      <message>Guest account is ENABLED</message>
      <details>STIG CAT I: Guest account must be disabled to prevent anonymous access</details>
      <remediation>Disable-LocalUser -Name Guest</remediation>
    </event>
    <event>
      <timestamp>2024-12-30T14:30:25Z</timestamp>
      <module>STIG</module>
      <status>Pass</status>
      <category>STIG - V-220718 (CAT II)</category>
      <message>Minimum password length: 14 characters</message>
      <details>STIG: Passwords must be at least 14 characters to resist brute force</details>
      <remediation></remediation>
    </event>
  </events>
</security_audit>

XML Features

Benefits:

  • ✅ Standards-compliant format
  • ✅ Hierarchical structure for complex data
  • ✅ Wide SIEM compatibility
  • ✅ XPath query support
  • ✅ Schema validation capable
  • ✅ Direct ingestion by security tools

Reading XML in PowerShell

# Load XML
[xml]$report = Get-Content ".\Security-Audit-Report-*.xml"

# Access metadata
$report.security_audit.metadata.computer_name
$report.security_audit.metadata.total_checks
$report.security_audit.metadata.fail_count

# Get all events
$events = $report.security_audit.events.event

# Filter failures
$failures = $events | Where-Object { $_.status -eq "Fail" }

# Display failures
$failures | ForEach-Object {
    Write-Host "[$($_.module)] $($_.message)" -ForegroundColor Red
    Write-Host "  Remediation: $($_.remediation)" -ForegroundColor Yellow
}

# Count by status
$events | Group-Object status | Format-Table Count, Name -AutoSize

# Get critical findings
$critical = $events | Where-Object { 
    $_.status -eq "Fail" -and $_.category -like "*CAT I*" 
}

Write-Host "`nCritical Failures: $($critical.Count)" -ForegroundColor Red
$critical | ForEach-Object {
    Write-Host "- $($_.message)" -ForegroundColor Red
}

XML Parsing in Python

import xml.etree.ElementTree as ET

# Parse XML
tree = ET.parse('Security-Audit-Report-20241230-143022.xml')
root = tree.getroot()

# Access metadata
metadata = root.find('metadata')
computer = metadata.find('computer_name').text
total = int(metadata.find('total_checks').text)
failed = int(metadata.find('fail_count').text)
compliance = ((total - failed) / total * 100)

print(f"Computer: {computer}")
print(f"Total Checks: {total}")
print(f"Failed: {failed}")
print(f"Compliance: {compliance:.1f}%")

# Parse events
events = root.find('events')
failures = []

for event in events.findall('event'):
    if event.find('status').text == 'Fail':
        failures.append({
            'module': event.find('module').text,
            'category': event.find('category').text,
            'message': event.find('message').text,
            'remediation': event.find('remediation').text
        })

print(f"\nFailures ({len(failures)}):")
for fail in failures:
    print(f"  [{fail['module']}] {fail['message']}")

XML Use Cases

1. SIEM Integration (Splunk)

<!-- inputs.conf -->
<monitor>
  <path>C:\SecurityAudits\Reports\*.xml</path>
  <sourcetype>windows:security:audit:xml</sourcetype>
  <index>security</index>
</monitor>

Splunk Search Queries:

sourcetype="windows:security:audit:xml"
| xmlkv
| table computer_name, fail_count, compliance_rate

sourcetype="windows:security:audit:xml" status="Fail"
| stats count by module, category

2. ArcSight Integration

<!-- Import XML reports directly into ArcSight -->
<!-- Configure XML FlexConnector to parse security_audit format -->

3. QRadar Integration

# Configure log source to parse XML
# Map fields: module → category, status → severity

Console Output

Overview

Real-time progress display during script execution with color-coded status indicators.

Console Output Format

[*] Starting Windows Security Audit Script v6.0
[*] Output Directory: C:\SecurityAudit\Reports
[*] Running Modules: Core, STIG, NIST, CIS, NSA, CISA, MS

[Core] Starting Core security baseline checks...
[Core] Checking User Accounts...
[Core] Checking Account Policies...
[Core] Checking Windows Defender...
[Core] Module completed:
  Total Checks: 42
  Passed: 38
  Failed: 2
  Warnings: 1
  Info: 1
  Errors: 0

[STIG] Starting DISA STIG compliance checks...
[STIG] Checking Account Policies...
[STIG] Checking Audit Policy Configuration...
[STIG] Module completed:
  Total Checks: 92
  Passed: 78
  Failed: 8
  Warnings: 4
  Info: 2
  Errors: 0

...

[*] ========================================
[*] Audit Complete!
[*] ========================================
[*] Total Checks: 3199
[*] Passed: 487 (88.5%)
[*] Failed: 34 (6.2%)
[*] Warnings: 18 (3.3%)
[*] Info: 9 (1.6%)
[*] Errors: 2 (0.4%)
[*] 
[*] Reports generated:
[*]   HTML: C:\SecurityAudit\Reports\Security-Audit-Report-20241225-143022.html
[*]   JSON: C:\SecurityAudit\Reports\Security-Audit-Report-20241225-143022.json
[*]   CSV:  C:\SecurityAudit\Reports\Security-Audit-Report-20241225-143022.csv
[*]   XML:  C:\SecurityAudit\Reports\Security-Audit-Report-20241225-143022.xml

Color Coding

  • Cyan - Module names and section headers
  • Yellow - Category/check group names
  • Green - Pass status, success messages
  • Red - Fail status, error messages
  • Magenta - Module completion summaries
  • White - Neutral information

Capturing Console Output

# Redirect to file
.\Windows-Security-Audit.ps1 > audit_log.txt 2>&1

# Save transcript
Start-Transcript -Path "audit_transcript.txt"
.\Windows-Security-Audit.ps1
Stop-Transcript

# Run in background job
Start-Job -ScriptBlock { 
    C:\SecurityAudit\Windows-Security-Audit.ps1 
}
# Check job status
Get-Job | Format-Table -AutoSize
# Retrieve job output
Receive-Job -Id 1

Report Locations

Default Output Directory

.\

Current directory where script is executed

Example:
C:\SecurityAudit\Security-Audit-Report-20241230-143022.html

Custom Output Directory

# Specify custom location
.\Windows-Security-Audit.ps1 -OutputPath "C:\AuditReports\Report.html"

# Network share
.\Windows-Security-Audit.ps1 -OutputPath "\\FileServer\Security\Audits\Report.html"

# Timestamped folders
$date = Get-Date -Format "yyyy-MM-dd"
.\Windows-Security-Audit.ps1 -OutputPath "C:\Audits\$date\Report.html"

# Per-computer folders
.\Windows-Security-Audit.ps1 -OutputPath "C:\Audits\$env:COMPUTERNAME\Report.html"

Finding Reports

# List recent HTML reports
Get-ChildItem ".\Security-Audit-Report-*.html" | 
    Sort-Object LastWriteTime -Descending |
    Select-Object -First 5

# Find today's reports
$today = Get-Date -Format "yyyyMMdd"
Get-ChildItem ".\Security-Audit-Report-$today*.html"

# Find all reports
Get-ChildItem ".\Security-Audit-Report-*.html"
Get-ChildItem ".\Security-Audit-Report-*.json"
Get-ChildItem ".\Security-Audit-Report-*.csv"
Get-ChildItem ".\Security-Audit-Report-*.xml"

Parsing and Integration

PowerShell Integration

# Load and analyze JSON
$report = Get-Content ".\Security-Audit-Report-*.json" -Raw | ConvertFrom-Json

# Extract key metrics
$metrics = @{
    Hostname = $report.ExecutionInfo.ComputerName
    TotalChecks = $report.ExecutionInfo.TotalChecks
    Failures = $report.ExecutionInfo.FailCount
    ComplianceRate = [math]::Round(($report.ExecutionInfo.PassCount / $report.ExecutionInfo.TotalChecks * 100), 1)
    AuditDate = $report.ExecutionInfo.ScanDate
}

# Store in database
Invoke-SqlCmd -Query "
    INSERT INTO AuditMetrics (Hostname, Date, Total, Failures, Compliance)
    VALUES ('$($metrics.Hostname)', '$($metrics.AuditDate)', 
            $($metrics.TotalChecks), $($metrics.Failures), $($metrics.ComplianceRate))
"

REST API Example (Node.js)

const fs = require('fs');
const express = require('express');
const app = express();

// Endpoint to retrieve audit results
app.get('/api/audit/:hostname', (req, res) => {
  const reportPath = `./Reports/Security-Audit-Report-*.json`;
  const report = JSON.parse(fs.readFileSync(reportPath, 'utf8'));
  
  if (report.ExecutionInfo.ComputerName === req.params.hostname) {
    res.json({
      hostname: report.ExecutionInfo.ComputerName,
      date: report.ExecutionInfo.ScanDate,
      compliance: (report.ExecutionInfo.PassCount / report.ExecutionInfo.TotalChecks * 100).toFixed(1),
      failures: report.Results.filter(r => r.Status === 'Fail')
    });
  } else {
    res.status(404).send('Report not found');
  }
});

app.listen(3000);

Elasticsearch Ingestion

from elasticsearch import Elasticsearch
import json

es = Elasticsearch(['http://localhost:9200'])

with open('Security-Audit-Report-20241230.json') as f:
    report = json.load(f)
    
# Index document
es.index(
    index='security-audits',
    document={
        'hostname': report['ExecutionInfo']['ComputerName'],
        'audit_date': report['ExecutionInfo']['ScanDate'],
        'results': report['Results'],
        'summary': {
            'total': report['ExecutionInfo']['TotalChecks'],
            'pass': report['ExecutionInfo']['PassCount'],
            'fail': report['ExecutionInfo']['FailCount'],
            'compliance': (report['ExecutionInfo']['PassCount'] / 
                          report['ExecutionInfo']['TotalChecks'] * 100)
        }
    }
)

Report Retention

Recommended Retention Policy

Purpose Retention Reasoning
Active Analysis 30 days Recent trend analysis
Compliance Evidence 1-3 years Audit requirements
Historical Trending 1 year monthly Long-term metrics
Baseline Snapshots Indefinite Gold image validation

Archival Strategy

# Compress old reports (>90 days)
$oldReports = Get-ChildItem ".\Security-Audit-Report-*" | 
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-90) }

$archiveName = "SecurityAudits_Archive_$(Get-Date -Format 'yyyyMM').zip"
Compress-Archive -Path $oldReports -DestinationPath ".\Archives\$archiveName"

# Delete originals after successful compression
if (Test-Path ".\Archives\$archiveName") {
    $oldReports | Remove-Item
}

Storage Requirements

Typical sizes per audit:

  • HTML: 300-600 KB
  • JSON: 100-300 KB
  • CSV: 50-150 KB
  • XML: 150-400 KB
  • Total: ~600 KB - 1.6 MB

Annual storage (weekly audits):

  • 52 weeks × ~1 MB = ~52 MB per system
  • 100 systems × 52 MB = ~5 GB per year

Best Practices

Security

Do:

  • Store reports in secured location with access controls
  • Consider encrypting sensitive reports
  • Implement proper file permissions
  • Audit access to report directories

Don't:

  • Email reports unencrypted to large distribution lists
  • Store reports in publicly accessible shares
  • Commit reports to version control
  • Share reports outside organization without review

Organization

Recommended folder structure:
Reports/
├── Active/          # Last 30 days
├── Monthly/         # Monthly baseline snapshots
├── Archives/        # Compressed older reports
└── Remediation/     # Tracking spreadsheets

Automation

# Automated weekly report generation and archival
$scriptPath = "C:\SecurityAudit\Windows-Security-Audit.ps1"
$outputPath = "\\FileServer\Security\Audits\$env:COMPUTERNAME"

# Run audit
& $scriptPath -OutputPath "$outputPath\Report.html"

# Copy to monthly snapshot if first week of month
if ((Get-Date).Day -le 7) {
    $monthlyPath = "\\FileServer\Security\Monthly\$env:COMPUTERNAME"
    New-Item -ItemType Directory -Force -Path $monthlyPath | Out-Null
    Copy-Item "$outputPath\Security-Audit-Report-*.html" -Destination $monthlyPath
}

# Email summary to security team
$report = Get-Content "$outputPath\Security-Audit-Report-*.json" -Raw | ConvertFrom-Json
if ($report.ExecutionInfo.FailCount -gt 10) {
    Send-MailMessage -To "security@company.com" `
        -Subject "Security Audit Alert - $env:COMPUTERNAME" `
        -Body "Audit found $($report.ExecutionInfo.FailCount) failures" `
        -SmtpServer "smtp.company.com"
}

Related Documentation:

Clone this wiki locally