Использовать переменную из скрипта внутри скриптового блока

#powershell #invoke-command

#powershell #вызов-команда

Вопрос:

Я пытаюсь написать сценарий Powershell, который отключит текущего пользователя, вошедшего в систему. Я использую Invoke-Command командлет со скриптовым блоком внутри скрипта.

Я определил некоторые параметры в скрипте, которые я пытаюсь передать в блок сценария, но я вполне могу заставить его работать.

Вот сценарий:

 param(
    [Parameter()]
    [string]$ComputerName,
    
    [Parameter()]
    [string]$Username
)


$ScriptBlock = {

     $ErrorActionPreference = 'Stop'
     try {
         ## Find all sessions matching the specified username
         $sessions = quser | Where-Object {$_ -match "$args[0]"}
         ## Parse the session IDs from the output
         $sessionIds = ($sessions -split '  ')[2]
         Write-Host "Found $(@($sessionIds).Count) user login(s) on computer."
         ## Loop through each session ID and pass each to the logoff command
         $sessionIds | ForEach-Object {
             Write-Host "Logging off session id [$($_)]..."
             logoff $_
         }
     } catch {
         if ($_.Exception.Message -match 'No user exists') {
             Write-Host "The user is not logged in."
         } else {
             throw $_.Exception.Message
         }
     }
 }


Invoke-Command -ComputerName $ComputerName -Argumentlist $Username -ScriptBlock $ScriptBlock
  

Я запускаю скрипт следующим образом:

 .Logoff-User.ps1 -Computername some_server -Username some_user
  

Теперь это действительно работает, но он выходит из системы от случайного пользователя (вероятно, не случайного, если честно).

Насколько я понимаю, переменная (the $Username ) из -ArgumentList передается в scriptblock и, похоже, интерпретируется правильно. Я могу распечатать $args переменную, используя Write-Host далее вниз, и она возвращает правильное имя пользователя.

Работает только с использованием $args ошибок, но с указанием первой позиции ( $args[0] ), но отключает случайного пользователя.

Я, очевидно, делаю что-то не так, но я не понимаю, почему. Скрипты, вероятно, ведут себя не так, как я думаю.

Спасибо!

Комментарии:

1. Изменить {$_ -match "$args[0]"} на {$_ -match "b$([regex]::Escape($args[0]))b"}

2. Зачем использовать $args[0] , если вы определили $Username для него именованный параметр?

3. @MathiasR.Jessen Спасибо за ответ, я попробовал другое предложение, но оно не сработало. Похоже, что переменная содержит не имя пользователя, а «заголовок» столбца в выходных данных (выход из сеанса id [SESSION])

4. @Noct03 Тогда кажется, что имя пользователя, которое вы предоставляете, — это не просто строка, содержащая имя пользователя, но, вероятно, вывод таблицы форматов для объекта. Проверьте, что вы отправляете в скрипт, это должно быть 2 строки

5. @Noct03 Да, я знаю, но я подозреваю, что вы не отправляете строку. Проверьте, что у вас есть some_user . Это определенно не просто имя пользователя, возможно, объект или строковое представление объекта.

Ответ №1:

Я понял это благодаря Тео. $Username Переменная, которую я использовал в скрипте, была неправильно передана в scriptblock. Мне пришлось переопределить параметр внутри блока скрипта, который затем использовал -Argument бы из Invoke-Command для передачи переменной в виде строки (чего первый скрипт также не делал.

Вот окончательный сценарий:

 param(
    [Parameter()]
    [string]$ComputerName,
    
    [Parameter()]
    [string]$Username
)

$ScriptBlock = {

     param($User)
     $ErrorActionPreference = 'Stop'
     try  {
         ## Find all sessions matching the specified username
         $sessions = quser | Where-Object {$_ -match $User}
         ## Parse the session IDs from the output
         $sessionIds = ($sessions -split '  ')[2]
         Write-Host "Found $(@($sessionIds).Count) user login(s) on computer."
         ## Loop through each session ID and pass each to the logoff command
         $sessionIds | ForEach-Object {
             Write-Host "Logging off session id [$($_)]..."
             logoff $_
         }
     } catch {
         if ($_.Exception.Message -match 'No user exists') {
             Write-Host "The user is not logged in."
         } else {
             throw $_.Exception.Message
         }
     }
 }

Invoke-Command -ComputerName $ComputerName -Argumentlist $Username -ScriptBlock $ScriptBlock
  

Затем я смог запустить скрипт по мере необходимости:

 .Logoff-User.ps1 -Computername some_server -Username some_user
  

Спасибо Тео и всем остальным за вашу помощь!