Как избежать аргументов schtasks / tr - PullRequest
3 голосов
/ 18 марта 2019

Мне нужно запланировать задачу PowerShell следующим образом:

powershell.exe -file ..\Execute\execute.ps1

И я попытался присвоить его аргументу $Argument, а затем передать его schtasks следующим образом:

$Argument = "powershell.exe -file '..\Execute\execute.ps1'"
schtasks /create /tn "SOE_Checks" /tr $Argument /sc DAILY /st 05:00 /ru "System" /rl HIGHEST /f

но после запуска вышеуказанного кода ничего не произошло - пока задача создается успешно, она, похоже, не запускается.

Я также пытался присвоить его $Argument без кавычек, оно работало, но я получил следующие предупреждения:

ERROR: Invalid syntax. Value expected for '/tr'.
Type "SCHTASKS /CREATE /?" for usage.

Может кто-нибудь, пожалуйста, дайте мне знать, что я здесь сделал неправильно? (Я знаю, что могу сделать это с помощью PowerShell New-ScheduledTaskAction, но я хочу, чтобы он работал таким образом)

Просто хочу добавить, что если я изменю путь к файлу в определенном месте в $Argument, например,
$Argument = "powershell.exe -file 'C:\SOE\Execute\execute.ps1'", он будет работать без каких-либо предупреждений, но это не идеально.

Я прочитал это , но у меня это не работает

1 Ответ

2 голосов
/ 18 марта 2019

Запланированные задачи, созданные с помощью schtasks.exe, выполняются с рабочим каталогом , установленным на $env:windir\system32 [1] , поэтому, если ваш сценарий не окажется в ..\Execute\execute.ps1 относительно там , ваша команда не будет работать должным образом.

Если вы не хотите жестко закодировать путь сценария непосредственно в команду, создайте команду динамически , разрешив относительный путь к absolute . при назначении на $Argument:

$Argument = 'powershell.exe -file \"{0}\"' -f (Convert-Path ..\Execute\execute.ps1)

Обратите внимание, что, к сожалению, необходимо скрыть встроенную " как \", которая является давней ошибкой, которая не была исправлена ​​ради обратной совместимости - см. эту проблему с документацией GitHub для фона.

Convert-Path разрешает относительный путь к абсолютному.
Обратите внимание, что относительный путь должен указывать на существующий файл (или каталог).

Аналогично, относительные пути внутри ваш скрипт будет относительно $env:windir\system32 тоже ; чтобы сделать их относительно директории script , сначала перейдите в каталог вашего скрипта, выполнив Set-Location $PSScriptRoot в начале вашего скрипта.


Необязательное чтение: Как процитировать команды, запускаемые из запланированной задачи:

Примечание. Практически применяются те же правила , что и при запуске команды из диалогового окна Windows Run (нажмите WinKey + R ), что вас можно использовать для test-drive команду (команду для передачи на schtasks /tr без внешней кавычки, а не всю командную строку schtasks), хотя обратите внимание, что рабочий каталог будет домашний каталог пользователя, и что вы не сможете использовать '...' -квотирование вокруг аргумента -File CLI PowerShell - см. ниже):

  • cmd.exe НЕ задействован во время выполнения, что означает:

    • Вам не нужно беспокоиться об использовании метасимволов cmd.exe без двойных кавычек, таких как, например, &, так что вы можете использовать эти символы даже в одиночных строках в кавычках передан в PowerShell CLI powershell.exe как (часть) аргумента (ов) -Command.

    • И наоборот, перенаправления вывода (например, > c:\path\to\log.txt) не поддерживаются напрямую .

    • В контексте вызова интерфейса командной строки PowerShell это означает:

      • С -File вы не можете использовать их в командной строке и вместо этого должны выполнять их из в вашего скрипта.

      • С -Command, однако, вы можете использовать их, потому что тогда их применяет PowerShell (но учтите, что оператор Windows PowerShell > создает UTF) -16LE файлов).

  • (хотя cmd.exe не задействован) ссылки на переменные окружения , использующие ту же синтаксическую форму, что и в cmd.exe , расширен (например, %USERNAME%)

    • Предостережение : Вы не можете избежать таких ссылок :
    • %% не работает - дополнительный % просто обрабатывается как литерал, и расширение по-прежнему происходит; например, %%OS%% приводит к %Windows_NT%.
    • ^% (случайно) предотвращает расширение, но сохраняет ^ - ^ не escape ; скорее он «разрушает» имя переменной, и в этом случае токен остается без изменений; например, ^%OS^% приводит к ^%OS^%, то есть сохраняется как есть.

