98

e.g: if I run notepad.exe c:\autoexec.bat,

How can I get c:\autoexec.bat in Get-Process notepad in PowerShell?

Or how can I get c:\autoexec.bat in Process.GetProcessesByName("notepad"); in C#?

aphoria
  • 19,796
  • 7
  • 64
  • 73
victorwoo
  • 2,107
  • 3
  • 17
  • 20
  • Maybe this will help you: [How to get the command line parameters from a different process](http://social.msdn.microsoft.com/Forums/en-US/8efe163b-927e-4895-9983-b8c47b515d7c/how-to-get-the-command-line-parameters-from-a-different-process-in-c) – Corak Jul 10 '13 at 06:08
  • its not clear. can u specify more clearly what exactly you are trying to do? @victorwoo – Rezoan Jul 10 '13 at 06:09
  • 1
    Please take a step back and describe the actual problem you're trying to solve instead of what you perceive as the solution. – Ansgar Wiechers Jul 10 '13 at 09:40
  • 1
    If we've started a process and passed some parameters, how to get the command line parameters of the running process by C# or PowerShell? – victorwoo Jul 10 '13 at 10:10

4 Answers4

153

In PowerShell you can get the command line of a process via WMI:

$process = "notepad.exe"
Get-WmiObject Win32_Process -Filter "name = '$process'" | Select-Object CommandLine

Note that you need admin privileges to be able to access that information about processes running in the context of another user. As a normal user it's only visible to you for processes running in your own context.

Ansgar Wiechers
  • 193,178
  • 25
  • 254
  • 328
  • 9
    There is a permissions aspect to this too. The Powershell process needs to have permissions at least equivalent to the target process. So a regular Powershell session won't be able to get such information for a process running elevated (e.g. as Administrator). in this case, CommandLine (the response) will just be blank. – CJBS Feb 18 '14 at 19:18
  • 4
    @CJBS To be precise you need admin privileges to be able to access that information about processes running in the context of another user. As a normal user it's only visible to you for processes running in your own context. – Ansgar Wiechers Feb 18 '14 at 22:15
  • 7
    The value is still truncated to a certain length of characters. You can work around it by piping the result to "out-string -Width 2000" or something similar. – Shannon Jun 17 '14 at 22:47
  • 1
    Just a general syntax note, you can also use `| where name -eq $process` instead of `-filter` and it compiles the same before execution. I prefer this way as it's more extensible. – brandeded Jul 17 '15 at 13:01
  • 11
    @mbrownnyc Using `-Filter` does the filtering on the remote host if your run `Get-WmiObject` against remote computers (using the `-ComputerName` parameter), reducing the amount of data that is transferred over the network (thus improving performance). Using `Where-Object` filters locally, after *all* WMI data was fetched from the remote host(s). It doesn't make a difference when running `Get-WmiObject` locally, though, like in this case. Also note that the syntax `where property value` only works in PowerShell v3 or newer. Prior to that you must use `where { $_.property value }`. – Ansgar Wiechers Jul 18 '15 at 10:44
  • @AnsgarWiechers thanks for that point! Very important with get-wmiobject indeed! – brandeded Jul 18 '15 at 16:17
  • 3
    To avoid long line truncation you can also use `| fl` or `| ft -auto` ([from here](http://stackoverflow.com/a/13735900/344541)) – Kay Zed Mar 13 '17 at 06:56
  • 3
    This didn't take much to figure out, but to save someone a few keystrokes, if you already have the process id (like from looking at CPU usage, etc) you can use `"processid = 1234"` - I use it for seeing which website is going rogue on our server (and there are 200 `w3wp.exe` processes) – ahwm Jul 14 '17 at 17:32
  • how to I cast the type of "Selected.System.Management.ManagementObject" to int32, provided I selected processid rather than commandline? – Sajuuk Jan 17 '19 at 06:44
  • 1
    @Sajuuk That has nothing to do with this question or answer. Please ask a new question. – Ansgar Wiechers Jan 17 '19 at 08:38
58

This answer is excellent, however for futureproofing and to do future you a favor, Unless you're using pretty old powershell (in which case I recommend an update!) Get-WMIObject has been superseded by Get-CimInstance Hey Scripting Guy reference

Try this

$process = "notepad.exe"
Get-CimInstance Win32_Process -Filter "name = '$process'" | select CommandLine 
PsychoData
  • 1,198
  • 16
  • 32
  • 14
    Note that with `Get-CimInstance Win32_Process`, the `name` includes the .exe extension. That's different from `Get-Process`. – Ross Presser Oct 10 '19 at 21:02
  • 1
    Or, if you want to use PIDs: get-process node | select id,starttime,name,@{Name="CommandLine";Expr={ $filter = "ProcessId = {0}" -f $_.Id; (Get-CimInstance Win32_Process -filter $filter).CommandLine }} | sort starttime | ft -au -wr – JohnL4 Mar 16 '23 at 15:57
13

If you put the following code in your powershell $PROFILE file you can permanently extend the Process object class and use the CommandLine property:

$TypeData = @{
    TypeName   = [System.Diagnostics.Process].ToString()
    MemberType = [System.Management.Automation.PSMemberTypes]::ScriptProperty
    MemberName = 'CommandLine'
    Value = {
        if (('Win32NT' -eq [System.Environment]::OSVersion.Platform)) { # it's windows
            (Get-CimInstance Win32_Process -Filter "ProcessId = $($this.Id)").CommandLine
        } elseif (('Unix' -eq [System.Environment]::OSVersion.Platform)) { # it's linux/unix
            Get-Content -LiteralPath "/proc/$($this.Id)/cmdline"
        } elseif (('MacOSX' -eq [System.Environment]::OSVersion.Platform)) { # it's macos
            # ???
        }
    }
}
Update-TypeData @TypeData -ErrorAction Ignore

NB: Update-TypeData is called with -ErrorAction Ignore because in pwsh (at least on version 7.3.4), CommandLine already exists; -EA Ignore suppresses the error. As an alternative, you could check for the property existence, and execute Update-TypeData only in the case of missing property.

The scriptblock used as value is taken from what pwsh 7.3.4 actually uses internally, adapted also for Windows Powershell (where $IsWindows, etc do not exist).

You can get the code in the scriptblock by running the following in pwsh 7.3.4: (([System.Diagnostics.Process]@{}) | gm | ? { $_.Name -ieq 'commandline' }) | select -expand Definition.

Then you can reliably query the command line (iif you have the correct rights, for the queried process(es), see [1], [2]):

get-process notepad.exe | select-object ProcessName, CommandLine
aetonsi
  • 208
  • 2
  • 9
Marty
  • 176
  • 1
  • 5
9

I'm using powershell 7.1 and this seems to be built in to the process object now as a scripted property:

> (Get-Process notepad)[0].CommandLine
"C:\WINDOWS\system32\notepad.exe"

Interestingly, you can view its implementation and see that it partially uses the answer from PsychoData:

($process | Get-Member -Name CommandLine).Definition
System.Object CommandLine {get=
                        if ($IsWindows) {
                            (Get-CimInstance Win32_Process -Filter "ProcessId = $($this.Id)").CommandLine
                        } elseif ($IsLinux) {
                            Get-Content -LiteralPath "/proc/$($this.Id)/cmdline"
                        }
                    ;}

Running Get-Member on a process shows that it is an instance of System.Diagnostics.Process, but that it has several properties that are scripted.

The other properties are FileVersion, Path, Product, and ProductVersion.

Jared Beach
  • 2,635
  • 34
  • 38
  • 1
    Appreciated the idea to use `Get-Member` to get more details on how pwsh works. We can also use `$process | Get-TypeData | ConvertTo-Json` for similar reasons. – minus one Feb 02 '21 at 11:01