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