functions/System/Hardening/New-HardeningSchedule.ps1
|
function New-HardeningSchedule { <# .SYNOPSIS Creates a scheduled task for automated hardening compliance verification. .DESCRIPTION Sets up recurring compliance checks via Windows Task Scheduler. Monitors system hardening status and generates reports at specified intervals. Supports: - One-time execution - Recurring schedules (daily, weekly) - Custom time intervals - Automated remediation on non-compliance - Report generation in multiple formats Tasks run with SYSTEM privilege level for full access to security settings. .PARAMETER TaskName Name for the scheduled task. Default: "WinHarden-HardeningCompliance" .PARAMETER Profile Hardening profile for scheduled verification: Basis, Recommended, Strict. Mandatory. .PARAMETER Schedule Schedule frequency: OneTime, Daily, Weekly. Mandatory. .PARAMETER Time Time of day for task execution (HH:mm format). Default: 02:00 (2 AM) .PARAMETER DayOfWeek Day of week for weekly schedules (e.g., Monday, Friday). Required for Weekly schedule. .PARAMETER AutoRemediate If specified, automatically remediate non-compliant rules. Requires admin rights. .PARAMETER GenerateReport If specified, generates compliance report after each check. Report saved to specified path. .PARAMETER ReportFormat Format for generated reports: JSON, CSV, HTML, Text. Default: HTML .PARAMETER ReportPath Directory path for saving compliance reports. Default: C:\ProgramData\WinHarden\Reports .EXAMPLE New-HardeningSchedule -Profile Recommended -Schedule Daily -Time 03:00 Creates daily compliance check at 3 AM for Recommended profile. .EXAMPLE New-HardeningSchedule -Profile Strict -Schedule Weekly -DayOfWeek Monday -AutoRemediate -GenerateReport -ReportFormat HTML Creates weekly Monday check with auto-remediation and HTML report generation. .NOTES ADMIN: Requires administrative rights to create scheduled tasks SECURITY: Script block is Base64-encoded to prevent code injection WHATIF: Supports -WhatIf parameter; no resources created in WhatIf mode DEPENDENCIES: - Write-Log (Core) – Logging - New-HardeningSession (System) – Session initialization - Invoke-SecurityHardening (System) – Apply hardening rules - Test-HardeningCompliance (System) – Compliance verification & remediation - Export-HardeningReport (System) – Report generation TASK SCHEDULER: Uses Windows Task Scheduler for recurring execution REPORTS: Generated in C:\ProgramData\WinHarden\Reports by default #> [CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] param( [Parameter(Mandatory = $false)] [string] $TaskName = "WinHarden-HardeningCompliance", [Parameter(Mandatory = $true)] [ValidateSet('Basis', 'Recommended', 'Strict')] [string] $Profile, [Parameter(Mandatory = $true)] [ValidateSet('OneTime', 'Daily', 'Weekly')] [string] $Schedule, [Parameter(Mandatory = $false)] [string] $Time = '02:00', [Parameter(Mandatory = $false)] [ValidateSet('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday')] [string] $DayOfWeek, [switch] $AutoRemediate, [switch] $GenerateReport, [Parameter(Mandatory = $false)] [ValidateSet('JSON', 'CSV', 'HTML', 'Text')] [string] $ReportFormat = 'HTML', [Parameter(Mandatory = $false)] [string] $ReportPath = 'C:\ProgramData\WinHarden\Reports' ) $ErrorActionPreference = 'Stop' try { # Validate schedule parameters if ($Schedule -eq 'Weekly' -and -not $DayOfWeek) { throw "DayOfWeek required for Weekly schedule" } # Validate time format early try { [DateTime]::ParseExact($Time, 'HH:mm', [System.Globalization.CultureInfo]::InvariantCulture) | Out-Null } catch { throw "Invalid time format. Use HH:mm (e.g., 14:30)" } # Build PowerShell script block for task (with safe parameter handling) $scriptBlock = @" # WinHarden Hardening Compliance Check Import-Module '$($PSScriptRoot | Split-Path)\modules\System.psm1' -Force `$session = New-HardeningSession -Profile 'PROFILE_PLACEHOLDER' -TargetSystem Client -SkipPrerequisiteCheck `$hardening = Invoke-SecurityHardening -Session `$session `$compliance = Test-HardeningCompliance -Session `$session Write-Output "Compliance: `$(`$compliance.CompliancePercentage)% - `$(`$compliance.Status)" REMEDIATE_PLACEHOLDER REPORT_PLACEHOLDER "@ # Replace placeholders with safe values (prevents injection) $scriptBlock = $scriptBlock -replace 'PROFILE_PLACEHOLDER', $Profile if ($AutoRemediate) { $remediateBlock = @" if (`$compliance.NonCompliantRules -gt 0) { `$remediation = Test-HardeningCompliance -Session `$session -Remediate Write-Output "Remediated `$(`$remediation.RemediatedRules.Count) non-compliant rules" } "@ $scriptBlock = $scriptBlock -replace 'REMEDIATE_PLACEHOLDER', $remediateBlock } else { $scriptBlock = $scriptBlock -replace 'REMEDIATE_PLACEHOLDER', '' } if ($GenerateReport) { $reportBlock = @" `$reportFileName = "compliance-`$(Get-Date -Format 'yyyy-MM-dd-HHmmss').$($ReportFormat.ToLower())" Export-HardeningReport -ComplianceReport `$compliance -Format '$ReportFormat' -OutputPath '$ReportPath\`$reportFileName' "@ $scriptBlock = $scriptBlock -replace 'REPORT_PLACEHOLDER', $reportBlock } else { $scriptBlock = $scriptBlock -replace 'REPORT_PLACEHOLDER', '' } # Encode script block as Base64 for secure execution (prevents code injection) $scriptBytes = [System.Text.Encoding]::Unicode.GetBytes($scriptBlock) $encodedScript = [Convert]::ToBase64String($scriptBytes) # Check WhatIf BEFORE creating resources if ($PSCmdlet.ShouldProcess($TaskName, "Create scheduled hardening task")) { Write-Log -Message "Creating hardening schedule: Task=$TaskName, Profile=$Profile, Schedule=$Schedule" -Level Info # Create report directory if generating reports (inside WhatIf block) if ($GenerateReport) { if (-not (Test-Path -Path $ReportPath)) { New-Item -ItemType Directory -Path $ReportPath -Force | Out-Null } } # Create scheduled task with Base64-encoded command (secure, no injection risk) $taskAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -WindowStyle Hidden -EncodedCommand $encodedScript" $taskTrigger = switch ($Schedule) { 'OneTime' { $triggerTime = [DateTime]::ParseExact($Time, 'HH:mm', [System.Globalization.CultureInfo]::InvariantCulture) New-ScheduledTaskTrigger -Once -At $triggerTime } 'Daily' { $triggerTime = [DateTime]::ParseExact($Time, 'HH:mm', [System.Globalization.CultureInfo]::InvariantCulture) New-ScheduledTaskTrigger -Daily -At $triggerTime } 'Weekly' { $triggerTime = [DateTime]::ParseExact($Time, 'HH:mm', [System.Globalization.CultureInfo]::InvariantCulture) New-ScheduledTaskTrigger -Weekly -DaysOfWeek $DayOfWeek -At $triggerTime } } # Create principal (SYSTEM account) $taskPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest # Create task settings $taskSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable # Register task Register-ScheduledTask -TaskName $TaskName ` -Action $taskAction ` -Trigger $taskTrigger ` -Principal $taskPrincipal ` -Settings $taskSettings ` -Force | Out-Null Write-Log -Message "Hardening schedule created: $TaskName" -Level Info Get-ScheduledTask -TaskName $TaskName } else { Write-Log -Message "Scheduled task creation cancelled by user (WhatIf)" -Level Info return } } catch { Write-ErrorLog -Message "Failed to create hardening schedule: $($_.Exception.Message)" -Caller $MyInvocation.MyCommand.Name throw } } |