All Posts Automation

How to Run a Security Audit on Your Own Business (Free Checklist)

You know you should be auditing your business's security. You also know you should be flossing every night and rotating your tires every 5,000 miles.

A small business security audit is a systematic review of your technology, policies, and practices that takes about two hours per quarter and covers 80-90 percent of the security gaps that lead to real breaches. This guide provides a complete seven-domain checklist, two PowerShell scripts (a network scanner and a firewall checker), and a step-by-step self-audit process — no $15,000 penetration test or consulting firm required.

You know you should be auditing your business’s security. You also know you should be flossing every night and rotating your tires every 5,000 miles. The problem with security audits is the same problem as flossing: it sounds vague, nobody taught you exactly how to do it properly, and skipping it works fine right up until the moment it very much does not.

Here is what nobody tells small business owners about security audits: you do not need a $15,000 penetration test. You do not need a consulting firm with a fancy report. What you need is a systematic, repeatable process that takes about two hours per quarter — and the discipline to actually do it. Most breaches that hit small businesses exploit gaps so basic that a structured checklist would have caught them months in advance.

A small business security audit is a systematic review of your technology, policies, and practices to identify vulnerabilities before attackers find them. For most small businesses, a quarterly self-audit using a structured checklist — combined with automated scanning scripts — covers 80-90% of the security gaps that lead to real breaches. This guide gives you the complete checklist, two PowerShell scripts (a network scanner and a firewall checker), and a step-by-step process you can run in under two hours every quarter.

I am going to walk you through the exact audit process I use with clients across Volusia County. No fluff, no theory, just the checklist and the scripts.

What a Security Audit Actually Covers

Before we start running scripts, let me frame what we are actually assessing. A proper security audit covers seven domains. Most small businesses only think about one or two of these — usually the technical ones — and completely ignore the rest. That is how you end up with an encrypted server but an unlocked server room, or a great firewall policy but an ex-employee who still has access.

Domain 1: Network Security. Are your firewalls configured correctly? Are unnecessary ports closed? Is your Wi-Fi segmented so guest traffic cannot reach business systems? Are there any unauthorized devices on your network?

Domain 2: Access Control. Who has access to what? Are there accounts for people who no longer work here? Does everyone have unique credentials, or is there a shared “admin” password written on a Post-it under the keyboard?

Domain 3: Endpoint Security. Are all workstations and servers running current antivirus? Are operating systems patched? Is disk encryption enabled on laptops?

Domain 4: Data Protection. Where is sensitive data stored? Is it encrypted at rest and in transit? Are backups working and tested? How long do you retain data, and are you retaining more than you need?

Domain 5: Physical Security. Are server rooms locked? Are POS terminals in supervised areas? Can a visitor access network ports or USB ports on company machines?

Domain 6: Policies and Documentation. Do you have a written security policy? An incident response plan? Are employee roles and responsibilities documented? Is there an acceptable use policy that employees have signed?

Domain 7: Human Factors. Have employees received security awareness training in the last 12 months? Do they know how to report a phishing attempt? Is there a clean desk policy?

The checklist I am about to give you covers all seven domains. The PowerShell scripts automate the technical checks for domains 1, 2, 3, and parts of 4. The rest requires you and your team walking through questions and being honest about the answers.

The Complete Security Audit Checklist

Print this out. Or better yet, copy it into a spreadsheet so you can track your scores over time. Rate each item as PASS, PARTIAL, or FAIL. A PASS means it is fully implemented and documented. PARTIAL means it exists but has gaps. FAIL means it is not implemented or you are not sure — and “not sure” counts as a fail because uncertainty is a vulnerability. We cover this in more detail in Year-End IT Audit: What to Check Before January 1st.

Network Security (Domain 1)

  • [ ] Firewall is enabled on all profiles (Domain, Private, Public) on every machine
  • [ ] Default router/firewall admin credentials have been changed
  • [ ] Router firmware is updated to the latest version
  • [ ] Guest Wi-Fi is on a separate VLAN from business network
  • [ ] WPA3 (or WPA2-AES minimum) is used for all wireless networks
  • [ ] No open or unnecessary ports are exposed to the internet
  • [ ] Remote access (RDP, VPN) is restricted and requires MFA
  • [ ] Network diagram exists and is current
  • [ ] All devices on the network are identified and authorized
  • [ ] DNS filtering is configured to block known malicious domains

