Loading...
Development

Windows Shell Scripting: Complete Guide from Basic to Advanced

Windows Shell Scripting: Complete Guide from Basic to Advanced

Master CMD, PowerShell & WSL Bash for Windows Automation & Security


OVERVIEW: Windows Shell Options

ShellUse CaseLearning Curve
CMDLegacy batch files, simple automationEasy
PowerShellModern, object-oriented, security-focusedMedium
WSL BashLinux-like scripting on WindowsMedium (if know Linux)

Recommendation: Start with PowerShell (built-in, powerful). Use WSL for Linux tools.


SECTION 1: CMD BATCH SCRIPTING (BASIC)


1.1 Hello World Batch File

@echo off
echo Hello, Windows World!
pause

Save as: hello.bat → Double-click to run.


1.2 Variables & User Input

@echo off
set /p name=Enter your name: 
echo Hello, %name%!
if "%name%"=="admin" (
    echo Welcome, Administrator!
) else (
    echo Hello, User!
)
pause

1.3 Loops & Conditions

@echo off
echo Counting 1-5:
for /l %%i in (1,1,5) do (
    echo %%i
)

echo Check if file exists:
if exist C:\Windows\system32\notepad.exe (
    echo Notepad found!
) else (
    echo Notepad missing!
)
pause

1.4 File Operations

@echo off
echo Creating backup...
mkdir C:\backup 2>nul
copy C:\important.txt C:\backup\ 2>nul
echo Backup complete!
dir C:\backup
pause

SECTION 2: POWERSELL (INTERMEDIATE)


2.1 Basic PowerShell Script

# hello.ps1
Write-Host "Hello, PowerShell!" -ForegroundColor Green
$username = Read-Host "Enter username"
Write-Host "Welcome, $username!" -ForegroundColor Yellow

Run: powershell -ExecutionPolicy Bypass -File hello.ps1


2.2 Variables, Arrays & Hashtables

# data_types.ps1
$ip = "192.168.1.1"
$ports = @(80, 443, 22)
$services = @{
    "80" = "HTTP"
    "443" = "HTTPS"
    "22" = "SSH"
}

Write-Host "Scanning $ip on ports: $ports"
foreach ($port in $ports) {
    Write-Host "Port $port : $($services[$port])"
}

2.3 Functions & Parameters

# functions.ps1
function Test-Port {
    param(
        [string]$ComputerName,
        [int]$Port
    )
    $tcp = New-Object System.Net.Sockets.TcpClient
    try {
        $tcp.Connect($ComputerName, $Port)
        Write-Host "$ComputerName`:$Port OPEN" -ForegroundColor Green
        $tcp.Close()
        return $true
    } catch {
        Write-Host "$ComputerName`:$Port CLOSED" -ForegroundColor Red
        return $false
    }
}

# Usage
Test-Port -ComputerName "localhost" -Port 80

2.4 Error Handling & Logging

# error_handling.ps1
try {
    $result = Get-Process -Name "nonexistent" -ErrorAction Stop
} catch {
    Write-Warning "Process not found: $($_.Exception.Message)"
    Add-Content -Path "C:\logs\errors.log" -Value "$(Get-Date): $($_.Exception.Message)"
}

# Continue script
Write-Host "Script continues..." -ForegroundColor Cyan

SECTION 3: ADVANCED POWERSHELL (SECURITY-FOCUSED)


3.1 System Reconnaissance

# recon.ps1
Write-Host "=== Windows System Recon ===" -ForegroundColor Magenta

# Basic info
$os = Get-CimInstance Win32_OperatingSystem
$cpu = Get-CimInstance Win32_Processor
$hostname = $env:COMPUTERNAME

Write-Host "Hostname: $hostname" -ForegroundColor Yellow
Write-Host "OS: $($os.Caption)" -ForegroundColor Yellow
Write-Host "CPU: $($cpu.Name)" -ForegroundColor Yellow

# Network adapters
Get-NetAdapter | Where-Object {$_.Status -eq "Up"} | Select Name, InterfaceDescription, LinkSpeed

# Running services (suspicious)
Get-Service | Where-Object {$_.Status -eq "Running" -and $_.StartType -eq "Manual"} | 
    Select Name, DisplayName | Format-Table

3.2 Network Scanning & Discovery

# network_scan.ps1
function Scan-Network {
    param([string]$Network = "192.168.1.0/24")
    
    Write-Host "Scanning $Network..." -ForegroundColor Cyan
    
    $ips = 1..254 | ForEach-Object { "192.168.1.$_" }
    $results = @()
    
    foreach ($ip in $ips) {
        if (Test-Connection -ComputerName $ip -Count 1 -Quiet -ErrorAction SilentlyContinue) {
            $results += [PSCustomObject]@{
                IP = $ip
                Status = "UP"
                Timestamp = Get-Date
            }
            Write-Host "$ip is UP" -ForegroundColor Green
        }
    }
    
    return $results
}

# Usage
$liveHosts = Scan-Network
$liveHosts | Export-Csv -Path "C:\scans\network_scan.csv" -NoTypeInformation

