Мне нравится ответ Тео. Я просто хочу добавить некоторые дополнительные вещи, которые, конечно, не поместятся в комментарии ...
Изначально я думаю, что мы все отлаживаем ваш код, но придерживаемся шаблона, который вы изначально изложили. Строго говоря, в этом нет ничего плохого.
Я думаю, что здесь что-то потеряно, так это ваш актуальный вопрос; почему вы не можете просто передать вывод одной функции в другую? Ответ в том, как принимающий командлет или функция ожидает данные.
Если вы посмотрите на Get-Help Stop-Process -Parameter Id
(ИЛИ Имя параметра), вы увидите, что оно получит свойство через конвейер, если свойство будет названо правильно. :
-Id <Int32[]>
Specifies the process IDs of the processes to stop. To specify multiple IDs, use commas to separate the IDs. To find the PID of a process, type `Get-Process`.
Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? false
Таким образом, вы могли бы передавать по конвейеру, если бы у вашего пользовательского объекта было свойство с именем "Id".
Stop-Process примет идентификатор процесса, но это выполняется поиск имени свойства «Id», а Win32_Process возвращает «ProcessID».
Но есть вторая проблема. Значение переданного свойства должно быть приемлемым для принимающей функции / командлета. К сожалению, в Win32_Process обычно возвращается имя с суффиксом «.exe», и Get-Process не примет это.
Ответ Тео очень хорош и работает с Stop-Process, потому что его новый объект имеет свойство с именем ID, которое принимается конвейером и является частью набора параметров по умолчанию, что означает, что оно предпочтительнее, чем свойство name.
Однако, если вы передадите эти объекты в Get-Process, он не будет работать. Get-Process предпочитает имя над ID и ожидает значение типа «блокнот», а не «Notepad.exe», который возвращает Win32_Process. В этом случае Get-Process не сможет найти процесс и выдаст ошибку.
Примечание. Выше исправлено на основе сотрудничества с Тео, вы можете посмотреть предыдущую редакцию и комментарии для справки.
Чтобы заставить объекты работать также с Get-Process, просто измените значение, перейдя в «Имя». "свойство удалить завершающий файл" .exe ". Я отредактировал ответ Тео только для того, чтобы добавить этот бит. Вы должны увидеть, что если он его одобрит.
Я понимаю, что это не является частью вашего исходного вопроса, но это иллюстрирует дополнительная оговорка о передаче между различными инструментами / командлетами / функциями и т. д. c ...
Примечание: может быть несколько исключений, например: Win32_Process возвращает «System Idle Process», но Get-Process возвращает «Idle». Для ваших целей это, вероятно, не проблема. Конечно, вы никогда не остановите этот процесс!
Примечание: Вероятная причина, по которой Get-Process предпочитает имя, в то время как Stop-Process предпочитает идентификатор, состоит в том, что имя не уникально, а идентификатор. Stop-Process Notepad уничтожит все экземпляры Notepad, что обычно (и в вашем случае) не соответствует цели.
Относительно подхода в целом. Я хотел бы отметить, что существует несколько способов расширения объектов и создания пользовательских объектов PS. Add-Member - это хороший подход, если вам нужно или хотите, чтобы тип экземпляра оставался прежним; Я бы посчитал это расширением объекта. Однако в вашем случае вы создаете пользовательский объект, а затем добавляете в него членов. В таком случае я обычно использую Select-Object, который по умолчанию преобразует объекты в пользовательские объекты PS.
Ваш код с исправленным свойством «Имя»: $ Processes = Get-WmiObject win32_process
$Processes |
ForEach-Object{
$Owner = $_.getowner()
$Process = New-Object PSObject
$Process | Add-Member NoteProperty 'ComputerName' $_.CSName
$Process | Add-Member NoteProperty 'ProcessName' $_.ProcessName
$Process | Add-Member NoteProperty 'ProcessID' $_.ProcessID
$Process | Add-Member NoteProperty 'Domain' $Owner.Domain
$Process | Add-Member NoteProperty 'User' $Owner.User
$Process | Add-Member NoteProperty 'Name' -Value ( $_.ProcessName -Replace '\.exe$' )
$Process
}
Примечание: для краткости я удалил некоторый окружающий код.
Использование select выглядело бы примерно так:
$Processes = Get-WmiObject win32_process |
Select-Object ProcessID,
@{Name = 'ComputerName'; Expression = { $_.CSName }},
@{Name = 'Name '; Expression = { $_.ProcessName -Replace '\.exe$' } },
@{Name = 'Id'; Expression = { $_.ProcessID } },
@{Name = 'Domain'; Expression = { $_.GetOwner().Domain} },
@{Name = 'User'; Expression = { $_.GetOwner().User} }
Затем его можно перенаправить прямо в предложение where для фильтрации процессов, которые вы просматриваете. for, а затем снова отправьте в командлет Stop-Process:
Get-WmiObject win32_process |
Select-Object ProcessID,
@{Name = 'ComputerName'; Expression = { $_.CSName }},
@{Name = 'Name '; Expression = { $_.ProcessName -Replace '\.exe$' } },
@{Name = 'Id'; Expression = { $_.ProcessID } },
@{Name = 'Domain'; Expression = { $_.GetOwner().Domain} },
@{Name = 'User'; Expression = { $_.GetOwner().User} } |
Where-Object{ $TargetUsers -contains $_.User } |
Stop-Process
Примечание. Это исключает даже присвоение переменной $ Processes. Вам все еще нужно было заполнить переменную $ TargetUsers.
Также: в предыдущем комментарии указывалось, что, учитывая то, что вы делаете, вам не нужны все реквизиты, поэтому что-то вроде:
Get-WmiObject win32_process |
Select-Object @{Name = 'Name '; Expression = { $_.ProcessName -Replace '\.exe$' } },
@{Name = 'User'; Expression = { $_.GetOwner().User} } |
Where-Object{ $TargetUsers -contains $_.User } |
Stop-Process
Однако, если вы делаете в своем коде другие вещи, такие как регистрация завершенных процессов, установить / 1060 * и сохранить больше свойств относительно безопасно.
И просто для иллюстрации: с помощью ForEach-Object можно с легкостью упростить конвейерную обработку и не нужно отклоняться от исходных объектов:
Get-WmiObject win32_process |
Where{$TargetUsers -contains $_.GetOwner().User } |
ForEach-Object{ Stop-Process -Id $_.ProcessID }
Одна из лучших особенностей PowerShell - это то, что много способов делать вещи. Насколько надежно вы хотите сделать данный проект. Последний пример, очевидно, очень лаконичен, но было бы неоптимально (хотя и выполнимо) добавить что-то вроде ведения журнала или вывода на консоль ...
Также Тео прав насчет Get-CimInstance. Если я не ошибаюсь, Get-WmiObject устарел. Старые привычки трудно сломать, поэтому во всех моих примерах использовался Get-Wmi ... Однако эти концепции должны применяться во всей PowerShell, включая Get-CimInstance ...
В любом случае, я надеюсь, что я кое-что добавил здесь. Есть несколько статей, в которых обсуждаются различные возможности создания и манипулирования объектами за и против и т. Д. c ... Если у меня будет время, я постараюсь их отследить.