Initial commit: AVWatch v1.0.0 with .gitignore and CLAUDE.md
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Register (or remove) the two Windows scheduled tasks that make AVWatch
|
||||
run by itself.
|
||||
|
||||
.DESCRIPTION
|
||||
Creates:
|
||||
"AVWatch Scan" mid-week checks. Cheap: it only asks Claude about
|
||||
versions it has never seen before, and reuses cached
|
||||
web lookups. Writes reports\latest.html. No email.
|
||||
"AVWatch Digest" the Monday briefing. Full pass, every outstanding
|
||||
update gets a verdict, then the email goes out.
|
||||
|
||||
Tasks run as the current user so they inherit your environment variables
|
||||
(API key, SMTP password). They are set to run whether or not you are
|
||||
logged in, and to start late if the machine was off at the scheduled time.
|
||||
|
||||
Run this from a normal PowerShell window -- no administrator rights are
|
||||
needed for a per-user task.
|
||||
|
||||
.EXAMPLE
|
||||
.\install_tasks.ps1
|
||||
.\install_tasks.ps1 -ScanDays Tuesday,Thursday,Saturday -ScanTime 06:00 -DigestTime 07:15
|
||||
.\install_tasks.ps1 -Remove
|
||||
#>
|
||||
[CmdletBinding()]
|
||||
param(
|
||||
[string[]]$ScanDays = @('Tuesday', 'Thursday', 'Saturday'),
|
||||
[string]$ScanTime = '06:00',
|
||||
[string]$DigestDay = 'Monday',
|
||||
[string]$DigestTime = '07:00',
|
||||
[string]$ProjectRoot,
|
||||
[switch]$Remove
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not $ProjectRoot) {
|
||||
$ProjectRoot = Split-Path -Parent $PSScriptRoot
|
||||
}
|
||||
$runner = Join-Path $ProjectRoot 'scripts\run_avwatch.ps1'
|
||||
|
||||
$scanTaskName = 'AVWatch Scan'
|
||||
$digestTaskName = 'AVWatch Digest'
|
||||
|
||||
if ($Remove) {
|
||||
foreach ($name in $scanTaskName, $digestTaskName) {
|
||||
if (Get-ScheduledTask -TaskName $name -ErrorAction SilentlyContinue) {
|
||||
Unregister-ScheduledTask -TaskName $name -Confirm:$false
|
||||
Write-Output "removed scheduled task: $name"
|
||||
} else {
|
||||
Write-Output "not present: $name"
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (-not (Test-Path $runner)) {
|
||||
throw "runner script not found: $runner"
|
||||
}
|
||||
|
||||
# --- sanity check before we schedule anything ---------------------------
|
||||
Write-Output "Checking the setup first..."
|
||||
Push-Location $ProjectRoot
|
||||
try {
|
||||
$venvPython = Join-Path $ProjectRoot '.venv\Scripts\python.exe'
|
||||
if (Test-Path $venvPython) { $python = $venvPython }
|
||||
else { $python = (Get-Command python).Source }
|
||||
& $python -m avwatch doctor
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Warning ("'avwatch doctor' reported problems (exit $LASTEXITCODE). " +
|
||||
"Scheduling anyway -- fix them and the tasks will start working.")
|
||||
}
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
$principal = New-ScheduledTaskPrincipal -UserId "$env:USERDOMAIN\$env:USERNAME" `
|
||||
-LogonType S4U -RunLevel Limited
|
||||
|
||||
$settings = New-ScheduledTaskSettingsSet `
|
||||
-StartWhenAvailable `
|
||||
-DontStopOnIdleEnd `
|
||||
-AllowStartIfOnBatteries `
|
||||
-DontStopIfGoingOnBatteries `
|
||||
-MultipleInstances IgnoreNew `
|
||||
-ExecutionTimeLimit (New-TimeSpan -Hours 3)
|
||||
|
||||
function New-AvwatchAction([string]$Command) {
|
||||
# -NoProfile keeps a slow or broken PowerShell profile out of the picture.
|
||||
$argument = ('-NoProfile -NonInteractive -ExecutionPolicy Bypass -File "{0}" ' +
|
||||
'-Command {1} -ProjectRoot "{2}"') -f $runner, $Command, $ProjectRoot
|
||||
New-ScheduledTaskAction -Execute 'powershell.exe' -Argument $argument `
|
||||
-WorkingDirectory $ProjectRoot
|
||||
}
|
||||
|
||||
# --- mid-week scans ------------------------------------------------------
|
||||
$scanTrigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek $ScanDays -At $ScanTime
|
||||
Register-ScheduledTask -TaskName $scanTaskName `
|
||||
-Action (New-AvwatchAction 'scan') `
|
||||
-Trigger $scanTrigger `
|
||||
-Principal $principal `
|
||||
-Settings $settings `
|
||||
-Description ("AVWatch: check the AV fleet for new firmware and software " +
|
||||
"releases and refresh reports\latest.html. No email.") `
|
||||
-Force | Out-Null
|
||||
Write-Output "registered: $scanTaskName ($($ScanDays -join ', ') at $ScanTime)"
|
||||
|
||||
# --- Monday digest -------------------------------------------------------
|
||||
$digestTrigger = New-ScheduledTaskTrigger -Weekly -DaysOfWeek $DigestDay -At $DigestTime
|
||||
Register-ScheduledTask -TaskName $digestTaskName `
|
||||
-Action (New-AvwatchAction 'digest') `
|
||||
-Trigger $digestTrigger `
|
||||
-Principal $principal `
|
||||
-Settings $settings `
|
||||
-Description ("AVWatch: full update-and-risk pass, then email the weekly " +
|
||||
"briefing to the recipients in config.toml.") `
|
||||
-Force | Out-Null
|
||||
Write-Output "registered: $digestTaskName ($DigestDay at $DigestTime)"
|
||||
|
||||
Write-Output ""
|
||||
Write-Output "Done. Useful commands:"
|
||||
Write-Output " Start-ScheduledTask -TaskName '$digestTaskName' # run the digest now"
|
||||
Write-Output " Get-ScheduledTaskInfo -TaskName '$digestTaskName' # last run time and result"
|
||||
Write-Output " Get-ChildItem '$ProjectRoot\logs' | Sort LastWriteTime -Desc | Select -First 5"
|
||||
Write-Output ""
|
||||
Write-Output "Secrets must be set as USER environment variables so the tasks"
|
||||
Write-Output "inherit them. For example:"
|
||||
Write-Output ' setx ANTHROPIC_API_KEY "sk-ant-..."'
|
||||
Write-Output ' setx AVWATCH_SMTP_PASSWORD "your-app-password"'
|
||||
Write-Output "Open a new shell after setx before testing."
|
||||
Reference in New Issue
Block a user