Bilgisayarınızdaki Hesapların_Sağlık Raporu_

Programlama ve Script dilleri konusunda bilgi paylaşım alanıdır.
Cevapla
Kullanıcı avatarı
TRWE_2012
Zettabyte1
Zettabyte1
Mesajlar: 15611
Kayıt: 25 Eyl 2013, 13:38
cinsiyet: Erkek
Teşekkür etti: 2709 kez
Teşekkür edildi: 5626 kez

Bilgisayarınızdaki Hesapların_Sağlık Raporu_

Mesaj gönderen TRWE_2012 »

KONU ANLATIMI :
Resim
EKRAN GÖRÜNTÜSÜ :
Resim
KOD İÇERİĞİ (Invoke-LocalAccountSecurityAudit.ps1) :

Kod: Tümünü seç

<#
.SYNOPSIS
    Audits local Windows user accounts for security risk indicators and
    optionally disables risky accounts with user confirmation.

.DESCRIPTION
    This script replicates the manual investigation workflow used to analyze
    the VUSR_NOTEBOOK-PC (Visual Studio Analyzer) local account:
      1. Enumerates all local user accounts.
      2. Checks group memberships (Administrators, Users, Remote Desktop Users).
      3. Exports and parses the local User Rights Assignment policy
         (SeInteractiveLogonRight, SeRemoteInteractiveLogonRight,
         SeNetworkLogonRight, SeBatchLogonRight, SeServiceLogonRight).
      4. Checks for services running under each account.
      5. Computes a three-tier risk level (LOW / MEDIUM / HIGH) per account.
      6. Optionally disables accounts, only after explicit user confirmation
         (unless -AutoApprove or -DryRun is specified).

.PARAMETER DryRun
    Runs the full audit and prints what WOULD be done, but never disables
    any account and never prompts for confirmation.

.PARAMETER AutoApprove
    Skips interactive confirmation and automatically disables accounts
    flagged as HIGH risk. MEDIUM risk accounts are still reported only.
    Ignored if -DryRun is specified.

.PARAMETER Silent
    Suppresses console color output and the on-screen table; only the
    CSV report is written. Confirmation prompts still occur unless
    -AutoApprove or -DryRun is also specified.

.PARAMETER LogFolder
    Folder where the CSV audit report is saved. Created if it does not exist.
    Default: Desktop\SecurityAudit

.EXAMPLE
    .\Invoke-LocalAccountSecurityAudit.ps1 -DryRun

.EXAMPLE
    .\Invoke-LocalAccountSecurityAudit.ps1 -AutoApprove -LogFolder "C:\Logs"
#>

param(
    [switch]$DryRun,
    [switch]$AutoApprove,
    [switch]$Silent,
    [string]$LogFolder = "$env:USERPROFILE\Desktop\SecurityAudit"
)

# ---------------------------------------------------------------------------
# Elevation check
# ---------------------------------------------------------------------------
function Test-IsAdmin {
    $currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentIdentity)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

if (-not (Test-IsAdmin)) {
    Write-Host "This script must be run as Administrator. Exiting." -ForegroundColor Red
    Read-Host "`nPress ENTER to exit."
    exit 1
}

# ---------------------------------------------------------------------------
# Helper: resolve a raw secedit rights entry (SID or name) to a display name
# ---------------------------------------------------------------------------
function Resolve-RightsEntry {
    param([string]$Entry)

    if ($Entry -like "*S-1-*") {
        $rawSid = $Entry.TrimStart('*')
        try {
            $sid = New-Object System.Security.Principal.SecurityIdentifier($rawSid)
            return $sid.Translate([System.Security.Principal.NTAccount]).Value
        } catch {
            return $rawSid
        }
    }
    return $Entry
}

# ---------------------------------------------------------------------------
# Export and parse local User Rights Assignment policy via secedit
# ---------------------------------------------------------------------------
function Get-UserRightsMap {
    $tempFile = Join-Path $env:TEMP ("secpol_{0}.cfg" -f ([guid]::NewGuid().ToString("N")))
    secedit /export /cfg $tempFile /areas USER_RIGHTS | Out-Null

    if (-not (Test-Path $tempFile)) {
        Write-Host "Warning: secedit export failed. User rights data will be incomplete." -ForegroundColor Yellow
        return @{}
    }

    $lines = Get-Content -Path $tempFile -Encoding Unicode
    Remove-Item -Path $tempFile -Force -ErrorAction SilentlyContinue

    $rightsMap = @{}
    foreach ($line in $lines) {
        if ($line -match '^(Se\w+)\s*=\s*(.*)$') {
            $rightName = $Matches[1]
            $rawList = $Matches[2] -split ','
            $resolved = @()
            foreach ($rawEntry in $rawList) {
                $trimmed = $rawEntry.Trim()
                if ($trimmed) {
                    $resolved += (Resolve-RightsEntry -Entry $trimmed)
                }
            }
            $rightsMap[$rightName] = $resolved
        }
    }
    return $rightsMap
}