Access Control (Domain 2)

  • [ ] Every user has a unique account (no shared logins)
  • [ ] MFA is enabled on all email accounts
  • [ ] MFA is enabled on all cloud services
  • [ ] MFA is enabled on all financial/banking accounts
  • [ ] Former employees’ accounts are disabled within 24 hours of departure
  • [ ] Admin/root access is limited to personnel who require it
  • [ ] Password minimum length is 12+ characters
  • [ ] Account lockout is configured (max 10 failed attempts)
  • [ ] Privileged accounts are inventoried and reviewed quarterly
  • [ ] Remote access accounts are reviewed monthly

Endpoint Security (Domain 3)

  • [ ] Antivirus/anti-malware is installed and active on all workstations
  • [ ] Antivirus definitions are updated automatically
  • [ ] Operating system automatic updates are enabled
  • [ ] All OS versions are vendor-supported (no Windows 7, no end-of-life systems)
  • [ ] Full disk encryption is enabled on all laptops
  • [ ] USB device policies are in place (block unauthorized devices or auto-run)
  • [ ] Screen lock activates after 5 minutes of inactivity
  • [ ] Critical security patches are installed within 30 days of release
  • [ ] POS systems are on dedicated, hardened machines (not general-purpose PCs)
  • [ ] Browser extensions are audited and unapproved extensions removed

Data Protection (Domain 4)

  • [ ] Backups run daily for critical data
  • [ ] Backup restores have been tested within the last 90 days
  • [ ] At least one backup copy is offsite or in the cloud
  • [ ] At least one backup is immutable (cannot be deleted/encrypted by ransomware)
  • [ ] Sensitive data at rest is encrypted
  • [ ] Data in transit uses TLS 1.2 or higher
  • [ ] TLS 1.0 and 1.1 are disabled
  • [ ] Data retention policy exists and data is purged on schedule
  • [ ] Customer payment data is not stored unnecessarily
  • [ ] Sensitive data is not sent via unencrypted email

Physical Security (Domain 5)

  • [ ] Server room/network closet is locked and access-controlled
  • [ ] POS terminals are in areas with staff supervision
  • [ ] Visitor access to network-connected areas is controlled
  • [ ] Network ports in public areas are disabled or locked
  • [ ] POS terminals and card readers are inspected monthly for tampering
  • [ ] Security cameras cover entry points and sensitive areas
  • [ ] Computer screens are not visible to unauthorized persons
  • [ ] Paper documents with sensitive data are secured or shredded

Policies and Documentation (Domain 6)

  • [ ] Written information security policy exists and is approved
  • [ ] Incident response plan is documented and has been tested
  • [ ] Acceptable use policy exists and employees have signed it
  • [ ] Security roles and responsibilities are documented
  • [ ] Vendor/service provider security is verified annually
  • [ ] Change management process exists for system modifications
  • [ ] Asset inventory is maintained and current
  • [ ] Risk assessment has been completed within the last 12 months

Human Factors (Domain 7)

  • [ ] Security awareness training completed by all staff within last 12 months
  • [ ] Phishing simulation conducted within last 90 days
  • [ ] Employees know how to report suspicious emails or incidents
  • [ ] New hire security onboarding is part of the hiring process
  • [ ] Clean desk policy is in place for areas with sensitive data
  • [ ] Temporary/seasonal staff receive abbreviated security training
  • [ ] Social engineering awareness is part of training curriculum

That is 65 items across seven domains. If you score each as 0 (FAIL), 0.5 (PARTIAL), or 1 (PASS), you get a score out of 65. In my experience, most small businesses score between 15 and 30 on their first audit — and that is completely normal. The goal is not perfection on day one. The goal is consistent improvement quarter over quarter.

PowerShell Network Scanner: Find Everything on Your Network