3.3 Event Log Analysis

# event_analysis.ps1
Write-Host "=== Security Event Analysis ===" -ForegroundColor Magenta

# Failed logins (Event ID 4625)
$failedLogins = Get-WinEvent -FilterHashtable @{
    LogName = 'Security'
    ID = 4625
} -MaxEvents 50 -ErrorAction SilentlyContinue

if ($failedLogins) {
    $failedLogins | Select-Object TimeCreated, Id, LevelDisplayName, @{Name="Message";Expression={$_.Message -replace "`n"," " -replace "`r"," "}} | 
        Format-Table -Wrap
} else {
    Write-Host "No recent failed logins found" -ForegroundColor Yellow
}

# Export to JSON
$failedLogins | ConvertTo-Json | Out-File "C:\logs\failed_logins.json"

3.4 File System Auditing

# file_audit.ps1
$targetPath = "C:\Users"
$auditReport = @()

Write-Host "Auditing $targetPath..." -ForegroundColor Cyan

Get-ChildItem -Path $targetPath -Recurse -File -ErrorAction SilentlyContinue | 
    ForEach-Object {
        $file = $_
        $acl = Get-Acl $file.FullName
        
        $auditReport += [PSCustomObject]@{
            Path = $file.FullName
            Size = $file.Length
            Modified = $file.LastWriteTime
            Owner = $acl.Owner
            Access = ($acl.Access | Select-Object -First 1).FileSystemRights
        }
    }

$auditReport | Export-Csv -Path "C:\audits\file_system_audit.csv" -NoTypeInformation
Write-Host "Audit complete. Report saved." -ForegroundColor Green

3.5 Active Directory Enumeration

# ad_enum.ps1
# Requires RSAT tools or domain context

Import-Module ActiveDirectory -ErrorAction SilentlyContinue

if (Get-Module -ListAvailable -Name ActiveDirectory) {
    Write-Host "=== AD Enumeration ===" -ForegroundColor Magenta
    
    # Domain users with passwords not expiring
    Get-ADUser -Filter {PasswordNeverExpires -eq $true -and Enabled -eq $true} | 
        Select Name, SamAccountName, LastLogonDate | 
        Format-Table
    
    # Domain admins
    Get-ADGroupMember -Identity "Domain Admins" -Recursive | 
        Select Name, SamAccountName, DistinguishedName
} else {
    Write-Warning "ActiveDirectory module not available. Install RSAT."
}

SECTION 4: WSL BASH ON WINDOWS (ADVANCED)


4.1 Setup WSL + Kali

# Enable WSL
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# Install WSL2
wsl --set-default-version 2
wsl --install -d kali-linux

# Update Kali
wsl -d kali-linux
sudo apt update && sudo apt upgrade -y

4.2 Hybrid PowerShell + WSL Script

# hybrid_scan.ps1
$target = "192.168.1.100"

Write-Host "Windows recon + WSL nmap..." -ForegroundColor Cyan

# Windows: Check connectivity
if (Test-Connection -ComputerName $target -Count 1 -Quiet) {
    Write-Host "$target is reachable from Windows" -ForegroundColor Green
    
    # WSL: Run nmap
    $nmapResult = wsl -d kali-linux nmap -sV -p 22,80,443 $target
    
    Write-Host "`nNmap Results:" -ForegroundColor Yellow
    Write-Host $nmapResult
} else {
    Write-Host "$target is not reachable" -ForegroundColor Red
}

4.3 WSL Bash Network Scanner

#!/bin/bash
# save as: scan.sh in WSL Kali

target=$1
if [ -z "$target" ]; then
    echo "Usage: ./scan.sh <IP>"
    exit 1
fi

echo "=== WSL Kali Scan on $target ==="
sudo nmap -sC -sV -p- $target -oN scan_$(date +%F).txt

# Parse results
echo "`nOpen ports:"
grep "open" scan_$(date +%F).txt

# Quick web recon
if sudo nmap -p 80,443 $target | grep -q "open"; then
    echo "`nWeb enumeration:"
    curl -I http://$target 2>/dev/null || echo "HTTP failed"
    curl -I https://$target 2>/dev/null || echo "HTTPS failed"
fi

Run from PowerShell: wsl -d kali-linux /path/to/scan.sh 192.168.1.100


SECTION 5: SECURITY-SPECIFIC SCRIPTS


5.1 Windows Defender Quick Scan

# defender_scan.ps1
Write-Host "Running Windows Defender Quick Scan..." -ForegroundColor Cyan

$scanResult = Start-MpScan -ScanType QuickScan -ErrorAction SilentlyContinue

if ($scanResult) {
    Write-Host "Scan completed. Checking threats..." -ForegroundColor Yellow
    Get-MpThreat | Select-Object ThreatID, ThreatName, SeverityID, ProcessName | 
        Format-Table -AutoSize
} else {
    Write-Host "No threats detected" -ForegroundColor Green
}

5.2 Scheduled Task Auditor

