CIS Benchmarks with Powershell Scripts

POWERSHELL - multifile input

#Requires -Version 5.1

<#

.SYNOPSIS

Multi-File Registry SID Processor - PowerShell Version

.DESCRIPTION

This PowerShell script processes multiple Windows Registry files by replacing

<***USER_SID***> placeholders with the current user's actual SID and then

executing the registry changes. Supports single files, multiple files, file

lists, and configurable source locations including network paths.

.PARAMETER Files

Array of registry filenames to process

.PARAMETER FileList

Path to a text file containing a list of registry files to process

.PARAMETER ConfigFile

Path to configuration file (JSON format)

.PARAMETER SourcePath

Override the source path for registry files

.PARAMETER Preview

Show preview of changes without applying them

.PARAMETER Force

Skip confirmation prompts

.PARAMETER Verbose

Enable verbose output

.EXAMPLE

.\Process-RegistryMulti.ps1 -Files "screensaver_policy.reg"

Process a single registry file

.EXAMPLE

.\Process-RegistryMulti.ps1 -Files "policy1.reg","policy2.reg","policy3.reg"

Process multiple registry files

.EXAMPLE

.\Process-RegistryMulti.ps1 -FileList "company_policies.txt"

Process files listed in a text file

.EXAMPLE

.\Process-RegistryMulti.ps1 -Files "policy.reg" -SourcePath "\\server\share\registry\"

Process file from network location

.EXAMPLE

.\Process-RegistryMulti.ps1 -FileList "policies.txt" -Preview

Preview changes without applying them

.NOTES

Version: 2.0

Author: Registry SID Processor

Requires: PowerShell 5.1 or later, Administrator privileges for some registry keys

#>

[CmdletBinding(DefaultParameterSetName = 'Files')]

param(

[Parameter(ParameterSetName = 'Files', Position = 0)]

[string[]]$Files,

[Parameter(ParameterSetName = 'FileList')]

[string]$FileList,

[Parameter()]

[string]$ConfigFile = "registry_config.json",

[Parameter()]

[string]$SourcePath,

[Parameter()]

[switch]$Preview,

[Parameter()]

[switch]$Force,

[Parameter()]

[switch]$WhatIf

)

# Script configuration

$script:Config = @{

SourcePath = ".\registry_files\"

TempDir = $null

LogFile = $null

BackupEnabled = $true

BackupPath = ".\registry_backups\"

}

$script:Stats = @{

ProcessedCount = 0

FailedCount = 0

SkippedCount = 0

StartTime = Get-Date

}

# Initialize logging

function Initialize-Logging {

$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

$script:Config.LogFile = ".\registry_processor_$timestamp.log"

Write-Log "Registry SID Processor v2.0 - PowerShell Edition" -Level "INFO"

Write-Log "Started at: $(Get-Date)" -Level "INFO"

Write-Log "User: $env:USERNAME" -Level "INFO"

Write-Log "Computer: $env:COMPUTERNAME" -Level "INFO"

}

# Logging function

function Write-Log {

param(

[string]$Message,

[ValidateSet("INFO", "WARN", "ERROR", "DEBUG")]

[string]$Level = "INFO"

)

$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"

$logEntry = "[$timestamp] [$Level] $Message"

# Console output with colors

switch ($Level) {

"ERROR" { Write-Host $logEntry -ForegroundColor Red }

"WARN" { Write-Host $logEntry -ForegroundColor Yellow }

"DEBUG" { if ($VerbosePreference -eq "Continue") { Write-Host $logEntry -ForegroundColor Gray } }

default { Write-Host $logEntry -ForegroundColor White }

}

# File output

if ($script:Config.LogFile) {

Add-Content -Path $script:Config.LogFile -Value $logEntry -ErrorAction SilentlyContinue

}

}

# Load configuration from JSON file