The first technical script discovers every device on your local network. This is critical because you cannot secure what you do not know exists. I have walked into businesses with thirty-plus devices on their network, and when I asked the owner how many devices they had, the answer was “maybe ten.”

<#
.SYNOPSIS
    Network Device Discovery Scanner
.DESCRIPTION
    Scans your local network subnet for active devices, identifies
    open common ports, and reports findings for security audit.
.NOTES
    Version: 1.0 | PowerShell 5.1+ | Run as: Administrator
    Note: Scan takes 3-10 minutes depending on subnet size.
#>

param(
    [string]$Subnet = "",  # Auto-detect if empty
    [int]$TimeoutMs = 100
)

# Auto-detect subnet from primary network adapter
if (-not $Subnet) {
    $adapter = Get-NetIPAddress -AddressFamily IPv4 |
        Where-Object { $_.InterfaceAlias -notmatch "Loopback" -and $_.PrefixOrigin -eq "Dhcp" } |
        Select-Object -First 1
    if ($adapter) {
        $octets = $adapter.IPAddress.Split('.')
        $Subnet = "$($octets[0]).$($octets[1]).$($octets[2])"
        Write-Host "Auto-detected subnet: $Subnet.0/24" -ForegroundColor Cyan
    } else {
        Write-Host "Could not auto-detect subnet. Specify with -Subnet parameter." -ForegroundColor Red
        exit
    }
}

Write-Host "`n======================================" -ForegroundColor Green
Write-Host "  Network Device Discovery Scanner" -ForegroundColor Green
Write-Host "======================================" -ForegroundColor Green
Write-Host "Scanning $Subnet.1 through $Subnet.254..." -ForegroundColor Yellow
Write-Host "This may take several minutes.`n" -ForegroundColor Yellow

# Common ports to check on discovered hosts
$portsToCheck = @(
    @{ Port = 22;    Service = "SSH" },
    @{ Port = 80;    Service = "HTTP" },
    @{ Port = 443;   Service = "HTTPS" },
    @{ Port = 445;   Service = "SMB/File Sharing" },
    @{ Port = 3389;  Service = "RDP (Remote Desktop)" },
    @{ Port = 8080;  Service = "HTTP Alt/Admin Panel" },
    @{ Port = 3306;  Service = "MySQL" },
    @{ Port = 5432;  Service = "PostgreSQL" },
    @{ Port = 1433;  Service = "SQL Server" },
    @{ Port = 21;    Service = "FTP" }
)

$devices = @()
$riskyFindings = @()

# Ping sweep
$jobs = 1..254 | ForEach-Object {
    $ip = "$Subnet.$_"
    [PSCustomObject]@{
        IP   = $ip
        Ping = Test-Connection -ComputerName $ip -Count 1 -Quiet -TimeoutSeconds 1 -ErrorAction SilentlyContinue
    }
}

$aliveHosts = $jobs | Where-Object { $_.Ping }
Write-Host "Found $($aliveHosts.Count) active hosts. Scanning ports...`n" -ForegroundColor Cyan

foreach ($host_ in $aliveHosts) {
    $ip = $host_.IP
    $openPorts = @()

    foreach ($portInfo in $portsToCheck) {
        $tcp = New-Object System.Net.Sockets.TcpClient
        try {
            $result = $tcp.BeginConnect($ip, $portInfo.Port, $null, $null)
            $wait = $result.AsyncWaitHandle.WaitOne($TimeoutMs)
            if ($wait -and $tcp.Connected) {
                $openPorts += "$($portInfo.Port)/$($portInfo.Service)"

                # Flag risky open ports
                if ($portInfo.Port -in @(3389, 21, 3306, 5432, 1433, 445)) {
                    $riskyFindings += [PSCustomObject]@{
                        IP      = $ip
                        Port    = $portInfo.Port
                        Service = $portInfo.Service
                        Risk    = "Sensitive service exposed on network"
                        Action  = "Verify this is authorized and properly secured"
                    }
                }
            }
        } catch {} finally {
            $tcp.Close()
        }
    }

    # Try to resolve hostname
    $hostname = try {
        [System.Net.Dns]::GetHostEntry($ip).HostName
    } catch { "Unknown" }

    # Get MAC address from ARP cache
    $arpEntry = arp -a $ip 2>$null | Select-String $ip
    $mac = if ($arpEntry) {
        ($arpEntry.ToString().Trim() -split '\s+')[1]
    } else { "N/A" }

    $devices += [PSCustomObject]@{
        IP        = $ip
        Hostname  = $hostname
        MAC       = $mac
        OpenPorts = ($openPorts -join " | ")
        PortCount = $openPorts.Count
    }
}