# task_audit.ps1
Write-Host "=== Scheduled Task Audit ===" -ForegroundColor Magenta

Get-ScheduledTask | Where-Object {$_.State -eq "Ready"} | 
    Select TaskName, TaskPath, State, @{Name="Triggers";Expression={$_.Triggers.Count}}, 
           @{Name="Actions";Expression={$_.Actions.Execute}} | 
    Format-Table -AutoSize

# Suspicious tasks (non-Microsoft)
Get-ScheduledTask | Where-Object {$_.Actions.Execute -notlike "*Windows*" -and $_.Actions.Execute -notlike "*Microsoft*"} | 
    Select TaskName, Actions | Format-Table

5.3 USB Device Logger

# usb_monitor.ps1
# Run as scheduled task for monitoring

$logPath = "C:\logs\usb_events.log"
$event = Get-WinEvent -FilterHashtable @{LogName='System'; ID=2003} -MaxEvents 1 -ErrorAction SilentlyContinue

if ($event) {
    $usbInfo = [PSCustomObject]@{
        Timestamp = Get-Date
        DeviceID = $event.Properties[0].Value
        Message = $event.Message
    }
    $usbInfo | Export-Csv -Path $logPath -Append -NoTypeInformation
    Write-Host "USB event logged: $($usbInfo.DeviceID)" -ForegroundColor Yellow
}

SECTION 6: AUTOMATION FRAMEWORKS


6.1 Modular Security Toolkit

# toolkit.ps1
function Show-Menu {
    Clear-Host
    Write-Host "=== Windows Security Toolkit v1.0 ===" -ForegroundColor Magenta
    Write-Host "1. System Reconnaissance"
    Write-Host "2. Network Discovery"
    Write-Host "3. Event Log Analysis"
    Write-Host "4. File System Audit"
    Write-Host "5. Defender Scan"
    Write-Host "6. Exit"
    $choice = Read-Host "Select option"
    return $choice
}

function Run-Recon { .\modules\recon.ps1 }
function Run-Network { .\modules\network.ps1 }
function Run-Events { .\modules\events.ps1 }
function Run-Files { .\modules\files.ps1 }
function Run-Defender { .\modules\defender.ps1 }

do {
    $selection = Show-Menu
    switch ($selection) {
        1 { Run-Recon }
        2 { Run-Network }
        3 { Run-Events }
        4 { Run-Files }
        5 { Run-Defender }
        6 { Write-Host "Goodbye!" -ForegroundColor Green; exit }
        default { Write-Warning "Invalid option" }
    }
    Read-Host "Press Enter to continue"
} while ($selection -ne 6)

6.2 Scheduled Automation

# Create scheduled task for daily recon
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-File C:\scripts\daily_recon.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At "2:00AM"
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries

Register-ScheduledTask -TaskName "DailySecurityRecon" -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Force
Write-Host "Scheduled task created!" -ForegroundColor Green

SECTION 7: BEST PRACTICES & TROUBLESHOOTING


Execution Policies

# Check current policy
Get-ExecutionPolicy -List

# Set for current user (recommended)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# Bypass for single script
powershell -ExecutionPolicy Bypass -File script.ps1

Error Handling Patterns

# Try-Catch-Finally
try {
    # Risky operation
    $result = Invoke-WebRequest -Uri "http://example.com" -ErrorAction Stop
} catch [System.Net.WebException] {
    Write-Error "Network error: $($_.Exception.Message)"
} catch {
    Write-Error "Unexpected error: $($_.Exception.Message)"
} finally {
    Write-Host "Cleanup complete" -ForegroundColor Gray
}

Logging & Output

# Structured logging
function Write-Log {
    param([string]$Message, [string]$Level = "INFO")
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "$timestamp [$Level] $Message"
    Write-Host $logEntry
    Add-Content -Path "C:\logs\app.log" -Value $logEntry
}

# Usage
Write-Log "Scan started" "INFO"
Write-Log "Error occurred" "ERROR"

CHEAT SHEET: COMMON COMMANDS

TaskCMDPowerShellWSL Bash
List FilesdirGet-ChildItem or lsls -la
Copy Filecopy src destCopy-Itemcp src dest
Network Pingping hostTest-Connectionping host
Process ListtasklistGet-Processps aux
Kill Processtaskkill /PID 1234Stop-Process -Id 1234kill 1234
System InfosysteminfoGet-ComputerInfouname -a

LEARNING ROADMAP

WeekFocusScripts to Build
1CMD BasicsHello world, file ops
2PowerShell IntroVariables, functions
3System AdminRecon, process management
4Network SecurityPort scanning, discovery
5Advanced PSAD, events, auditing
6WSL IntegrationHybrid scripts, Linux tools
7AutomationScheduled tasks, toolkits

Want specific expansions?

  • Full security toolkit with modules
  • WSL + PowerShell hybrid examples
  • Active Directory deep dive
  • Malware analysis scripts

Just ask!

Stay Secure. Script Smart. Windows Mastered. 🔒