Fetching value of processId from list of process Ids - windows

I am running the below cmdlet to get the process ids used by a file:
Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq $lockedFile){$processVar.Name + " PID:" + $processVar.id}}}
The above cmdlet is generating the output process1 PID:5260
Now, I need to pipe the cmdlet so as to kill the above process id for which I have written below cmdlet:
Get-Process | foreach{$processVar = $_;$_.Modules | foreach{if($_.FileName -eq $lockedFile){$processVar.Name + " PID:" + $processVar.id}}} | Stop-Process $processVar.id
However, it is not stopping the process.
I basically want to print out the process name and process id and then kill the process.
The process name and process id are already printing out correctly but need help to pipe the process id into the cmdlet and then kill the process.

Maybe you could do it this way, I believe outputting an object to the console would be more readable. The only change you need to do is move the Stop-Process inside the if condition.
$lockedFile = 'defineThisVariable'
Get-Process | ForEach-Object {
if($_.Modules.FileName.where({$_ -eq $lockedFile})) {
# This is the ouput object to the console
[pscustomobject]#{
Process = $_.Name
PID = $_.id
}
# Here you stop the Process, you can add
# `-Verbose` for more output to console
Stop-Process -Id $_.Id
}
}

Related

Kill the process if start time is less than 2 hours

I need to kill the process if start time is less than 2 hours.
I have written the below cmdlet to find out the starttime but how to find out if is it less than 2 hours:
get-process process1 | select starttime
There is also a possibility that on some hosts process1 is not running. so I need to check first if the process1 is running
You can use a loop of your choice, in this example ForEach-Object in addition to an if condition to check if the StartTime value is lower than 2 hours.
If you need to check first is the process is running then you would need to get all processes and filter by the process name you're looking for. Then check if the returned value from Where-Object is $null or not.
$procName = 'myprocess'
$process = Get-Process | Where-Object Name -EQ $procName
if(-not $process) {
Write-Warning "$procName not found!"
}
else {
$process | ForEach-Object {
if($_.StartTime -lt [datetime]::Now.AddHours(-2)) {
try {
'Attempting to stop {0}' -f $_.Name
Stop-Process $_ -Force
'{0} successfully stopped.' -f $_.Name
}
catch {
Write-Warning $_.Exception.Message
}
}
}
}

match one of two pid's using the processes full path

I have two identical running processes called RocketLeague.exe
I want to store one of the processes PID's in a variable for later use in another command by matching both processes full file paths.
I have been able to come up with two commands so far that pipe the full path of the processes but can't figure out how to continue the piping of the right PID into a final custom command.
How can I store the correct PID in a variable for use in my custom command?
1) Get-Process -Name 'RocketLeague' | Format-List -Property Path
2) Get-Process -Name 'RocketLeague'
Using the feedback from user:lit I was able to come up with this solution.
$procID = Get-process -Name 'RocketLeague' | Select-Object -Property Id,Path | ForEach-Object {
If($_.Path -eq 'C:\Program Files (x86)\Steam\steamapps\common\rocketleague\Binaries\Win64\RocketLeague.exe'){
Set-Variable -Name 'procSteam' -Value $_.Id; Write-Host $procSteam
}
}
If you just want the specific Process that is equal to that Path you can use Where-Object or .Where() method for filtering. The code would be reduced to:
# This:
$procID = (Get-Process -Name 'RocketLeague').Where({
$_.Path -eq 'C:\Program Files (x86)\Steam\steamapps\common\rocketleague\Binaries\Win64\RocketLeague.exe'
}) | Select-Object -Property Id, Path
# Or this:
$procID = Get-Process -Name 'RocketLeague' | Where-Object {
$_.Path -eq 'C:\Program Files (x86)\Steam\steamapps\common\rocketleague\Binaries\Win64\RocketLeague.exe'
} | Select-Object -Property Id, Path
And if, for example there is only one of the paths that ends with Win64\....exe you can use .EndsWith() method:
$procID = (Get-Process -Name 'RocketLeague').Where({
([string]$_.Path).EndsWith('\Win64\RocketLeague.exe')
}) | Select-Object -Property Id, Path

Pass / Pipe / Loop All processes from Get-Process to Powershell PoshInternals script