# Display results
Write-Host "======================================" -ForegroundColor Green
Write-Host "  DEVICE INVENTORY" -ForegroundColor Green
Write-Host "======================================`n" -ForegroundColor Green

$devices | Sort-Object IP | Format-Table IP, Hostname, MAC, PortCount, OpenPorts -AutoSize -Wrap

if ($riskyFindings.Count -gt 0) {
    Write-Host "`n======================================" -ForegroundColor Red
    Write-Host "  SECURITY CONCERNS" -ForegroundColor Red
    Write-Host "======================================`n" -ForegroundColor Red
    $riskyFindings | Format-Table IP, Port, Service, Risk -AutoSize -Wrap
}

Write-Host "`nSummary:" -ForegroundColor Cyan
Write-Host "  Total active devices: $($devices.Count)"
Write-Host "  Devices with risky ports: $($riskyFindings | Select-Object -Unique IP | Measure-Object).Count"
Write-Host "  Unknown hostnames: $(($devices | Where-Object { $_.Hostname -eq 'Unknown' }).Count)"

# Export
$devices | Export-Csv ".\Network-Scan-$(Get-Date -Format 'yyyy-MM-dd').csv" -NoTypeInformation
$riskyFindings | Export-Csv ".\Network-Risks-$(Get-Date -Format 'yyyy-MM-dd').csv" -NoTypeInformation
Write-Host "`nReports saved to current directory." -ForegroundColor Green

Here is what this script does and why each part matters:

Subnet auto-detection. The script automatically figures out your network range by looking at your active network adapter. If your machine’s IP is 192.168.1.50, it scans 192.168.1.1 through 192.168.1.254. You can override this with the -Subnet parameter if you have multiple subnets.

Ping sweep. First pass identifies which IP addresses have an active device. This is your device inventory — and comparing it to what you think is on your network often reveals surprises. Printers you forgot about. An old laptop plugged into a conference room port. A personal device someone connected to the business Wi-Fi.

Port scanning. For every live device, the script checks ten common service ports. The important ones to watch for:

  • Port 3389 (RDP) — Remote Desktop Protocol. If this is open on any machine, that machine is accessible for remote login. RDP is one of the most commonly exploited services in ransomware attacks. If it is open and you did not intend it to be, that is a critical finding.
  • Port 445 (SMB) — File sharing. This is normal on machines that share files or printers, but if it is open on a device that should not be sharing anything, investigate.
  • Port 21 (FTP) — File Transfer Protocol. FTP transmits credentials in plain text. If this is running anywhere on your network in 2026, replace it with SFTP immediately.
  • Port 3306/5432/1433 (Database ports) — MySQL, PostgreSQL, or SQL Server. If a database port is exposed on your network, that database should be configured to only accept connections from authorized hosts.

Risk flagging. The script automatically flags sensitive services that are exposed and generates a separate risk report. Each flagged item includes the IP, port, service name, and recommended action.

Hostname resolution and MAC address lookup. The script attempts to identify each device by resolving its hostname and pulling its MAC address from the ARP cache. The MAC address can help you identify the device manufacturer — useful for figuring out what that mystery device at 192.168.1.47 actually is.

Run this script quarterly. Compare the results to your previous scan. Any new device that appears should be investigated and authorized. Any device that disappears should be accounted for.

PowerShell Firewall Audit Script

The network scanner shows you what is on your network. This next script audits the firewall on each Windows machine to ensure it is properly configured:

<#
.SYNOPSIS
    Windows Firewall Security Audit