# ---------------------------------------------------------------------------
# Build the per-account risk report
# ---------------------------------------------------------------------------
function Get-AccountRiskReport {
    param([hashtable]$RightsMap)

    $currentUserName = $env:USERNAME
    $allUsers = Get-LocalUser
    $report = @()

    foreach ($user in $allUsers) {
        $accountName = $user.Name

        # Group memberships
        $memberOfGroups = @()
        foreach ($group in Get-LocalGroup) {
            $members = Get-LocalGroupMember -Group $group.Name -ErrorAction SilentlyContinue
            if ($members | Where-Object { $_.Name -like "*\$accountName" -or $_.Name -eq $accountName }) {
                $memberOfGroups += $group.Name
            }
        }

        $isAdminMember = $memberOfGroups -contains "Administrators"

        $hasInteractive       = $RightsMap["SeInteractiveLogonRight"]       -contains $accountName
        $hasRemoteInteractive = $RightsMap["SeRemoteInteractiveLogonRight"] -contains $accountName
        $hasNetwork           = $RightsMap["SeNetworkLogonRight"]          -contains $accountName
        $hasBatch             = $RightsMap["SeBatchLogonRight"]            -contains $accountName
        $hasService           = $RightsMap["SeServiceLogonRight"]          -contains $accountName

        # Services running under this account
        $tiedServices = Get-CimInstance Win32_Service -ErrorAction SilentlyContinue |
            Where-Object { $_.StartName -like "*$accountName*" } |
            Select-Object -ExpandProperty Name

        # ---------------------------------------------------------------
        # Risk scoring
        # ---------------------------------------------------------------
        $score = 0
        $reasons = @()

        if ($user.Enabled -and (-not $user.PasswordRequired)) {
            $score += 3
            $reasons += "Enabled with no password required"
        }
        if ($user.Enabled -and $isAdminMember) {
            $score += 2
            $reasons += "Enabled and member of Administrators"
        }
        if ($user.Enabled -and ($hasInteractive -or $hasRemoteInteractive)) {
            $score += 2
            $reasons += "Enabled with interactive or remote logon rights"
        }
        if ($accountName -eq "Guest" -and $user.Enabled) {
            $score += 3
            $reasons += "Built-in Guest account is enabled"
        }
        if ($user.Enabled -and ($hasBatch -or $hasService) -and $tiedServices.Count -eq 0) {
            $score += 1
            $reasons += "Has batch/service logon right but no tied service found"
        }
        if ($user.Enabled -and -not $user.LastLogon -and $user.PasswordLastSet -and
            ((Get-Date) - $user.PasswordLastSet).Days -gt 365) {
            $score += 1
            $reasons += "Enabled, never logged on, password older than 1 year"
        }

        $riskLevel = "LOW"
        if ($score -ge 5) { $riskLevel = "HIGH" }
        elseif ($score -ge 2) { $riskLevel = "MEDIUM" }

        $report += [PSCustomObject]@{
            Name                  = $accountName
            Enabled               = $user.Enabled
            PasswordRequired      = $user.PasswordRequired
            IsCurrentUser         = ($accountName -eq $currentUserName)
            Groups                = ($memberOfGroups -join "; ")
            InteractiveLogon      = $hasInteractive
            RemoteInteractiveLogon= $hasRemoteInteractive
            NetworkLogon          = $hasNetwork
            BatchLogon            = $hasBatch
            ServiceLogon          = $hasService
            TiedServices          = ($tiedServices -join "; ")
            RiskScore             = $score
            RiskLevel             = $riskLevel
            RiskReasons           = ($reasons -join " | ")
        }
    }
    return $report
}