function Load-Configuration {

param([string]$ConfigPath)

if (Test-Path $ConfigPath) {

try {

Write-Log "Loading configuration from: $ConfigPath" -Level "INFO"

$configData = Get-Content $ConfigPath -Raw | ConvertFrom-Json

if ($configData.SourcePath) { $script:Config.SourcePath = $configData.SourcePath }

if ($configData.TempDir) { $script:Config.TempDir = $configData.TempDir }

if ($configData.BackupEnabled -ne $null) { $script:Config.BackupEnabled = $configData.BackupEnabled }

if ($configData.BackupPath) { $script:Config.BackupPath = $configData.BackupPath }

Write-Log "Configuration loaded successfully" -Level "INFO"

}

catch {

Write-Log "Failed to load configuration: $($_.Exception.Message)" -Level "WARN"

Write-Log "Using default configuration" -Level "INFO"

}

}

else {

Write-Log "Configuration file not found: $ConfigPath" -Level "WARN"

Write-Log "Using default configuration" -Level "INFO"

}

}

# Get current user's SID

function Get-CurrentUserSID {

try {

Write-Log "Detecting current user SID..." -Level "INFO"

# Method 1: Using .NET Security Principal

$user = [System.Security.Principal.WindowsIdentity]::GetCurrent()

if ($user -and $user.User) {

$sid = $user.User.Value

Write-Log "SID detected using .NET method: $sid" -Level "DEBUG"

return $sid

}

# Method 2: Using WMI

$userAccount = Get-WmiObject -Class Win32_UserAccount -Filter "Name='$env:USERNAME'"

if ($userAccount) {

$sid = $userAccount.SID

Write-Log "SID detected using WMI method: $sid" -Level "DEBUG"

return $sid

}

# Method 3: Using whoami command

$whoamiOutput = & whoami /user /fo csv | ConvertFrom-Csv

if ($whoamiOutput -and $whoamiOutput.SID) {

$sid = $whoamiOutput.SID

Write-Log "SID detected using whoami method: $sid" -Level "DEBUG"

return $sid

}

throw "All SID detection methods failed"

}

catch {

Write-Log "Failed to detect user SID: $($_.Exception.Message)" -Level "ERROR"

return $null

}

}

# Create backup of registry key

function Backup-RegistryKey {

param(

[string]$KeyPath,

[string]$BackupName

)

if (-not $script:Config.BackupEnabled) {

return $true

}

try {

$backupDir = $script:Config.BackupPath

if (-not (Test-Path $backupDir)) {

New-Item -Path $backupDir -ItemType Directory -Force | Out-Null

}

$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"

$backupFile = Join-Path $backupDir "$BackupName`_$timestamp.reg"

Write-Log "Creating backup: $backupFile" -Level "DEBUG"

# Use reg export command

$result = & reg export $KeyPath $backupFile /y 2>&1

if ($LASTEXITCODE -eq 0) {

Write-Log "Backup created successfully: $backupFile" -Level "INFO"

return $true

}

else {

Write-Log "Backup failed: $result" -Level "WARN"

return $false

}

}

catch {

Write-Log "Backup error: $($_.Exception.Message)" -Level "WARN"

return $false

}

}

# Process a single registry file