Вышеприведенное относится к командам, так как они должны заканчиваться , определенными внутри запланированной задачи, как вы могли бы видеть или определять их в интерактивном режиме в планировщике задач (taskschd.msc).

Дополнительно , для создания запланированного задания из командной строки / сценария PowerShell / командного файла :

  • вы должны процитировать команду в целом и

  • соответствуют правилам синтаксиса вызывающей оболочки относительно экранирования и прямой интерполяции строк.

(Вы можете уйти только без цитированияесли команда состоит только из одиночного слова , которое не требует экранирования, например пути к исполняемому файлу, не содержащему пробелов или специальных символов и к которому не передаются аргументы.)

При вызовеschtasks.exe [2] , процитируйте аргумент /tr в целом следующим образом :

  • из PowerShell , используйте "...", если вам нужно расширить (строка-интерполировать) командную строку вперед ;в противном случае используйте '...'.
    Важно : необходимость экранирования вложенного " в качестве \" применяется в обоих случаях, что в случае внешнего "..."цитирование означает, что вложенный " должен быть экранирован как \`" (sic).

    • Удивительно, но schtasks.exe распознает внедренное '...' цитирование и автоматически переводитэто "..." цитирование - именно поэтому ваша исходная команда "powershell.exe -file '..\Execute\execute.ps1'" сработала, хотя при прямом вызове PowerShell CLI не поддерживает использование '...' в сочетании с -File.
  • из cmd.exe (напрямую или из пакетного файла), вы должны использование "...".

Примеры PowerShell :

  • Следующие команды PowerShell создают и выполняют две команды запуска.запланированные задачи с именами test1 и test2, которые запускаются, когда начинается следующая календарная минута, в контексте вызывающего пользователя, визуально.(После этого вам придется удалить эти задачи вручную.)

  • Возможно, вам придется подождать до 1 минуты, чтобы увидеть активацию вызова, после чего появится новое окно консоли.для каждой задачи.

# Create sample script test.ps1 in the current dir. that
# echoes its arguments and then waits for a keypress.
'"Hi, $Args."; Read-Host "Press ENTER to exit"' > test.ps1

# Find the start of the next calendar minute.
$nextFullMinute = ([datetime]::Now.AddMinutes(1).TimeOfDay.ToString('hh\:mm'))

# -File example:
# Invoke test.ps1 and pass it 'foo' as an argument.
# Note the escaped embedded "..." quoting around the script path
# and that with -File you can only pass literal arguments at 
# invocation time).
schtasks.exe /create /f /tn test1 /sc once /st $nextFullMinute `
  /tr "powershell -File \`"$PWD/test.ps1\`" foo"                                                                            #`# (dummy comment to fix broken syntax highlighting)

# -Command example:
# Invoke test.ps1 and pass it $env:USERNAME as an argument.
# Note the '...' around the script path and the need to invoke it with
# &, as well as the ` before $env:USERNAME to prevent its premature expansion.
schtasks.exe /create /f /tn test2 /sc once /st $nextFullMinute `
  /tr "powershell -Command & '$PWD/test.ps1' `$env:USERNAME"

"Tasks will execute at ${nextFullMinute}:00"

[1] Обратите внимание, что графический интерфейс планировщика заданий позволяет настраивать рабочий каталог, но эта функция недоступнас помощью утилиты schtasks.exe.

[2] То же самое относится к значениям, передаваемым параметру -Argument командлета New-ScheduledTaskAction PowerShell, хотя следует учитывать, что имя / путь к исполняемому файлутам указывается отдельно через параметр -Execute.
Для сравнения: командлет Register-ScheduledJob для создания запланированных PowerShell заданий принимает блок сценариев в качестве команды для запуска,который устраняет головную боль цитирования.

...