Hardening/Enable-PowerShellSecurity.ps1

function Enable-PowerShellSecurity {
    <#
    .SYNOPSIS
        Hardens PowerShell security settings
    .DESCRIPTION
        Configures PowerShell security features including execution policy, logging,
        transcription, and constrained language mode
    .PARAMETER ExecutionPolicy
        Set execution policy (default: RemoteSigned)
    .PARAMETER EnableScriptBlockLogging
        Enable PowerShell script block logging
    .PARAMETER EnableTranscription
        Enable PowerShell transcription logging
    .PARAMETER EnableModuleLogging
        Enable PowerShell module logging
    .PARAMETER TranscriptionPath
        Path for transcription logs
    .EXAMPLE
        Enable-PowerShellSecurity -ExecutionPolicy RemoteSigned -EnableScriptBlockLogging
        Enable-PowerShellSecurity -EnableTranscription -TranscriptionPath "C:\PSLogs"
    .OUTPUTS
        PSCustomObject with configuration results
    #>

    
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [Parameter()]
        [ValidateSet('Restricted', 'AllSigned', 'RemoteSigned', 'Unrestricted', 'Bypass')]
        [string]$ExecutionPolicy = 'RemoteSigned',
        
        [Parameter()]
        [switch]$EnableScriptBlockLogging,
        
        [Parameter()]
        [switch]$EnableTranscription,
        
        [Parameter()]
        [switch]$EnableModuleLogging,
        
        [Parameter()]
        [string]$TranscriptionPath = "C:\PowerShellLogs"
    )
    
    begin {
        Write-Host "=== POWERSHELL SECURITY HARDENING ===" -ForegroundColor Cyan
        
        # Check for admin privileges
        $isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
        if (-not $isAdmin) {
            throw "This function requires Administrator privileges!"
        }
        
        $results = [PSCustomObject]@{
            ConfigurationDate = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
            ExecutionPolicy = @{
                Before = $null
                After = $null
                Status = 'Not Changed'
            }
            ScriptBlockLogging = @{
                Enabled = $false
                Status = 'Not Configured'
            }
            Transcription = @{
                Enabled = $false
                Path = $null
                Status = 'Not Configured'
            }
            ModuleLogging = @{
                Enabled = $false
                Status = 'Not Configured'
            }
            Changes = @()
        }
    }
    
    process {
        try {
            # 1. Configure Execution Policy
            Write-Host "`n[1/4] Configuring Execution Policy..." -ForegroundColor Cyan
            
            $currentPolicy = Get-ExecutionPolicy -Scope LocalMachine
            $results.ExecutionPolicy.Before = $currentPolicy
            
            if ($currentPolicy -ne $ExecutionPolicy) {
                if ($PSCmdlet.ShouldProcess("LocalMachine", "Set Execution Policy to $ExecutionPolicy")) {
                    Set-ExecutionPolicy -ExecutionPolicy $ExecutionPolicy -Scope LocalMachine -Force
                    $results.ExecutionPolicy.After = $ExecutionPolicy
                    $results.ExecutionPolicy.Status = 'Changed'
                    $results.Changes += "Execution Policy changed from $currentPolicy to $ExecutionPolicy"
                    Write-Host " Execution Policy set to: $ExecutionPolicy" -ForegroundColor Green
                }
            } else {
                $results.ExecutionPolicy.After = $currentPolicy
                $results.ExecutionPolicy.Status = 'Already Configured'
                Write-Host " Execution Policy already set to: $ExecutionPolicy" -ForegroundColor Yellow
            }
            
            # 2. Configure Script Block Logging
            Write-Host "`n[2/4] Configuring Script Block Logging..." -ForegroundColor Cyan
            
            if ($EnableScriptBlockLogging) {
                $regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging"
                
                if ($PSCmdlet.ShouldProcess("Registry", "Enable PowerShell Script Block Logging")) {
                    # Create registry path if it doesn't exist
                    if (-not (Test-Path $regPath)) {
                        New-Item -Path $regPath -Force | Out-Null
                    }
                    
                    # Enable script block logging
                    Set-ItemProperty -Path $regPath -Name "EnableScriptBlockLogging" -Value 1 -Type DWord -Force
                    
                    # Enable logging of invocation start/stop
                    Set-ItemProperty -Path $regPath -Name "EnableScriptBlockInvocationLogging" -Value 1 -Type DWord -Force
                    
                    $results.ScriptBlockLogging.Enabled = $true
                    $results.ScriptBlockLogging.Status = 'Enabled'
                    $results.Changes += "Script Block Logging enabled"
                    
                    Write-Host " Script Block Logging: Enabled" -ForegroundColor Green
                }
            } else {
                Write-Host " Script Block Logging: Skipped" -ForegroundColor Yellow
            }
            
            # 3. Configure PowerShell Transcription
            Write-Host "`n[3/4] Configuring PowerShell Transcription..." -ForegroundColor Cyan
            
            if ($EnableTranscription) {
                $regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\Transcription"
                
                if ($PSCmdlet.ShouldProcess("Registry", "Enable PowerShell Transcription")) {
                    # Create transcription directory
                    if (-not (Test-Path $TranscriptionPath)) {
                        New-Item -Path $TranscriptionPath -ItemType Directory -Force | Out-Null
                    }
                    
                    # Create registry path if it doesn't exist
                    if (-not (Test-Path $regPath)) {
                        New-Item -Path $regPath -Force | Out-Null
                    }
                    
                    # Enable transcription
                    Set-ItemProperty -Path $regPath -Name "EnableTranscripting" -Value 1 -Type DWord -Force
                    Set-ItemProperty -Path $regPath -Name "OutputDirectory" -Value $TranscriptionPath -Type String -Force
                    Set-ItemProperty -Path $regPath -Name "EnableInvocationHeader" -Value 1 -Type DWord -Force
                    
                    $results.Transcription.Enabled = $true
                    $results.Transcription.Path = $TranscriptionPath
                    $results.Transcription.Status = 'Enabled'
                    $results.Changes += "PowerShell Transcription enabled at: $TranscriptionPath"
                    
                    Write-Host " Transcription: Enabled" -ForegroundColor Green
                    Write-Host " Transcription Path: $TranscriptionPath" -ForegroundColor White
                }
            } else {
                Write-Host " Transcription: Skipped" -ForegroundColor Yellow
            }
            
            # 4. Configure Module Logging
            Write-Host "`n[4/4] Configuring Module Logging..." -ForegroundColor Cyan
            
            if ($EnableModuleLogging) {
                $regPath = "HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ModuleLogging"
                $moduleNamesPath = "$regPath\ModuleNames"
                
                if ($PSCmdlet.ShouldProcess("Registry", "Enable PowerShell Module Logging")) {
                    # Create registry paths
                    if (-not (Test-Path $regPath)) {
                        New-Item -Path $regPath -Force | Out-Null
                    }
                    if (-not (Test-Path $moduleNamesPath)) {
                        New-Item -Path $moduleNamesPath -Force | Out-Null
                    }
                    
                    # Enable module logging
                    Set-ItemProperty -Path $regPath -Name "EnableModuleLogging" -Value 1 -Type DWord -Force
                    
                    # Log all modules
                    Set-ItemProperty -Path $moduleNamesPath -Name "*" -Value "*" -Type String -Force
                    
                    $results.ModuleLogging.Enabled = $true
                    $results.ModuleLogging.Status = 'Enabled'
                    $results.Changes += "Module Logging enabled for all modules"
                    
                    Write-Host " Module Logging: Enabled" -ForegroundColor Green
                }
            } else {
                Write-Host " Module Logging: Skipped" -ForegroundColor Yellow
            }
            
            # Additional PowerShell Security Settings
            Write-Host "`n[ADDITIONAL] Applying Additional Security Settings..." -ForegroundColor Cyan
            
            # Disable PowerShell v2 (if exists)
            $psv2Feature = Get-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 -ErrorAction SilentlyContinue
            if ($psv2Feature -and $psv2Feature.State -eq 'Enabled') {
                if ($PSCmdlet.ShouldProcess("Windows Feature", "Disable PowerShell v2")) {
                    try {
                        Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2 -NoRestart -ErrorAction Stop | Out-Null
                        Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root -NoRestart -ErrorAction Stop | Out-Null
                        $results.Changes += "PowerShell v2 disabled (requires restart)"
                        Write-Host " PowerShell v2: Disabled (restart required)" -ForegroundColor Green
                    } catch {
                        Write-Warning " Could not disable PowerShell v2: $_"
                    }
                }
            } else {
                Write-Host " PowerShell v2: Already disabled or not installed" -ForegroundColor Yellow
            }
            
            # Configure WSMAN (Windows Remote Management) security
            Write-Host "`n[WSMAN] Configuring Windows Remote Management Security..." -ForegroundColor Cyan
            
            try {
                if ($PSCmdlet.ShouldProcess("WSMAN Service", "Disable Basic authentication and enable Kerberos")) {
                    # Disable Basic Authentication
                    Set-Item WSMan:\localhost\Service\Auth\Basic -Value $false -Force
                    $results.Changes += "WSMAN Basic Authentication disabled"
                    Write-Host " WSMAN Basic Auth: Disabled" -ForegroundColor Green
                    
                    # Enable Kerberos
                    Set-Item WSMan:\localhost\Service\Auth\Kerberos -Value $true -Force
                    Write-Host " WSMAN Kerberos: Enabled" -ForegroundColor Green
                }
                
            } catch {
                Write-Warning " Could not configure WSMAN: $_"
            }
            
        }
        catch {
            Write-Error "Error during PowerShell security hardening: $_"
            throw
        }
    }
    
    end {
        Write-Host "`n=== CONFIGURATION COMPLETE ===" -ForegroundColor Green
        Write-Host "`nChanges Applied:" -ForegroundColor Cyan
        
        if ($results.Changes.Count -gt 0) {
            $results.Changes | ForEach-Object {
                Write-Host " - $_" -ForegroundColor White
            }
        } else {
            Write-Host " No changes were made" -ForegroundColor Yellow
        }
        
        Write-Host "`nCurrent Configuration:" -ForegroundColor Cyan
        Write-Host " Execution Policy: $($results.ExecutionPolicy.After)" -ForegroundColor White
        Write-Host " Script Block Logging: $($results.ScriptBlockLogging.Status)" -ForegroundColor White
        Write-Host " Transcription: $($results.Transcription.Status)" -ForegroundColor White
        Write-Host " Module Logging: $($results.ModuleLogging.Status)" -ForegroundColor White
        
        if ($results.Changes -match 'restart') {
            Write-Host "`n⚠ RESTART REQUIRED for some changes to take effect" -ForegroundColor Yellow
        }
        
        Write-Host "`nRecommendations:" -ForegroundColor Cyan
        Write-Host " 1. Test scripts after changing execution policy" -ForegroundColor White
        Write-Host " 2. Monitor PowerShell logs regularly" -ForegroundColor White
        Write-Host " 3. Rotate transcription logs to prevent disk space issues" -ForegroundColor White
        Write-Host " 4. Consider implementing JEA (Just Enough Administration)" -ForegroundColor White
        
        return $results
    }
}