Создан модуль PowerShell, он имеет функцию и предоставляет командлет для этой функции. встроенный PowerShell 5.1 и pwsh.exe 7.3.1 (устанавливается с помощью установщика MSI) могут без проблем обнаружить и запустить командлет.
теперь мне нужен этот командлет для «запуска независимо от того, вошел ли пользователь в систему или нет» в планировщике задач Windows.
проблема возникает, когда я пытаюсь запустить командлет моего модуля PowerShell как NT AUTHORITY\SYSTEM
.
Что мне нужно сделать, потому что в планировщике задач это кажется единственным способом получить запланированное задание «запускаться независимо от того, вошел ли пользователь в систему или нет». (Я не хочу вручную вводить имя пользователя или пароль любой учетной записи пользователя Windows)
В идеале я бы предпочел использовать встроенную группу безопасности администраторов, но, как вы видите, я не смогу запустить задачу, если пользователь не вошел в систему.
поэтому я действительно застрял здесь, не зная, что делать. Я предполагаю, что это один из крайних случаев, с которыми я сталкиваюсь.
Мне нужно найти способ, чтобы, когда PowerShell работает как SYSTEM, он по-прежнему мог обнаруживать командлет моего модуля.
Я знаю, что мой командлет не обнаруживается, когда PowerShell работает как SYSTEM, потому что я тестировал его с помощью PsExec64.
Я поместил сюда свой модуль PowerShell (именно там они устанавливаются по умолчанию из онлайн-галерей):
C:\Users\<UserName>\OneDrive\Documents\PowerShell\Modules\ModuleFolder
Это весь блок сценария PowerShell, который я использую для создания своей задачи.
$action = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-command 'myCmdLet -parameter1 $variable1"
# First thing I tried
$TaskPrincipal = New-ScheduledTaskPrincipal -GroupId "BUILTIN\Administrators" -RunLevel Highest
# Second thing I tried
$TaskPrincipal = New-ScheduledTaskPrincipal -UserID "NT AUTHORITY\SYSTEM" -LogonType ServiceAccount -RunLevel Highest
$trigger = New-ScheduledTaskTrigger -AtStartup
Register-ScheduledTask -Action $action -Trigger $trigger -Principal $TaskPrincipal -TaskName "Name" -Description "Description"
$TaskSettings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -Compatibility Win8 -StartWhenAvailable
Set-ScheduledTask -TaskName "Name" -Settings $TaskSettings
ОБНОВЛЯТЬ:
Я нашла способ:
$TaskPrincipal = New-ScheduledTaskPrincipal -LogonType S4U -UserId $env:USERNAME -RunLevel Highest
который запускает задачу от имени администратора (поскольку командлет модуля не будет работать даже без прав администратора), а также проверяет эти 2 поля, которые я действительно хотел сделать. тем не менее, я все еще ищу способ сделать командлет моего модуля известным PowerShell, когда он работает как SYSTEM, он предоставит 1 преимущество, AFAIK, которое заключается в удалении зависимости от конкретной учетной записи пользователя, существующей на компьютере.
Я не могу. модуль, который я делаю, требует ввода от пользователя, после того, как эти входы будут введены с помощью командлета модуля, будут запущены команды, а затем будет создана задача с этими входами в планировщике задач Windows, которую мне нужно запустить независимо от того, какие пользователь вошел в систему. поэтому сам файл модуля, который находится там, не имеет никаких входных данных и имеет только функцию, которая принимает параметры. Я не понимаю, почему для PowerShell нет надлежащего официального параметра, чтобы установить флажок для Run whether user is logged on or not
и Do not store password The task will only have access to local resources
Я не понимаю: предлагаемый вызов Import-Module
просто сделал бы автоматический импорт вашего модуля, на который вы сейчас пытаетесь положиться, явным. По определению вы пытаетесь работать не в интерактивном режиме, верно?
Извините, позвольте мне попробовать еще раз, я создал модуль, загрузил его в галерею PowerShell, пользователь А установит его с помощью командлета Install-Module
в обычном окне PowerShell. он будет установлен по умолчанию в C:\Users\<username>\OneDrive\Documents\PowerShell\Modules
. пользователь A запустит мой модуль с помощью командлета, который он предоставляет, и передаст ему параметры. модуль запускается и выполняет свою работу, в конце необходимо создать запланированное задание, чтобы пользователю не нужно было снова повторять процесс запуска командлета с параметрами. задача, которую он создает, должна выполняться независимо от того, вошел ли пользователь в систему или не запрашивать pwd.
Помимо противоречия в «модуль, который я делаю, требует ввода от пользователя» и «запускается независимо от того, вошел ли пользователь в систему или нет». Учетная запись SYSTEM не должна взаимодействовать с пользователем, поскольку она представляет угрозу безопасности. Любые попытки в этом направлении будут либо запрещены, либо инициировать UAC (как в случае с PSExec). Связь между этими учетными записями может / должна осуществляться только отдельными процессами через небольшие каналы, такие как реестр или файлы, содержащие безопасные настройки, избегая всего, что является исполняемым.
@iRon Lol, в части противоречия, это многоцелевой модуль, который требует ввода хотя бы один раз от пользователя, после чего его необходимо запускать регулярно. в любом случае, да, вы правы, я имею в виду, что мне пришлось отключить правило ASR Block process creations originating from PSExec and WMI commands
, прежде чем я смог протестировать свой модуль с помощью PSExec. так вы говорите, что я должен забыть о попытке запустить командлет моего модуля как SYSTEM в планировщике задач, и мой лучший вариант — продолжить с -LogonType S4U -UserId $env:USERNAME -RunLevel Highest
?
Почему модуль «требует ввода хотя бы один раз от пользователя»?
Проще говоря, PS ищет модули в указанных каталогах. Если вы устанавливаете для пользователя, он помещается в каталог профиля пользователя, СИСТЕМА не может «увидеть» там ваш модуль. Вы должны установить модуль для «Всех пользователей», который помещает его в системный каталог, чтобы ВСЕ пользователи могли получить к нему доступ. Будет ли это работать даже тогда, сомнительно.
@Bill_Stewart, потому что я так это сделал и как это работает. @Scepticalist большое спасибо, это в значительной степени отвечает на мой вопрос и помечает его как решенный. Я нашел параметр -scope
install-module
, по этой ссылке представлена вся информация: Learn.microsoft.com/en-us/powershell/module/powershellget/…
Я предполагаю, что то, что вы хотите сделать, можно сделать только в приложении с уровнем манифеста, но снова; Неподписанные манифесты могут упростить разработку и тестирование вашего приложения. Однако неподписанные манифесты создают существенную угрозу безопасности в производственной среде. Рассмотрите возможность использования неподписанных манифестов только в том случае, если ваше приложение ClickOnce работает на компьютерах в интрасети, которая полностью изолирована от Интернета или других источников вредоносного кода.
"потому что так я сделал и так оно и работает" - мне кажется, что это хороший повод рассмотреть конструкцию, которая этого не требует.
Обобщить:
Ваша проблема заключалась в том, что модуль, который вы хотите использовать в своей запланированной задаче, был установлен в области действия текущего пользователя, что не увидит задача, запущенная от имени другого пользователя, например NT AUTORITY\SYSTEM.
Самое простое решение — установить модуль для всех пользователей с помощью аргумента -Scope AllUsers
, переданного в Install-Module (требуется повышение прав).
Однако есть решение, даже если это невозможно или нежелательно, а именно передать полный путь к модулю явному вызову Import-Module, выполняемому в контексте задачи, как показано ниже.
Поскольку ваша задача должна выполняться с повышением прав, как вы утверждаете, запуск в контексте текущего пользователя возможен только в том случае, если этот пользователь является администратором; как вы обнаружили, вы можете настроить это следующим образом (требуется повышение):
$taskPrincipal =
New-ScheduledTaskPrincipal -LogonType S4U -UserId $env:USERNAME -RunLevel Highest
Запуск задачи от имени пользователя NT AUTORITY\SYSTEM
неизменно запускается:
-LogonType Service
.C:\Windows\System32
в качестве рабочего директора по умолчанию<hostname>$
, отраженным в $env:USERNAME
, где <hostname>
— имя локальной машины, а $HOME
/ $env:USERPROFILE
папка C:\Windows\system32\config\systemprofile
.Следующий автономный пример:
NT AUTHORITY\SYSTEM
~/_test.psm1
и ~/_test.txt
, а временная задача называется _Test
)#requires -RunAsAdministrator
# Abort on any error.
# Note: Since the *-ScheduledTask* cmdlets are implemented as
# CDXML-based *script* modules, they only see preference vars.
# in the *global* scope - see https://github.com/PowerShell/PowerShell/issues/4568
$prevEaPref = $global:ErrorActionPreference
$global:ErrorActionPreference = 'Stop'
try {
# Create a simple script module that exports function Get-Foo,
# in the current user's home dir., named '_test.psm1'
@'
function Get-Foo { "Hi, I'm running at $(Get-Date)`n * as $env:USERNAME (whose home dir. is '$HOME')`n * in '$PWD'`n * $(('NON-elevated', 'ELEVATED')[[bool] (net session 2>$null)])." }
'@ > ~/_test.psm1
# Set up the scheduled task:
# The command (program) to run.
# Import the test-module via its full path, call Get-Foo, and redirect all output streams
# to file '_test.txt' in the current users' home dir.
$action = New-ScheduledTaskAction -Execute powershell -Argument "-ExecutionPolicy Bypass -NoProfile -Command & { Import-Module `"$((Get-Item ~/_test.psm1).FullName)`"; Get-Foo } *> `"$((Get-Item ~).FullName)\_test.txt`""
# Run as 'NT AUTHORITY\SYSTEM', which runs:
# * invisibly
# * whether or not someone is logged on
# * implicitly with elevation
$user = New-ScheduledTaskPrincipal -UserID 'NT AUTHORITY\SYSTEM' -LogonType ServiceAccount
# # Advanced settings such as whether to allow start on demand, not running when on batter power, ...
# $settings = New-ScheduledTaskSettingsSet
# When to run it: Run a few seconds from now, once.
$secsFromNow = 5
$when = (Get-Date).AddSeconds($secsFromNow)
$trigger = New-ScheduledTaskTrigger -Once -At $when
# Create the task from the above.
$newTask = New-ScheduledTask -Action $action -Principal $user -Trigger $trigger
# Register the task with name '_Test'
Write-Verbose -Verbose "Creating task..."
Register-ScheduledTask '_Test' -InputObject $newTask -Force
Write-Verbose -Verbose "Task will execute invisibly in $secsFromNow seconds, running as 'NT AUTHORITY\SYSTEM'. Waiting (plus a few extra seconds)..."
Start-Sleep ($secsFromNow + 5) # Wait an extra few seconds to give the task time to complete.
Write-Verbose -Verbose "Task is assumed to have run. Output logged:"
Get-Content ~/_test.txt
}
finally {
# Clean up.
Remove-Item -ErrorAction Ignore ~/_test.psm1, ~/_test.txt
Unregister-ScheduledTask -ErrorAction Ignore -TaskName _Test -Confirm:$false
$global:ErrorActionPreference = $prevEaPref
}
Пример вывода:
VERBOSE: Creating task...
TaskPath TaskName State
-------- -------- -----
\ _Test Ready
VERBOSE: Task will execute invisibly in 5 seconds, running as 'NT AUTHORITY\SYSTEM'. Waiting (plus a few extra seconds)...
VERBOSE: Task is assumed to have run. Output logged:
Hi, I'm running at 01/11/2023 17:06:04
* as WORKSTATION1$ (whose home dir. is 'C:\Windows\system32\config\systemprofile')
* in 'C:\Windows\system32'
* ELEVATED.
Последние 4 строки — это вывод функции модуля (Get-Foo
), доказывающий, что модуль был успешно импортирован в контексте задачи.
Большое спасибо, только что закончил читать это полностью, и это так информативно и поучительно.
Говоря прагматически, разве вы не можете просто добавить
Import-Module C:\Users\<UserName>\OneDrive\Documents\PowerShell\Modules\ModuleFolder\<YourModule>
к своемуpwsh.exe
звонку?