foam_sync.ps1 (LIFEBALANCE) 2025-06-19T00:26:39Z

This commit is contained in:
Ben Miller
2025-06-19 00:26:39 -06:00
parent d10c85b295
commit 80a98b4fdd

View File

@ -50,30 +50,43 @@ $taskDescription = "Periodically synchronizes the Git repository at $scriptDir u
$taskPrincipal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive $taskPrincipal = New-ScheduledTaskPrincipal -UserId $env:USERNAME -LogonType Interactive
# Trigger configuration # Trigger configuration
$trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $frequencyMinutes) $trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes $frequencyMinutes) -RepetitionDuration ([TimeSpan]::MaxValue)
# Action configuration: # Action configuration:
# We use an indirection technique to ensure the window is truly hidden. # We use an indirection technique to ensure the window is truly hidden.
# The scheduled task launches an initial PowerShell. # The scheduled task launches an initial PowerShell.
# This initial PowerShell then uses Start-Process to launch the *actual* script in a new, hidden PowerShell process. # This initial PowerShell then uses Start-Process to launch the *actual* script in a new, hidden PowerShell process.
# 1. Path to the script, with internal double quotes escaped as "" (for the -File parameter of the innermost PowerShell) # 1. Innermost PowerShell's -File argument: Path to the script, with internal double quotes escaped as ""
# e.g., \"C:\path\to your script.ps1\"
$scriptPathForInnermostFileParam = $scriptPath.Replace('"', '""') $scriptPathForInnermostFileParam = $scriptPath.Replace('"', '""')
$innermostFileArg = "\`"$scriptPathForInnermostFileParam\`""
# 2. Argument string for the innermost PowerShell instance (the one executing the actual script) # 2. Argument string for the innermost PowerShell instance (the one executing the actual script)
$innermostPSArgs = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File \`"$scriptPathForInnermostFileParam\`"" # e.g., -NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"C:\path\to your script.ps1\"
$innermostPSArgs = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -File $innermostFileArg"
# 3. The innermostPSArgs string needs its single quotes escaped (as '') because it will be wrapped in single quotes for Start-Process's -ArgumentList # 3. The innermostPSArgs string needs its single quotes escaped (as '') because it will be wrapped in single quotes for Start-Process's -ArgumentList
$innermostPSArgsEscapedForStartProcess = $innermostPSArgs.Replace("'", "''") $innermostPSArgsEscapedForStartProcess = $innermostPSArgs.Replace("'", "''")
# 4. Command to be executed by the intermediate PowerShell (launched by Task Scheduler). This command uses Start-Process. # 4. Command string that the first PowerShell instance (launched by Task Scheduler) will execute using Start-Process.
$commandForIntermediatePS = "Start-Process -FilePath powershell.exe -ArgumentList '$innermostPSArgsEscapedForStartProcess' -WindowStyle Hidden" # e.g., Start-Process -FilePath powershell.exe -ArgumentList '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"C:\path\to your script.ps1\"' -WindowStyle Hidden
$taskActionArgument = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -Command \`"$($commandForIntermediatePS.Replace('"', '`"'))\`"" # Escape " in command as `"` $commandToRunViaStartProcess = "Start-Process -FilePath powershell.exe -ArgumentList '$innermostPSArgsEscapedForStartProcess' -WindowStyle Hidden"
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $taskActionArgument # 5. Argument string FOR THE TASK SCHEDULER to pass to the first powershell.exe.
# The $commandToRunViaStartProcess is the value for -Command, and needs to be quoted for registration.
# e.g., -NoProfile -NonInteractive -ExecutionPolicy Bypass -Command "Start-Process -FilePath powershell.exe -ArgumentList '-NoProfile -NonInteractive -ExecutionPolicy Bypass -File \"C:\path\to your script.ps1\"' -WindowStyle Hidden"
$actionArgumentForRegistration = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -Command \`"$commandToRunViaStartProcess\`""
# 6. Expected argument string WHEN RETRIEVED by Get-ScheduledTask.
# Task Scheduler/PowerShell often strips the outermost quotes from the -Command value when retrieved.
$expectedRetrievedActionArgument = "-NoProfile -NonInteractive -ExecutionPolicy Bypass -Command $commandToRunViaStartProcess"
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument $actionArgumentForRegistration
# Task settings # Task settings
$settings = New-ScheduledTaskSettingsSet -ExecutionTimeLimit (New-TimeSpan -Minutes 1) $settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit (New-TimeSpan -Hours 1) `
-StopIfGoingOnBatteries:$false # Explicitly ensure it doesn't stop
# Check and configure the scheduled task # Check and configure the scheduled task
try { try {
@ -85,16 +98,18 @@ try {
$currentTrigger = $existingTask.Triggers[0] $currentTrigger = $existingTask.Triggers[0]
$currentAction = $existingTask.Actions[0] $currentAction = $existingTask.Actions[0]
# Check Trigger
$triggerMatches = $false $triggerMatches = $false
if ($currentTrigger -is [Microsoft.Management.Infrastructure.CimInstance] ` if ($currentTrigger -is [Microsoft.Management.Infrastructure.CimInstance] `
-and $currentTrigger.RepetitionInterval.TotalMinutes -eq $frequencyMinutes) { -and $currentTrigger.RepetitionInterval.TotalMinutes -eq $frequencyMinutes `
-and $currentTrigger.RepetitionDuration -eq ([TimeSpan]::MaxValue)) {
# Check duration too
$triggerMatches = $true $triggerMatches = $true
} }
$actionMatches = $false $actionMatches = $false
if ($currentAction -is [Microsoft.Management.Infrastructure.CimInstance] ` if ($currentAction -is [Microsoft.Management.Infrastructure.CimInstance] `
-and $currentAction.Execute -eq "powershell.exe" ` -and $currentAction.Execute -eq "powershell.exe" `
-and $currentAction.Argument -eq $taskActionArgument) { -and $currentAction.Argument -eq $expectedRetrievedActionArgument) { # Compare with the expected retrieved format
$actionMatches = $true $actionMatches = $true
} }