# ---------------------------------------------------------------------------
# Console output helper (three-tier color convention: GREEN / YELLOW / RED)
# ---------------------------------------------------------------------------
function Write-RiskLine {
    param([PSCustomObject]$AccountEntry)

    $color = "Green"
    if ($AccountEntry.RiskLevel -eq "MEDIUM") { $color = "Yellow" }
    if ($AccountEntry.RiskLevel -eq "HIGH")   { $color = "Red" }

    Write-Host ("[{0}] {1}  (Score: {2})" -f $AccountEntry.RiskLevel, $AccountEntry.Name, $AccountEntry.RiskScore) -ForegroundColor $color
    if ($AccountEntry.RiskReasons) {
        Write-Host ("    Reasons: {0}" -f $AccountEntry.RiskReasons) -ForegroundColor $color
    }
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------
Write-Host "Starting local account security audit..." -ForegroundColor Cyan
Write-Host "Exporting user rights assignment policy..." -ForegroundColor Cyan

$rightsMap = Get-UserRightsMap
$report = Get-AccountRiskReport -RightsMap $rightsMap

if (-not $Silent) {
    Write-Host "`n===== Local Account Risk Report =====`n" -ForegroundColor Cyan
    $sortedReport = $report | Sort-Object -Property @{Expression = {
        switch ($_.RiskLevel) { "HIGH" {0} "MEDIUM" {1} default {2} }
    }}, Name
    foreach ($entry in $sortedReport) {
        Write-RiskLine -AccountEntry $entry
    }
    Write-Host ""
}

# ---------------------------------------------------------------------------
# Save CSV report
# ---------------------------------------------------------------------------
if (-not (Test-Path $LogFolder)) {
    New-Item -Path $LogFolder -ItemType Directory -Force | Out-Null
}
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$csvPath = Join-Path $LogFolder ("LocalAccountAudit_{0}.csv" -f $timestamp)
$report | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
Write-Host ("Report saved to: {0}" -f $csvPath) -ForegroundColor Cyan

# ---------------------------------------------------------------------------
# Remediation: disable risky accounts
# ---------------------------------------------------------------------------
$actionable = $report | Where-Object { $_.Enabled -and $_.RiskLevel -in @("HIGH", "MEDIUM") -and -not $_.IsCurrentUser }

if ($actionable.Count -eq 0) {
    Write-Host "`nNo actionable risky accounts found." -ForegroundColor Green
} elseif ($DryRun) {
    Write-Host "`n[DRY RUN] The following accounts would be reviewed for disabling:" -ForegroundColor Yellow
    foreach ($entry in $actionable) {
        Write-Host ("  - {0} ({1})" -f $entry.Name, $entry.RiskLevel) -ForegroundColor Yellow
    }
} else {
    Write-Host "`n===== Remediation =====`n" -ForegroundColor Cyan
    foreach ($entry in $actionable) {

        if ($entry.Name -eq "Administrator" -or $entry.Name -eq "Guest") {
            if ($entry.Name -eq "Guest" -and $entry.RiskLevel -ne "HIGH") {
                continue
            }
        }

        $shouldDisable = $false

        if ($AutoApprove -and $entry.RiskLevel -eq "HIGH") {
            $shouldDisable = $true
            Write-Host ("Auto-approving disable for HIGH risk account: {0}" -f $entry.Name) -ForegroundColor Red
        } elseif (-not $AutoApprove) {
            Write-Host ("Account: {0}  Risk: {1}  Reasons: {2}" -f $entry.Name, $entry.RiskLevel, $entry.RiskReasons) -ForegroundColor Yellow
            $answer = Read-Host "Disable this account now? (Y/N)"
            if ($answer -match '^[Yy]') {
                $shouldDisable = $true
            }
        }

        if ($shouldDisable) {
            try {
                Disable-LocalUser -Name $entry.Name -ErrorAction Stop
                Write-Host ("  -> Disabled: {0}" -f $entry.Name) -ForegroundColor Green
            } catch {
                Write-Host ("  -> Failed to disable {0}: {1}" -f $entry.Name, $_.Exception.Message) -ForegroundColor Red
            }
        } else {
            Write-Host ("  -> Skipped: {0}" -f $entry.Name) -ForegroundColor DarkYellow
        }
    }
}

Write-Host "`nAudit complete." -ForegroundColor Cyan
Read-Host "`nPress ENTER to exit."
Güle güle kullanın..
Cevapla

“Programlama ve Script dilleri” sayfasına dön