.DESCRIPTION
    Comprehensive firewall configuration audit including profile
    status, risky rules, and inbound exposure analysis.
.NOTES
    Version: 1.0 | PowerShell 5.1+ | Run as: Administrator
#>

Write-Host "`n======================================" -ForegroundColor Green
Write-Host "  Firewall Security Audit" -ForegroundColor Green
Write-Host "======================================`n" -ForegroundColor Green

$findings = @()

# --- Profile Status ---
Write-Host "[1/4] Checking firewall profiles..." -ForegroundColor Yellow
$profiles = Get-NetFirewallProfile

foreach ($profile in $profiles) {
    $status = if ($profile.Enabled) { "PASS - Enabled" } else { "CRITICAL - DISABLED" }
    $findings += [PSCustomObject]@{
        Category = "Profile Status"
        Item     = "$($profile.Name) Profile"
        Status   = $status
        Risk     = if (-not $profile.Enabled) { "HIGH" } else { "NONE" }
        Detail   = "Default Inbound: $($profile.DefaultInboundAction) | Default Outbound: $($profile.DefaultOutboundAction)"
    }

    # Check if default inbound action is Allow (should be Block)
    if ($profile.DefaultInboundAction -eq "Allow") {
        $findings += [PSCustomObject]@{
            Category = "Profile Config"
            Item     = "$($profile.Name) - Default Inbound Action"
            Status   = "FAIL - Default ALLOW"
            Risk     = "HIGH"
            Detail   = "Default inbound should be Block, not Allow"
        }
    }
}

# --- Risky Inbound Rules ---
Write-Host "[2/4] Analyzing inbound rules..." -ForegroundColor Yellow

$inboundRules = Get-NetFirewallRule -Direction Inbound -Enabled True -ErrorAction SilentlyContinue

# Find rules that allow all traffic or use broad ports
$riskyRules = @()
foreach ($rule in $inboundRules) {
    $portFilter = $rule | Get-NetFirewallPortFilter -ErrorAction SilentlyContinue
    $addressFilter = $rule | Get-NetFirewallAddressFilter -ErrorAction SilentlyContinue

    $isRisky = $false
    $riskReason = ""

    # Check for "any" port rules
    if ($portFilter.LocalPort -eq "Any" -and $rule.Action -eq "Allow") {
        $isRisky = $true
        $riskReason = "Allows ALL inbound ports"
    }

    # Check for "any" remote address with specific risky ports
    if ($addressFilter.RemoteAddress -eq "Any" -and
        $portFilter.LocalPort -in @("3389", "445", "22", "21", "1433", "3306")) {
        $isRisky = $true
        $riskReason = "Risky port ($($portFilter.LocalPort)) open to ANY source"
    }

    if ($isRisky) {
        $riskyRules += [PSCustomObject]@{
            RuleName   = $rule.DisplayName
            Port       = $portFilter.LocalPort
            Protocol   = $portFilter.Protocol
            RemoteAddr = $addressFilter.RemoteAddress
            Reason     = $riskReason
        }

        $findings += [PSCustomObject]@{
            Category = "Inbound Rules"
            Item     = $rule.DisplayName
            Status   = "REVIEW - Potentially risky"
            Risk     = "MEDIUM-HIGH"
            Detail   = $riskReason
        }
    }
}

Write-Host "  Found $($inboundRules.Count) enabled inbound rules" -ForegroundColor Cyan
Write-Host "  Flagged $($riskyRules.Count) as potentially risky`n" -ForegroundColor $(if ($riskyRules.Count -gt 0) { 'Yellow' } else { 'Green' })

# --- Logging Configuration ---
Write-Host "[3/4] Checking firewall logging..." -ForegroundColor Yellow

