Files
powershell-scripts/remote-execution/Schedule-Maintenance.ps1
cproudlock 847ec402bd Add scheduled maintenance, PC list export, and subnet scanner scripts
- Schedule-Maintenance.ps1: DPAPI credential storage + Task Scheduler integration
- Export-PCList.ps1: Pull PC lists from ShopDB API with type/BU filtering
- Find-ShopfloorPCs.ps1: Parallel subnet scanner with WinRM and DNS checks
- INSTRUCTIONS.txt: Schedule-Maintenance.ps1 documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 14:58:18 -05:00

209 lines
8.4 KiB
PowerShell

<#
.SYNOPSIS
Wrapper for running Invoke-RemoteMaintenance.ps1 unattended via Task Scheduler.
.DESCRIPTION
Stores credentials securely using Windows DPAPI (encrypted to your user account)
and runs maintenance tasks without interactive prompts.
First run: use -SaveCredential to store your username/password.
Subsequent runs (or Task Scheduler): credentials load automatically.
.PARAMETER SaveCredential
Prompt to save credentials for future unattended use.
.PARAMETER Task
Maintenance task to run (passed to Invoke-RemoteMaintenance.ps1).
.PARAMETER ComputerListFile
Path to PC list file (passed to Invoke-RemoteMaintenance.ps1).
.PARAMETER CreateScheduledTask
Register a Windows Scheduled Task to run this script on a schedule.
.PARAMETER TaskTime
Time for the scheduled task (default: 03:00 AM).
.PARAMETER TaskFrequency
How often to run: Daily, Weekly, or Once (default: Weekly).
.PARAMETER TaskDay
Day of week for Weekly frequency (default: Sunday).
.EXAMPLE
# Step 1: Save your credentials (one time, interactive)
.\Schedule-Maintenance.ps1 -SaveCredential
.EXAMPLE
# Step 2: Test unattended run
.\Schedule-Maintenance.ps1 -ComputerListFile ".\shopfloor-pcs.txt" -Task Reboot
.EXAMPLE
# Step 3: Create a scheduled task for weekly reboots
.\Schedule-Maintenance.ps1 -CreateScheduledTask -ComputerListFile ".\shopfloor-pcs.txt" -Task Reboot -TaskFrequency Weekly -TaskDay Sunday -TaskTime "03:00"
#>
[CmdletBinding()]
param(
[switch]$SaveCredential,
[string]$Task,
[string]$ComputerListFile,
[switch]$CreateScheduledTask,
[string]$TaskTime = "03:00",
[ValidateSet('Daily','Weekly','Once')]
[string]$TaskFrequency = "Weekly",
[ValidateSet('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday')]
[string]$TaskDay = "Sunday",
[string]$TaskDate,
[string]$Username,
[string]$Password
)
$credFile = Join-Path $PSScriptRoot ".maintenance-cred.xml"
$scriptDir = $PSScriptRoot
# ---------------------------------------------------------------------------
# Save credentials (DPAPI - only decryptable by this user on this machine)
# ---------------------------------------------------------------------------
if ($SaveCredential) {
if ($Username -and $Password) {
$secPass = ConvertTo-SecureString $Password -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($Username, $secPass)
} else {
Write-Host "Enter the credentials used to connect to remote shopfloor PCs:" -ForegroundColor Cyan
Write-Host "If no prompt appears, re-run with: -Username 'DOMAIN\user' -Password 'pass'" -ForegroundColor Yellow
$cred = Get-Credential -Message "Enter admin credentials for remote shopfloor PCs"
}
if (-not $cred) {
Write-Host "No credentials provided. Exiting." -ForegroundColor Red
exit 1
}
$cred | Export-Clixml -Path $credFile
Write-Host "Credentials saved to: $credFile" -ForegroundColor Green
Write-Host "Encrypted with DPAPI - only YOUR user account on THIS machine can decrypt them." -ForegroundColor Yellow
Write-Host ""
Write-Host "You can now run tasks unattended:" -ForegroundColor Cyan
Write-Host " .\Schedule-Maintenance.ps1 -ComputerListFile '.\shopfloor-pcs.txt' -Task Reboot"
exit 0
}
# ---------------------------------------------------------------------------
# Create Scheduled Task
# ---------------------------------------------------------------------------
if ($CreateScheduledTask) {
if (-not $Task) {
Write-Host "ERROR: -Task is required when creating a scheduled task." -ForegroundColor Red
exit 1
}
if (-not $ComputerListFile) {
Write-Host "ERROR: -ComputerListFile is required when creating a scheduled task." -ForegroundColor Red
exit 1
}
# Resolve to absolute paths
$absListFile = (Resolve-Path $ComputerListFile -ErrorAction Stop).Path
$absScript = Join-Path $scriptDir "Schedule-Maintenance.ps1"
if (-not (Test-Path $credFile)) {
Write-Host "ERROR: No saved credentials found. Run with -SaveCredential first." -ForegroundColor Red
exit 1
}
$taskName = "ShopfloorMaintenance-$Task"
$psArgs = "-NoProfile -ExecutionPolicy Bypass -File `"$absScript`" -Task `"$Task`" -ComputerListFile `"$absListFile`""
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $psArgs -WorkingDirectory $scriptDir
$triggerTime = if ($TaskDate) {
[DateTime]::Parse("$TaskDate $TaskTime")
} else {
[DateTime]::Parse($TaskTime)
}
$trigger = switch ($TaskFrequency) {
'Daily' { New-ScheduledTaskTrigger -Daily -At $triggerTime }
'Weekly' { New-ScheduledTaskTrigger -Weekly -DaysOfWeek $TaskDay -At $triggerTime }
'Once' { New-ScheduledTaskTrigger -Once -At $triggerTime }
}
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable -RunOnlyIfNetworkAvailable
# Register as current user (needed for DPAPI credential decryption)
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
Write-Host "Creating scheduled task '$taskName' as $currentUser..." -ForegroundColor Cyan
Write-Host " Schedule: $TaskFrequency at $TaskTime$(if ($TaskFrequency -eq 'Weekly') { " ($TaskDay)" })" -ForegroundColor Gray
Write-Host " Task: $Task" -ForegroundColor Gray
Write-Host " PC List: $absListFile" -ForegroundColor Gray
$existingTask = Get-ScheduledTask -TaskName $taskName -ErrorAction SilentlyContinue
if ($existingTask) {
Write-Host "Task '$taskName' already exists. Updating..." -ForegroundColor Yellow
Set-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings | Out-Null
} else {
Register-ScheduledTask -TaskName $taskName -Action $action -Trigger $trigger -Settings $settings -User $currentUser -RunLevel Highest -Description "Shopfloor PC Maintenance - $Task (via Invoke-RemoteMaintenance.ps1)" | Out-Null
}
Write-Host "Scheduled task '$taskName' created successfully." -ForegroundColor Green
Write-Host ""
Write-Host "Manage in Task Scheduler or with:" -ForegroundColor Cyan
Write-Host " Get-ScheduledTask -TaskName '$taskName'"
Write-Host " Start-ScheduledTask -TaskName '$taskName' # run now"
Write-Host " Unregister-ScheduledTask -TaskName '$taskName' # delete"
exit 0
}
# ---------------------------------------------------------------------------
# Run maintenance (unattended)
# ---------------------------------------------------------------------------
if (-not $Task) {
Write-Host "ERROR: -Task is required. Example: -Task Reboot" -ForegroundColor Red
Write-Host " Or use -SaveCredential to store credentials first." -ForegroundColor Yellow
Write-Host " Or use -CreateScheduledTask to set up a scheduled run." -ForegroundColor Yellow
exit 1
}
if (-not $ComputerListFile) {
Write-Host "ERROR: -ComputerListFile is required." -ForegroundColor Red
exit 1
}
# Load saved credentials
if (-not (Test-Path $credFile)) {
Write-Host "ERROR: No saved credentials found at $credFile" -ForegroundColor Red
Write-Host "Run with -SaveCredential first to store credentials." -ForegroundColor Yellow
exit 1
}
try {
$cred = Import-Clixml -Path $credFile
Write-Host "Loaded saved credentials for: $($cred.UserName)" -ForegroundColor Green
} catch {
Write-Host "ERROR: Failed to load credentials: $_" -ForegroundColor Red
Write-Host "Re-run with -SaveCredential to save new credentials." -ForegroundColor Yellow
exit 1
}
# Log output
$logDir = Join-Path $scriptDir "logs"
if (-not (Test-Path $logDir)) { New-Item -Path $logDir -ItemType Directory -Force | Out-Null }
$logFile = Join-Path $logDir "maintenance-$(Get-Date -Format 'yyyy-MM-dd_HHmmss')-$Task.log"
Write-Host "Running: Invoke-RemoteMaintenance.ps1 -Task $Task -ComputerListFile $ComputerListFile" -ForegroundColor Cyan
Write-Host "Log: $logFile" -ForegroundColor Gray
$mainScript = Join-Path $scriptDir "Invoke-RemoteMaintenance.ps1"
& $mainScript -ComputerListFile $ComputerListFile -Task $Task -Credential $cred 2>&1 | Tee-Object -FilePath $logFile
Write-Host ""
Write-Host "Complete. Log saved to: $logFile" -ForegroundColor Green