function Process-RegistryFile {

param(

[string]$FileName,

[string]$UserSID,

[switch]$PreviewOnly

)

$sourceFile = Join-Path $script:Config.SourcePath $FileName

Write-Log "Processing file: $FileName" -Level "INFO"

Write-Log "Source path: $sourceFile" -Level "DEBUG"

# Check if source file exists

if (-not (Test-Path $sourceFile)) {

Write-Log "File not found: $sourceFile" -Level "ERROR"

$script:Stats.FailedCount++

return $false

}

try {

# Read and process file content

$content = Get-Content $sourceFile -Raw

$processedContent = $content -replace '<\*\*\*USER_SID\*\*\*>', $UserSID

# Create temporary file

$tempDir = if ($script:Config.TempDir) { $script:Config.TempDir } else { $env:TEMP }

$tempFile = Join-Path $tempDir "processed_$(Get-Random)_$FileName"

# Ensure temp directory exists

$tempFileDir = Split-Path $tempFile -Parent

if (-not (Test-Path $tempFileDir)) {

New-Item -Path $tempFileDir -ItemType Directory -Force | Out-Null

}

# Write processed content

Set-Content -Path $tempFile -Value $processedContent -Encoding UTF8

Write-Log "Processed file created: $tempFile" -Level "DEBUG"

if ($PreviewOnly) {

Write-Log "PREVIEW MODE - Registry content:" -Level "INFO"

Write-Host "=" * 50 -ForegroundColor Cyan

Write-Host $processedContent -ForegroundColor Gray

Write-Host "=" * 50 -ForegroundColor Cyan

$script:Stats.ProcessedCount++

return $true

}

# Extract registry keys for backup

$registryKeys = $processedContent | Select-String -Pattern '\[HKEY_[^\]]+\]' -AllMatches |

ForEach-Object { $_.Matches.Value -replace '^\[|\]$', '' }

# Create backups

foreach ($key in $registryKeys) {

$backupName = "$FileName`_$(($key -split '\\')[-1])"

Backup-RegistryKey -KeyPath $key -BackupName $backupName

}

# Apply registry changes

Write-Log "Applying registry changes..." -Level "INFO"

if ($WhatIf) {

Write-Log "WHATIF: Would apply registry file: $tempFile" -Level "INFO"

$script:Stats.ProcessedCount++

return $true

}

$result = & reg import $tempFile 2>&1

if ($LASTEXITCODE -eq 0) {

Write-Log "Registry changes applied successfully for: $FileName" -Level "INFO"

$script:Stats.ProcessedCount++

$success = $true

}

else {

Write-Log "Failed to apply registry changes for: $FileName" -Level "ERROR"

Write-Log "Error output: $result" -Level "ERROR"

$script:Stats.FailedCount++

$success = $false

}

# Cleanup temporary file

Remove-Item $tempFile -Force -ErrorAction SilentlyContinue

return $success

}

catch {

Write-Log "Error processing file $FileName`: $($_.Exception.Message)" -Level "ERROR"

$script:Stats.FailedCount++

return $false

}

}

# Load file list from text file

function Get-FileListFromFile {

param([string]$ListFile)

if (-not (Test-Path $ListFile)) {

Write-Log "File list not found: $ListFile" -Level "ERROR"

return @()

}

try {

$files = Get-Content $ListFile |

Where-Object { $_ -and $_ -notmatch '^\s*#' -and $_.Trim() -ne '' } |

ForEach-Object { $_.Trim() }

Write-Log "Loaded $($files.Count) files from list: $ListFile" -Level "INFO"

return $files

}

catch {

Write-Log "Error reading file list: $($_.Exception.Message)" -Level "ERROR"

return @()

}

}

# Show processing summary

function Show-Summary {

$endTime = Get-Date

$duration = $endTime - $script:Stats.StartTime

Write-Host "`n" + "=" * 60 -ForegroundColor Cyan

Write-Host "PROCESSING SUMMARY" -ForegroundColor Cyan

Write-Host "=" * 60 -ForegroundColor Cyan

Write-Host "Files processed successfully: " -NoNewline

Write-Host $script:Stats.ProcessedCount -ForegroundColor Green

Write-Host "Files failed: " -NoNewline

Write-Host $script:Stats.FailedCount -ForegroundColor Red

Write-Host "Files skipped: " -NoNewline

Write-Host $script:Stats.SkippedCount -ForegroundColor Yellow

$total = $script:Stats.ProcessedCount + $script:Stats.FailedCount + $script:Stats.SkippedCount

Write-Host "Total files: " -NoNewline

Write-Host $total -ForegroundColor White

Write-Host "Duration: " -NoNewline

Write-Host $duration.ToString("hh\:mm\:ss") -ForegroundColor White

Write-Host "Log file: " -NoNewline

Write-Host $script:Config.LogFile -ForegroundColor White

Write-Host "=" * 60 -ForegroundColor Cyan

Write-Log "Processing completed. Summary: Processed=$($script:Stats.ProcessedCount), Failed=$($script:Stats.FailedCount), Skipped=$($script:Stats.SkippedCount)" -Level "INFO"

}