foreach ($profile in $profiles) {
    $logAllowed = $profile.LogAllowed
    $logBlocked = $profile.LogBlocked
    $logFile = $profile.LogFileName
    $logMaxSize = $profile.LogMaxSizeKilobytes

    $findings += [PSCustomObject]@{
        Category = "Logging"
        Item     = "$($profile.Name) - Log Blocked Connections"
        Status   = if ($logBlocked -eq "True") { "PASS" } else { "FAIL - Not logging blocked traffic" }
        Risk     = if ($logBlocked -ne "True") { "MEDIUM" } else { "NONE" }
        Detail   = "Log file: $logFile | Max size: ${logMaxSize}KB"
    }
}

# --- IPsec and Connection Security ---
Write-Host "[4/4] Checking connection security rules..." -ForegroundColor Yellow

$ipsecRules = Get-NetIPsecRule -ErrorAction SilentlyContinue
$findings += [PSCustomObject]@{
    Category = "IPsec"
    Item     = "Connection Security Rules"
    Status   = if ($ipsecRules) { "INFO - $($ipsecRules.Count) rules configured" } else { "INFO - No IPsec rules (normal for most small businesses)" }
    Risk     = "LOW"
    Detail   = "IPsec rules provide additional network-layer security"
}

# --- Results ---
Write-Host "`n======================================" -ForegroundColor Green
Write-Host "  FIREWALL AUDIT RESULTS" -ForegroundColor Green
Write-Host "======================================`n" -ForegroundColor Green

$criticalCount = ($findings | Where-Object { $_.Risk -eq "HIGH" }).Count
$mediumCount = ($findings | Where-Object { $_.Risk -match "MEDIUM" }).Count
$passCount = ($findings | Where-Object { $_.Status -match "^PASS" }).Count

Write-Host "PASS:     $passCount" -ForegroundColor Green
Write-Host "CRITICAL: $criticalCount" -ForegroundColor $(if ($criticalCount -gt 0) { 'Red' } else { 'Green' })
Write-Host "MEDIUM:   $mediumCount" -ForegroundColor $(if ($mediumCount -gt 0) { 'Yellow' } else { 'Green' })

$findings | Format-Table Category, Item, Status, Risk -AutoSize -Wrap

if ($riskyRules.Count -gt 0) {
    Write-Host "`nRISKY INBOUND RULES (review these):" -ForegroundColor Red
    $riskyRules | Format-Table RuleName, Port, Protocol, RemoteAddr, Reason -AutoSize -Wrap
}

# Export
$findings | Export-Csv ".\Firewall-Audit-$(Get-Date -Format 'yyyy-MM-dd').csv" -NoTypeInformation
Write-Host "`nReport saved to: .\Firewall-Audit-$(Get-Date -Format 'yyyy-MM-dd').csv" -ForegroundColor Green

Let me walk through the key checks and why they matter:

Profile status. Windows has three firewall profiles: Domain (when connected to a corporate domain), Private (trusted networks like your office), and Public (untrusted networks). All three must be enabled. I regularly find businesses where the Domain profile is enabled but Private and Public are disabled — meaning the firewall only works when the machine is on the office network. Take that laptop to a coffee shop and the firewall is off.

Default inbound action. Each profile has a default action for inbound traffic: Block or Allow. The correct setting is Block. If any profile defaults to Allow, every port on that machine is open to the network unless a specific rule blocks it. That is backwards security — you want everything blocked by default, with specific exceptions for things you need.

Risky inbound rules. The script scans all enabled inbound allow rules and flags two patterns: rules that allow all ports (essentially turning off the firewall for that rule), and rules that expose sensitive ports (RDP, SMB, FTP, database ports) to any source address. A rule that says “allow RDP from 192.168.1.50” is targeted and probably intentional. A rule that says “allow RDP from any address” is a ransomware invitation.

Logging configuration. Your firewall should log blocked connections. These logs are how you detect port scanning, brute force attempts, and reconnaissance by attackers. If blocked connection logging is disabled, you are flying blind — attacks are happening and you have no record of them.

Run this on every Windows machine in your business. The machines with the most CRITICAL and MEDIUM findings are your highest priority for remediation.

How to Run Your Quarterly Audit (Step by Step)

Now that you have the checklist and the scripts, here is the process. Block two hours on your calendar. Do this every quarter. Treat it like a doctor’s appointment — not optional.

