What’s My PID?

Doctor Scripto

Summary: Ed Wilson, Microsoft Scripting Guy, creates a function to capture the process ID of a Windows PowerShell host.

Microsoft Scripting Guy, Ed Wilson, is here. One of the things I like to know is the process ID (PID) of specific processes. Often this is trivial. I can use the Get-Process cmdlet and, for example, look to see what the process ID of Notepad.exe is. But what if I have four or five instances of Notepad running? Then it becomes somewhat an exercise in trial and error.

This is also true for Windows PowerShell. For example, the Windows PowerShell console process name is PowerShell. No problem. Except that I often have multiple instances of Windows PowerShell running, and quite often they are all doing different things.

So, whereas the $host automatic variable represents the Windows PowerShell console host, and it has an instance ID, I cannot easily reference that instance ID to a process ID. So, I had this idea about adding a member to the $host variable. Not too big of a deal. In fact, it is something that I could do since Windows PowerShell 1.0 by using the Add-Member cmdlet.

I need to know which instance of Windows PowerShell I am talking about, and I need a way to differentiate which is which. One way I can do that is by using the StartTime property from the process object that I obtain via the Get-Process cmdlet.

Now, to what do I compare it? Well obviously, with the date from Get-Date. So, I decided to capture the date as soon as I can and compare it with the StartTime property from Get-Process. The result? For me, it works nearly all the time, and that is good enough for something like this.

At first, it was easy, I simply captured the process ID and add it to $host. But that quickly did not work because if I have multiple instances of Windows PowerShell running (more likely than not in my case), I have an array of process IDs—and that doesn’t do any good.

But in fact, when I have multiple instances of Windows PowerShell running, that is THE time when it is most important to know which instance is which. So that added to the complexity of my Windows PowerShell function.

The first thing I do is use the Foreach statement and walk through a collection of Windows PowerShell processes. If the start time matches the current date time, I use the Add-Member cmdlet to add the PID to a property I created called PID. Otherwise, I don’t do anything.

Here is the function:

Function Get-HostPid

{

 Foreach($p in (Get-Process PowerShell))

  {

   if ($p.StartTime.Touniversaltime() -match

       (Get-Date).ToUniversalTime())

     { $host | Add-Member -NotePropertyName PID -NotePropertyValue ($p.ID)}}}

The first thing I do when processing commands in my Windows PowerShell profile is to call the Get-HostPID function. This gives me the best chance for success. The command is simple:

Get-HostPID

Here is the output from the $host variable now:

Image of command output

The complete Windows PowerShell profile is shown here:

#——————————————————————————

#

# PowerShell console profile

# ed wilson, msft

#

# NOTES: contains five types of things: aliases, functions, psdrives,

# variables and commands.

# version 1.2

# 7/27/2015

# HSG 7-28-2015

#——————————————————————————

#Aliases

Set-Alias -Name ep -Value edit-profile | out-null

Set-Alias -Name tch -Value Test-ConsoleHost | out-null

Set-Alias -Name gfl -Value Get-ForwardLink | out-null

Set-Alias -Name gwp -Value Get-WebPage | out-null

Set-Alias -Name rifc -Value Replace-InvalidFileCharacters | out-null

Set-Alias -Name gev -Value Get-EnumValues | out-null

Set-Alias -Name sudo -Value Start-ElevatedPowerShell | out-null

#Variables

New-Variable -Name doc -Value "$home\documents" `

   -Description "My documents library. Profile created" `

   -Option ReadOnly -Scope "Global"

if(!(Test-Path variable:backupHome))

{

 new-variable -name backupHome -value "$doc\WindowsPowerShell\profileBackup" `

    -Description "Folder for profile backups. Profile created" `

    -Option ReadOnly -Scope "Global"

}

#PS_Drives

New-PSDrive -Name Mod -Root ($env:PSModulePath -split ';')[0] `

 -PSProvider FileSystem | out-null

#Functions

Function Edit-Profile

{ ISE $profile }

Function Test-ConsoleHost

{

 if(($host.Name -match 'consolehost')) {$true}

 Else {$false}  

}

Function Replace-InvalidFileCharacters

{

 Param ($stringIn,

        $replacementChar)

 # Replace-InvalidFileCharacters "my?string"

 # Replace-InvalidFileCharacters (get-date).tostring()

 $stringIN -replace "[$( [System.IO.Path]::GetInvalidFileNameChars() )]", $replacementChar

}

Function Get-TranscriptName

{

 $date = Get-Date -format s

  "{0}.{1}.{2}.txt" -f "PowerShell_Transcript", $env:COMPUTERNAME,

  (rifc -stringIn $date.ToString() -replacementChar "-") }

Function Get-WebPage

{

 Param($url)

 # Get-WebPage -url (Get-CmdletFwLink get-process)

 (New-Object -ComObject shell.application).open($url)

}

Function Get-ForwardLink

{

 Param($cmdletName)

 # Get-WebPage -url (Get-CmdletFwLink get-process)

 (Get-Command $cmdletName).helpuri

}

Function BackUp-Profile

{

 Param([string]$destination = $backupHome)

  if(!(test-path $destination))

   {New-Item -Path $destination -ItemType directory -force | out-null}

  $date = Get-Date -Format s

  $backupName = "{0}.{1}.{2}.{3}" -f $env:COMPUTERNAME, $env:USERNAME,

   (rifc -stringIn $date.ToString() -replacementChar "-"),

   (Split-Path -Path $PROFILE -Leaf)

 copy-item -path $profile -destination "$destination\$backupName" -force

}

Function get-enumValues

{

 # get-enumValues -enum "System.Diagnostics.Eventing.Reader.StandardEventLevel"

Param([string]$enum)

$enumValues = @{}

[enum]::getvalues([type]$enum) |

ForEach-Object {

$enumValues.add($_, $_.value__)

}

$enumValues

}

Function Test-IsAdmin

{

 <#

    .Synopsis

        Tests if the user is an administrator

    .Description

        Returns true if a user is an administrator, false if the user is not an administrator       

    .Example

        Test-IsAdmin

    #>

 $identity = [Security.Principal.WindowsIdentity]::GetCurrent()

 $principal = New-Object Security.Principal.WindowsPrincipal $identity

 $principal.IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)

}

Function Start-ElevatedPowerShell

{

 Start-Process PowerShell -Verb Runas

 }

Function Get-HostPid

{

 Foreach($p in (Get-Process PowerShell))

  {

   if ($p.StartTime.Touniversaltime() -match

       (Get-Date).ToUniversalTime())

     { $host | Add-Member -NotePropertyName PID -NotePropertyValue ($p.ID)}}}

#Commands

Get-HostPid

Set-Location c:\

If(tch) {Start-Transcript -Path (Join-Path -Path `

 $doc -ChildPath $(Get-TranscriptName))}

BackUp-Profile

if(Test-IsAdmin)

   { $host.UI.RawUI.WindowTitle = "Elevated PowerShell" }

else { $host.UI.RawUI.WindowTitle = "Mr $($env:USERNAME) Non-elevated Posh" }

That is how you can use Windows PowerShell to find a PID. Join me tomorrow when I will talk about more cool stuff.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

0 comments

Discussion is closed.

Feedback usabilla icon