# Main execution function

function Main {

try {

# Initialize

Initialize-Logging

# Load configuration

Load-Configuration -ConfigPath $ConfigFile

# Override source path if specified

if ($SourcePath) {

$script:Config.SourcePath = $SourcePath

Write-Log "Source path overridden: $SourcePath" -Level "INFO"

}

Write-Log "Source path: $($script:Config.SourcePath)" -Level "INFO"

# Get user SID

$userSID = Get-CurrentUserSID

if (-not $userSID) {

Write-Log "Cannot proceed without user SID" -Level "ERROR"

return 1

}

Write-Log "Current user SID: $userSID" -Level "INFO"

# Determine files to process

$filesToProcess = @()

if ($FileList) {

$filesToProcess = Get-FileListFromFile -ListFile $FileList

}

elseif ($Files) {

$filesToProcess = $Files

}

else {

Write-Log "No files specified. Use -Files or -FileList parameter." -Level "ERROR"

return 1

}

if ($filesToProcess.Count -eq 0) {

Write-Log "No files to process" -Level "WARN"

return 0

}

Write-Log "Files to process: $($filesToProcess.Count)" -Level "INFO"

# Confirmation prompt

if (-not $Force -and -not $Preview -and -not $WhatIf) {

Write-Host "`nFiles to be processed:" -ForegroundColor Yellow

$filesToProcess | ForEach-Object { Write-Host " - $_" -ForegroundColor Gray }

Write-Host "`nSource: $($script:Config.SourcePath)" -ForegroundColor Yellow

$response = Read-Host "`nDo you want to proceed? (Y/N)"

if ($response -notmatch '^[Yy]') {

Write-Log "Operation cancelled by user" -Level "INFO"

return 0

}

}

# Process files

foreach ($file in $filesToProcess) {

$success = Process-RegistryFile -FileName $file -UserSID $userSID -PreviewOnly:$Preview

if (-not $success) {

Write-Log "Failed to process: $file" -Level "ERROR"

}

}

# Show summary

Show-Summary

# Return appropriate exit code

return if ($script:Stats.FailedCount -gt 0) { 1 } else { 0 }

}

catch {

Write-Log "Unexpected error: $($_.Exception.Message)" -Level "ERROR"

Write-Log "Stack trace: $($_.ScriptStackTrace)" -Level "DEBUG"

return 1

}

}

# Script entry point

if ($MyInvocation.InvocationName -ne '.') {

$exitCode = Main

exit $exitCode

}

USAGE_EXAMPLES.ps1

# PowerShell Registry Processor - Usage Examples

# ==============================================

# This file contains various usage examples for the Process-RegistryMulti.ps1 script

# Example 1: Process a single registry file

# .\Process-RegistryMulti.ps1 -Files "screensaver_policy.reg"

# Example 2: Process multiple registry files

# .\Process-RegistryMulti.ps1 -Files "screensaver_policy.reg","windows_update_policy.reg","security_policy.reg"

# Example 3: Process files from a list

# .\Process-RegistryMulti.ps1 -FileList "company_policies.txt"

# Example 4: Preview changes without applying them

# .\Process-RegistryMulti.ps1 -Files "screensaver_policy.reg" -Preview

# Example 5: Use custom configuration file

# .\Process-RegistryMulti.ps1 -ConfigFile "production_config.json" -FileList "policies.txt"

# Example 6: Override source path

# .\Process-RegistryMulti.ps1 -Files "policy.reg" -SourcePath "\\server\share\registry\"

# Example 7: Force execution without prompts

# .\Process-RegistryMulti.ps1 -Files "policy.reg" -Force

# Example 8: What-if mode (show what would be done)

# .\Process-RegistryMulti.ps1 -Files "policy.reg" -WhatIf

# Example 9: Verbose output for debugging

# .\Process-RegistryMulti.ps1 -Files "policy.reg" -Verbose