Hour 1: Technical Scan (30 minutes setup, 30 minutes review)

  1. Run the Network Scanner from any machine on your network. While it scans, review the device list against your asset inventory. Flag any device you do not recognize.
  2. Run the Firewall Audit on each Windows workstation and server. If you have more than five machines, prioritize the ones that handle sensitive data — your POS system, your accounting workstation, your file server.
  3. Export all CSV reports to a dated folder: Security-Audit-2026-Q2/. Keeping historical reports lets you track improvement over time.

Hour 2: Checklist Walk-Through (60 minutes)

  1. Open the 65-item checklist. Work through it domain by domain with a colleague if possible — a second set of eyes catches things you have normalized.
  2. Score each item as PASS (1), PARTIAL (0.5), or FAIL (0).
  3. Tally your score. Calculate your percentage: (score / 65) * 100.
  4. Identify the top five most critical FAIL items. These become your action items for the next quarter.
  5. Create a one-page audit summary with your score, critical findings, and remediation plan.

After the Audit:

  1. Address critical findings within 2 weeks. Not 2 months. 2 weeks.
  2. Address medium findings within 30 days.
  3. Schedule the next quarterly audit.
  4. File the audit report. These documents prove due diligence if you ever face a breach investigation, an insurance claim, or a compliance audit.

Scoring Guide: What Your Numbers Mean

0-20 out of 65 (0-30%): Critical risk. Your business has significant security gaps that could be exploited today. Prioritize MFA, firewall configuration, and backup verification immediately. Consider engaging professional help to accelerate remediation.

21-35 out of 65 (31-54%): High risk. You have some basics in place but major gaps remain. Focus on the FAIL items in your highest-risk domains (usually Access Control and Data Protection). This is where most small businesses land on their first audit.

36-50 out of 65 (55-77%): Moderate risk. Good foundation with room for improvement. Your technical controls are probably reasonable but your policies and documentation likely have gaps. Start formalizing your security policies.

51-60 out of 65 (78-92%): Low risk. Solid security posture for a small business. Focus on the PARTIAL items to reach full compliance and consider advanced controls like SIEM, endpoint detection and response (EDR), or security awareness testing.

61-65 out of 65 (93-100%): Strong. Excellent. You are ahead of most businesses regardless of size. Maintain this level through regular audits and stay current with emerging threats.

The single most important metric is not your absolute score. It is your trend. Going from 22 to 35 in one quarter is an excellent result. Staying at 35 for three quarters in a row means you have stopped improving and need to refocus.

Common Audit Findings (And How to Fix Them)

Here are the issues I find most frequently when auditing small businesses across Volusia County, along with the fix for each:

Finding: Guest Wi-Fi on the same network as business systems.
Fix: Enable VLAN segmentation on your router. Most business-grade routers (Ubiquiti, Meraki, FortiGate) support VLANs. Create a separate VLAN for guest traffic with no access to business resources. If your router does not support VLANs, set up a physically separate access point connected to a different network segment.

Finding: Ex-employee accounts still active.
Fix: Implement an offboarding checklist that includes account deactivation within 24 hours of departure. Our guide on automating employee offboarding covers this in detail. For immediate remediation, audit your user accounts right now and disable any that belong to people who no longer work for you.

Finding: No backup testing.
Fix: This quarter, restore three random files from your backup. Verify they are intact and current. If the restore fails, your backup is broken and you need to fix it before the next ransomware attack decides to test it for you.

Finding: RDP exposed to the internet.
Fix: Disable direct RDP access immediately. If you need remote access, use a VPN or a zero-trust access solution like Cloudflare Access or Tailscale (both have free tiers). RDP exposed to the internet is the number one way ransomware enters small business networks.

Finding: No firewall logging.
Fix: Enable logging for blocked connections on all firewall profiles. In PowerShell: Set-NetFirewallProfile -All -LogBlocked True -LogMaxSizeKilobytes 32768. This takes thirty seconds and gives you visibility into who is trying to reach your network.

