Back to All Modules

Windows Discovery with PowerShell

#Paste-Ready Native Discovery Script

This script accepts explicit IP addresses or hostnames. It performs bounded TCP connection checks, DNS resolution, HTTP header collection, printer-service discovery, and local wireless inventory without downloading tools or changing system configuration.

param(
    [Parameter(Mandatory)]
    [ValidateScript({ Test-Path -LiteralPath $_ -PathType Leaf })]
    [string]$TargetsFile,

    [int[]]$Ports = @(53, 80, 88, 135, 139, 389, 443, 445, 515, 631, 9100),

    [ValidateRange(100, 10000)]
    [int]$TimeoutMs = 1500,

    [string]$OutputRoot = (Join-Path $PWD "windows-discovery")
)

$ErrorActionPreference = "Stop"
$stamp = (Get-Date).ToUniversalTime().ToString("yyyyMMddTHHmmssZ")
$output = Join-Path $OutputRoot $stamp
New-Item -ItemType Directory -Path $output -Force | Out-Null

$targets = Get-Content -LiteralPath $TargetsFile |
    ForEach-Object { ($_ -split '#', 2)[0].Trim() } |
    Where-Object { $_ } |
    Sort-Object -Unique

if (-not $targets) {
    throw "No explicit targets were supplied."
}

$results = foreach ($target in $targets) {
    $addresses = try {
        [System.Net.Dns]::GetHostAddresses($target).IPAddressToString -join ","
    } catch {
        ""
    }

    foreach ($port in $Ports) {
        $client = [System.Net.Sockets.TcpClient]::new()
        try {
            $task = $client.ConnectAsync($target, $port)
            $open = $task.Wait($TimeoutMs) -and $client.Connected
            [pscustomobject]@{
                Target    = $target
                Addresses = $addresses
                Port      = $port
                Open      = $open
                CheckedAt = (Get-Date).ToUniversalTime().ToString("o")
            }
        } finally {
            $client.Dispose()
        }
    }
}

$results | Export-Csv -NoTypeInformation -LiteralPath (Join-Path $output "tcp-services.csv")
$results | Where-Object { $_.Open -and $_.Port -in 80,443 } | ForEach-Object {
    $scheme = if ($_.Port -eq 443) { "https" } else { "http" }
    $uri = "${scheme}://$($_.Target):$($_.Port)/"
    try {
        $request = @{
            Uri        = $uri
            Method     = "Head"
            TimeoutSec = 5
        }
        if ($PSVersionTable.PSVersion.Major -ge 7) {
            $request.SkipCertificateCheck = $true
        }
        $response = Invoke-WebRequest @request
        [pscustomobject]@{
            Uri        = $uri
            StatusCode = [int]$response.StatusCode
            Server     = $response.Headers.Server
        }
    } catch {
        [pscustomobject]@{ Uri = $uri; StatusCode = ""; Server = ""; Error = $_.Exception.Message }
    }
} | Export-Csv -NoTypeInformation -LiteralPath (Join-Path $output "http-head.csv")

Get-Printer -ErrorAction SilentlyContinue |
    Select-Object Name, ComputerName, PortName, DriverName, Type, Shared |
    Export-Csv -NoTypeInformation -LiteralPath (Join-Path $output "local-printers.csv")

netsh wlan show interfaces | Out-File -LiteralPath (Join-Path $output "wireless-interfaces.txt")
netsh wlan show networks mode=bssid | Out-File -LiteralPath (Join-Path $output "wireless-networks.txt")

Get-ChildItem -LiteralPath $output -File |
    Get-FileHash -Algorithm SHA256 |
    Export-Csv -NoTypeInformation -LiteralPath (Join-Path $output "manifest.csv")

Write-Host "Discovery output: $output"
POWERSHELL

On PowerShell 5.1, certificate failures are recorded rather than bypassed. PowerShell 7 can collect headers from devices with self-signed certificates without changing global certificate validation.