From 631a7fd404d7a4b9f839d677b8f4c5a8761690e1 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Sat, 15 Aug 2026 10:23:47 +0900 Subject: [PATCH] fix(windows): trust scheduled task module during elevation --- src/lib/windows-elevation.ts | 10 ++++++++-- tests/windows-elevation-spawn.test.ts | 8 +++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/lib/windows-elevation.ts b/src/lib/windows-elevation.ts index 36dae55bd8..a07331fbce 100644 --- a/src/lib/windows-elevation.ts +++ b/src/lib/windows-elevation.ts @@ -622,15 +622,21 @@ export function runWindowsElevatedScheduledTaskRegistration( xml: string, ): Promise { const xmlBase64 = Buffer.from(xml, "utf16le").toString("base64"); + const powerShellPath = windowsPowerShell(); + const powerShellDirectory = powerShellPath.replace(/[\\/][^\\/]+$/, ""); + const scheduledTasksModule = `${powerShellDirectory}\\Modules\\ScheduledTasks\\ScheduledTasks.psd1`; const inner = [ `$taskName = ${psSingleQuote(taskName)}`, `$xmlBase64 = ${psSingleQuote(xmlBase64)}`, "$xml = [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($xmlBase64))", - "Register-ScheduledTask -TaskName $taskName -Xml $xml -Force -ErrorAction Stop | Out-Null", + `$module = Microsoft.PowerShell.Core\\Import-Module -Name ${psSingleQuote(scheduledTasksModule)} -PassThru -Force -ErrorAction Stop`, + "$registerTask = $module.ExportedCommands['Register-ScheduledTask']", + "if ($null -eq $registerTask) { throw 'Trusted ScheduledTasks module does not export Register-ScheduledTask.' }", + "& $registerTask -TaskName $taskName -Xml $xml -Force -ErrorAction Stop | Out-Null", ].join("; "); const encodedCommand = Buffer.from(inner, "utf16le").toString("base64"); const script = [ - `$p = Start-Process -FilePath ${psSingleQuote(windowsPowerShell())}`, + `$p = Start-Process -FilePath ${psSingleQuote(powerShellPath)}`, ` -ArgumentList ${psSingleQuote(buildWindowsElevatedArgumentList([ "-NoProfile", "-NonInteractive", diff --git a/tests/windows-elevation-spawn.test.ts b/tests/windows-elevation-spawn.test.ts index 1eff2dddb0..90feec95ca 100644 --- a/tests/windows-elevation-spawn.test.ts +++ b/tests/windows-elevation-spawn.test.ts @@ -146,7 +146,13 @@ describe("runWindowsElevated spawn contract", () => { const match = /-EncodedCommand ([A-Za-z0-9+/=]+)/.exec(commandScript); expect(match).not.toBeNull(); const elevatedScript = Buffer.from(match![1]!, "base64").toString("utf16le"); - expect(elevatedScript).toContain("Register-ScheduledTask -TaskName $taskName -Xml $xml -Force"); + expect(elevatedScript).toContain( + "C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\Modules\\ScheduledTasks\\ScheduledTasks.psd1", + ); + expect(elevatedScript).toContain("Microsoft.PowerShell.Core\\Import-Module"); + expect(elevatedScript).toContain("$module.ExportedCommands['Register-ScheduledTask']"); + expect(elevatedScript).toContain("& $registerTask -TaskName $taskName -Xml $xml -Force"); + expect(elevatedScript).not.toMatch(/(^|[; ]+)Register-ScheduledTask\s+-TaskName/); expect(elevatedScript).toContain(Buffer.from(xml, "utf16le").toString("base64")); expect(commandScript).not.toContain("/xml"); expect(commandScript).not.toContain("task.xml");