How would I pass all processes with Get-Process matching a certain process name to another PowerShell script one by one ?
pseudocode
for each process in matchingprocesses:
myScript(process)
Planned usage Set-WorkingSetToMin script: https://www.powershellgallery.com/packages/PoshInternals/1.0/Content/Set-WorkingSetToMin.ps1
This works great as there is only one notepad++ process:
get-process notepad++ | Set-WorkingSetToMin
However for VS Code this only only gets the first code process and ignores the rest:
get-process code | Set-WorkingSetToMin
How do I pipe each process matching a certain name to powershell script ?
Alternative would be to modify PoshInternals script to accept multiple processes:
# Dont run Set-WorkingSet on sqlservr.exe, store.exe and similar processes
# Todo: Check process name and filter
# Example - get-process notepad | Set-WorkingSetToMin
Function Set-WorkingSetToMin {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline=$True, Mandatory=$true)]
[System.Diagnostics.Process] $Process
)
if ($Process -ne $Null)
{
$handle = $Process.Handle
$from = ($process.WorkingSet/1MB)
$to = [PoshInternals.Kernel32]::SetProcessWorkingSetSize($handle,-1,-1) | Out-Null
Write-Output "Trimming Working Set Values from: $from"
} #End of If
} # End of Function
ANSWER in one line without extra variables:
foreach ($process in Get-Process myprocessname) { Set-WorkingSetToMin ($process) }
You could add a where clause to pull out just the processes you want, then pipe that set to Set-WorkingSetToMin. An example is below, but adjust as needed to pull exactly what you're looking for.
get-process | where {$_.ProcessName -like "*code*"} | Set-WorkingSetToMin
Update:
I see what you're saying, the issue is not with the set of processes being sent, but how they're handled once they're there. To get around that, you could set a variable equal to the process set, then loop through them, calling the cmdlet each time. Something like this:
$processes = get-process | where {$_.ProcessName -like "code"} | Set-WorkingSetToMin
foreach ($process in $processes)
{
Set-WorkingSetToMin ($process)
}
ANSWER thanks to help from Landon: foreach ($process in Get-Process myprocessname) { Set-WorkingSetToMin ($process) }

How to find the process ID of a running scheduled task?

I can determine running tasks with:
$TaskService = new-object -ComObject('Schedule.Service')
$TaskService.connect()
$TaskFolder = $TaskService.GetFolder('\')
$TaskFolder.gettasks(1) | ? {$_.state -eq 4}
Is there any way to identify the process IDs of those tasks if they start the same program (i.e. process name) as other existing processes?
My goal is a PowerShell script started from a scheduled task that can identify which scheduled task it is running under. I can easily determine the PoSh processID with $PID, but I don't know how to link that to a particular scheduled task.
Thanks.
This should work if you have this running in the script that is fired as an action. It will get the task path assuming it can be found by the RunningTasks COM object method
# Initiate a COM object and connect
$TaskService = New-Object -ComObject('Schedule.Service')
$TaskService.Connect()
# Query for currently running tasks
# 0 - the user is permitted to see.
# 1 - 0 + Hidden
$runningTasks = $TaskService.GetRunningTasks(0)
# Get the task associated to a certain PID
$runningTasks | Where-Object{$_.EnginePID -eq $PID} | Select-Object -ExpandProperty Path
Credit goes to eryksun for pointing out the method and linking to the ITaskService interface on MSDN
There is something to be said about the other suggestion of just telling your script what is running from via an extra parameter. That way you don't have to worry about a COM dependency.
param(
[string]$SuperImportantString,
[int]$NumberofBagels,
[string]$TaskInitiated
)
Set-Content -Path $file -Value "I'm running from $TaskInitiated"
Yes, this does make it more manual but you would have ultimate control over the text and such used and not have to worry about multiple tasks running from the same PID.
This seems like it tells me exactly which task started the script:
$EventFilter = #{
Logname = 'Microsoft-Windows-TaskScheduler/Operational'
ProviderName = "Microsoft-Windows-TaskScheduler"
Id = 129
Data = "$PID"
}
$ThisProcessEvent = Get-WinEvent -FilterHashtable $EventFilter -MaxEvents 1 -ErrorAction SilentlyContinue
$EventXML = [xml]$ThisProcessEvent.toxml()
$TaskFullName = $eventxml.event.eventdata.data | ? {$_.name -eq 'taskname'} |select -ExpandProperty "#text"

Pass input to CMD, using CMD process id (PID) in powershell

Thanks to Abbas, the following code enable us to call a cmd process and pass command to it using PowerShell script.
$psi = New-Object System.Diagnostics.ProcessStartInfo;
$psi.FileName = "cmd.exe"; #process file
$psi.UseShellExecute = $false; #start the process from it's own executable file
$psi.RedirectStandardInput = $true; #enable the process to read from standard input
$p = [System.Diagnostics.Process]::Start($psi);
Start-Sleep -s 2 #wait 2 seconds so that the process can be up and running
$p.StandardInput.WriteLine("dir"); #StandardInput property of the Process is a .NET StreamWriter object
Now, How can I use a CMD process that already exists.
In better words, I want to use the PID of a cmd.exe process that is running and pass the command to it.
Based on #Falcon's comment:
I want to be sure that the CMD is running as SYSTEM
I think the code should work, which checks for a command shell running as SYSTEM. It will return true for each matching shell that's running as SYSTEM, with title=TEST:
Get-CimInstance Win32_Process -Filter "name = 'cmd.exe'" | ForEach-Object {
if ((Get-Process -Id $_.ProcessId).MainWindowTitle -eq 'TEST') {
(Invoke-CimMethod -InputObject $_ -MethodName GetOwner).User -eq 'SYSTEM'
}
}
The above code needs running in an elevated shell
The code based on this article checks for the command prompt being elevated:
$p = Get-Process -Name cmd | where {$_.MainWindowTitle -eq 'TEST'} |
Select Name, #{Name="Elevated"; Expression={ if ($this.Name -notin #('Idle','System')) {-not $this.Path -and -not $this.Handle} } }
The code above needs running in a non-elevated PowerShell instance. It is testing for the absence of a path & handle - which the non-elevated shell can't see for an elevated command prompt. Change the eq 'TEST' condition to match your window.

Resources