Finding: No written security policy.
Fix: You do not need a 50-page document. Start with a two-page document covering: who is responsible for security, how passwords are managed, how data is backed up, what happens when someone leaves, and what to do if you suspect a breach. That is a legitimate security policy for a small business, and it is infinitely better than having nothing.

Automating Your Audit Cadence

The audit itself is manual, but you can automate reminders and some of the recurring technical checks. Here is a lightweight approach:

Weekly automated checks: Schedule the firewall audit script to run every Monday morning via Windows Task Scheduler and email you the results. Any regression from your last quarterly audit shows up immediately.

Monthly network scan: Schedule the network discovery script to run on the first of each month. Compare the device list to the previous month. New devices get investigated.

Quarterly full audit: Block the two-hour audit on your calendar a year in advance. Put it on the same day each quarter so it becomes routine.

For the human-element portions of the checklist, a quarterly phishing simulation keeps your team sharp. Our guide on automating phishing training with n8n shows you how to set up automated phishing tests at no cost.

When to Bring In a Professional

The DIY audit covers 80-90% of what most small businesses need. Here are the situations where professional help makes sense:

You handle regulated data. If you are subject to PCI DSS, HIPAA, or SOC 2 requirements, a professional assessment can identify compliance gaps that a self-audit might miss. The stakes for non-compliance are too high to rely solely on self-assessment.

Your audit score is not improving. If you have done three quarterly audits and your score has plateaued, a fresh set of professional eyes can identify blind spots and recommend a prioritized remediation plan.

You have suffered an incident. Post-incident audits require forensic skills and an understanding of attacker methodologies that go beyond checklist-based assessment.

You are growing rapidly. Adding locations, employees, or systems changes your attack surface faster than quarterly audits can track. A professional can help you scale your security posture alongside your business.

For businesses in Ormond Beach and across Volusia County, our security services include professional security assessments that build on the DIY foundation covered in this guide. We also provide IT consulting in Ormond Beach covering security, infrastructure, and compliance.

The Bottom Line

The best time to run a security audit was last quarter. The second best time is today. The checklist and scripts in this guide take about two hours to run and will show you exactly where your business stands. Most of the vulnerabilities that lead to real breaches are basic gaps that a structured audit catches months before an attacker finds them.

Frequently Asked Questions

How long does a small business security audit take?

A self-audit using the checklist and scripts in this guide takes approximately two hours per quarter. The technical scans (network discovery and firewall audit) run for 10-30 minutes each. The manual checklist walk-through takes about 60 minutes. A professional audit typically takes 1-3 days depending on business size and complexity.

How often should a small business conduct a security audit?

Quarterly is the recommended cadence for the full checklist audit. Weekly automated technical scans (firewall status) and monthly network discovery scans supplement the quarterly review. Annual professional assessments are recommended for businesses handling regulated data or with more than 50 employees.

What is the most common security gap found in small business audits?

Stale user accounts — employees who have left but whose accounts remain active. This appears in nearly every small business audit I conduct. The second most common finding is lack of MFA on email accounts, followed by untested backups.

Can I use these scripts on a Mac or Linux network?

The PowerShell scripts are Windows-specific. For Mac environments, use the built-in nmap command for network scanning and review System Preferences > Security & Privacy for endpoint checks. For Linux, nmap and ufw (Uncomplicated Firewall) or iptables provide equivalent functionality. The checklist itself is platform-agnostic.

Do I need special tools beyond what is included here?

For the DIY audit, no. The PowerShell scripts and checklist cover the essentials. If you want to go deeper, free tools like Nmap (network scanning), CIS Benchmarks (system hardening guides), and Wazuh (open-source SIEM) can enhance your audit capabilities without additional cost.

What should I do if I find a critical vulnerability during the audit?

Address it immediately — do not wait until the end of the quarter. Disconnect affected systems from the network if necessary, remediate the vulnerability, verify the fix, and document what you found and what you did. If the vulnerability involves active exploitation or data exposure, engage professional incident response help.

Free Discovery Call

Start With a Conversation, Not a Commitment

Every engagement begins with a free 30-minute discovery call. We'll map what's slowing your business down and tell you exactly what we'd fix first – no pitch deck, no obligation.