# Example 10: Combine multiple options

# .\Process-RegistryMulti.ps1 -FileList "policies.txt" -SourcePath "\\server\registry\" -Force -Verbose

# Advanced Examples

# =================

# Process files with error handling

try {

.\Process-RegistryMulti.ps1 -Files "critical_policy.reg" -Force

Write-Host "Registry processing completed successfully" -ForegroundColor Green

}

catch {

Write-Host "Registry processing failed: $($_.Exception.Message)" -ForegroundColor Red

exit 1

}

# Process files and capture output

$result = .\Process-RegistryMulti.ps1 -Files "policy.reg" -Force

if ($LASTEXITCODE -eq 0) {

Write-Host "Success: All registry changes applied" -ForegroundColor Green

} else {

Write-Host "Error: Some registry changes failed" -ForegroundColor Red

}

# Batch processing with different configurations

$environments = @("development", "testing", "production")

foreach ($env in $environments) {

Write-Host "Processing $env environment..." -ForegroundColor Yellow

.\Process-RegistryMulti.ps1 -ConfigFile "$env`_config.json" -FileList "$env`_policies.txt" -Force

}

# Network path processing with retry logic

$maxRetries = 3

$retryCount = 0

do {

try {

.\Process-RegistryMulti.ps1 -SourcePath "\\server\registry\" -FileList "policies.txt" -Force

break

}

catch {

$retryCount++

Write-Host "Attempt $retryCount failed, retrying..." -ForegroundColor Yellow

Start-Sleep -Seconds 5

}

} while ($retryCount -lt $maxRetries)

# Scheduled task integration

# Register-ScheduledTask -TaskName "RegistryUpdate" -Action (New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-File C:\Scripts\Process-RegistryMulti.ps1 -FileList C:\Policies\daily_updates.txt -Force") -Trigger (New-ScheduledTaskTrigger -Daily -At "02:00")

# Group Policy integration example

# if (Test-Path "\\domain\sysvol\policies\registry\") {

# .\Process-RegistryMulti.ps1 -SourcePath "\\domain\sysvol\policies\registry\" -FileList "user_policies.txt" -Force

# }

PRODUCTION_CONFIG.JSON

{

"SourcePath": "\\\\policyserver\\registry\\production\\",

"TempDir": "C:\\Temp\\RegistryProcessor\\",

"BackupEnabled": true,

"BackupPath": "C:\\RegistryBackups\\Production\\",

"LogLevel": "INFO",

"MaxConcurrentFiles": 3,

"NetworkTimeout": 60,

"RetryAttempts": 5,

"Comments": {

"Description": "Production environment configuration",

"SourcePath": "Network path to production registry policies",

"TempDir": "Dedicated temp directory for production processing",

"BackupPath": "Production backup location with proper permissions",

"NetworkTimeout": "Increased timeout for network operations",

"RetryAttempts": "More retry attempts for critical production environment"

}

}

REGISTRY_CONFIG.JSON

{

"SourcePath": ".\\registry_files\\",

"TempDir": null,

"BackupEnabled": true,

"BackupPath": ".\\registry_backups\\",

"LogLevel": "INFO",

"MaxConcurrentFiles": 5,

"NetworkTimeout": 30,

"RetryAttempts": 3,

"Comments": {

"SourcePath": "Local folder or network path (e.g., '\\\\server\\share\\registry\\')",

"TempDir": "Custom temp directory (null = use system temp)",

"BackupEnabled": "Create registry backups before applying changes",

"BackupPath": "Directory for registry backups",

"LogLevel": "Logging level: DEBUG, INFO, WARN, ERROR",

"MaxConcurrentFiles": "Maximum files to process concurrently",

"NetworkTimeout": "Network timeout in seconds",

"RetryAttempts": "Number of retry attempts for failed operations"

}

}

Previous
Previous

CIS Benchmarks with Batch Scripts

Next
Next

OWASP Top 10 Risk Mitigation for SMBs: Essential Strategies for Securing Your Business