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

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"

Related

Method invocation failed because [System.RuntimeType] for GetCurrentThreadId

I want to get windows process's memory dump with below powershell script.
I used to try this script. But it's give following error:
Method invocation failed because [System.RuntimeType] does not contain
a method named 'GetCurrentThreadId'.
#############################################################
$process = Get-Process -Name AggregatorHost
$threadId = [System.Diagnostics.Process].GetCurrentThreadId()
$thread = $process.Threads | Where-Object { $_.Id -eq $threadId }
$thread.Export("test.dmp")
###################################################################
How to solve this problem or pls tell me if you have other way?
powershell memory dump
Process.GetCurrentTheadId is a static method, so you need to use the static member invocation operator :: (as opposed to the regular member invocation operator .):
[System.Diagnostics.Process]::GetCurrentThreadId()
That being said, I doubt the code you've presented is going to do what you expect - GetCurrentThreadId will get the thread id from the executing thread in the powershell process, and you're not going to find the same thread id belonging to another process during the same boot cycle
[System.RuntimeType] does not contain a method named 'GetCurrentThreadId'.
Let's find a type containing such a method:
Get-Type -ErrorAction SilentlyContinue |
Where-Object {$_.GetMethods().Name -eq 'GetCurrentThreadId'} |
Select-Object -ExpandProperty FullName
System.AppDomain
However, the following code snippet shows that thread identified in such a way (GetCurrentThreadId static method of the System.AppDomain class) belongs to calling process (hence, can't be found in Get-Process -Name AggregatorHost):
$PID
Get-Process -ErrorAction SilentlyContinue |
Where-Object {
$_.Threads.Id -eq [System.AppDomain]::GetCurrentThreadId()
} 2>$null
11492
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
559 37 70280 87944 2.31 11492 1 powershell
Moreover:
AppDomain.GetCurrentThreadId has been deprecated because it does not
provide a stable Id when managed threads are running on fibers (aka
lightweight threads). To get a stable identifier for a managed thread,
use the ManagedThreadId property on Thread instead.

Fetching value of processId from list of process Ids

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
}
}

How to get the kernel mode time and user mode time in PowerShell?

I am using Windows 7. How to find the kernel mode time and user mode time for a process in PowerShell? I was able to get the process name and process ID.
$strComputer = "."
$procs = Get-Process -ComputerName $strComputer
foreach ($proc in $procs) {
if ($proc.ProcessName -eq "notepad") {
echo $proc.Id
echo $proc.ProcessName
}
}
Kernel mode time:
$proc.PrivilegedProcessorTime.TotalMilliseconds
User mode time:
$proc.UserProcessorTime.TotalMilliseconds
For discovery purposes you can use $proc | Get-Member to enumerate the (non-hidden) methods and properties of an object, and $proc | Format-List * to list all (non-hidden) properties and their values.
Or, you could simply check the documentation.

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.

Strange result from powershell script when executing via scheduled task

I'm running a powershell script, that when run from the ISE outputs one set of values but when the same task is run through task scheduler it seems to add a second value that doesn't display when run manually. The code that's being executed is as below:
import-module WebAdministration
$app_pool_name = <<app_pool_name_goes_here>>
$memused = ""
$cpuused = ""
$datetime = get-date -format s
$memused = Get-WmiObject Win32_process | where CommandLine -Match "$app_pool_name"
$id = dir IIS:\AppPools\$app_pool_name\WorkerProcesses\ | Select-Object -expand processId
$cpuUsed = Get-WmiObject Win32_PerfFormattedData_PerfProc_Process | where IDProcess -Match $id
Add-Content -path C:\Winsys\PSOutput\$app_pool_name-CPU-RAM_test.txt -value "$datetime,$($memUsed.workingsetsize),$($cpuUsed.PercentProcessorTime)"
When running the script manually the output returned is:
Date,Mem,CPU
2016-08-02T14:09:36,15062687744,0
2016-08-02T14:09:38,15062425600,0
When running the script through task scheduler the output returned is:
Date,Mem,CPU
2016-08-02T13:58:25,15065047040 624189440,0
2016-08-02T14:05:01,15061901312 624713728,0
The difference being the Mem, for some reason it's adding an extra value. Does anyone know why this is?
Turns out this was my own error, there are two app pools with very similar names, the -match was catching both. But it still didn't explain why it was only showing both in task scheduler and not ISE. Ah well, resolved now by adding a -and -notmatch "text" section.
E.g.
Get-WmiObject Win32_process | where {$_.CommandLine -Match "$app_pool_name" -and $_.CommandLine -notmatch "<<text in other command line>>"}
Add Comment

Resources