Get running process path and create a quick desktop shortcut with PowerShell GUI

Get running process path and create a quick desktop shortcut with PowerShell GUI

The other day I was looking for a way to get the executable path of a given software, so I thought it would be nice to have a script which would do it for me.

While I was there I also  added  an option to create a quick desktop shortcut if you so wish.

Keep in mind that some process might need elevation, so make sure to start the script/executable as Admin or some path will show as blank.

You can run this small app from either  GUI or  CLI.

If you just want to run it from the command line: .\gpp.ps1

The executable .exe is in standalone directory in the Github repository.

Get process path or create desktop shortcut
Get process path or create desktop shortcut

This time I created the form design with PSScriptPad as I don't like Visual Studio, it creates so many files that are not really needed to handle such a small script.

gpp.designer.ps1

$AppContainer = New-Object -TypeName System.Windows.Forms.Form
[System.Windows.Forms.Button]$getRunningProcess = $null
[System.Windows.Forms.Label]$runningProcess = $null
[System.Windows.Forms.TextBox]$processArray = $null
[System.Windows.Forms.TextBox]$results = $null
[System.Windows.Forms.Label]$processPath = $null
[System.Windows.Forms.Label]$helpText = $null
[System.Windows.Forms.Label]$processName = $null
[System.Windows.Forms.Button]$shortcut = $null
function InitializeComponent
{
$getRunningProcess = (New-Object -TypeName System.Windows.Forms.Button)
$runningProcess = (New-Object -TypeName System.Windows.Forms.Label)
$processArray = (New-Object -TypeName System.Windows.Forms.TextBox)
$results = (New-Object -TypeName System.Windows.Forms.TextBox)
$processPath = (New-Object -TypeName System.Windows.Forms.Label)
$helpText = (New-Object -TypeName System.Windows.Forms.Label)
$processName = (New-Object -TypeName System.Windows.Forms.Label)
$shortcut = (New-Object -TypeName System.Windows.Forms.Button)
$AppContainer.SuspendLayout()
#
#getRunningProcess
#
$getRunningProcess.Cursor = [System.Windows.Forms.Cursors]::Hand
$getRunningProcess.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]167))
$getRunningProcess.Name = [System.String]'getRunningProcess'
$getRunningProcess.Padding = (New-Object -TypeName System.Windows.Forms.Padding -ArgumentList @([System.Int32]5))
$getRunningProcess.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]140,[System.Int32]31))
$getRunningProcess.TabIndex = [System.Int32]0
$getRunningProcess.Text = [System.String]'Find process path'
$getRunningProcess.UseVisualStyleBackColor = $true
#
#runningProcess
#
$runningProcess.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]9))
$runningProcess.Name = [System.String]'runningProcess'
$runningProcess.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]575,[System.Int32]23))
$runningProcess.TabIndex = [System.Int32]1
$runningProcess.Text = [System.String]'Type multiple process separated by a comma ","'
$runningProcess.add_Click($Label1_Click)
#
#processArray
#
$processArray.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]98))
$processArray.Multiline = $true
$processArray.Name = [System.String]'processArray'
$processArray.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]575,[System.Int32]63))
$processArray.TabIndex = [System.Int32]2
#
#results
#
$results.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]237))
$results.Multiline = $true
$results.Name = [System.String]'results'
$results.ReadOnly = $true
$results.ScrollBars = [System.Windows.Forms.ScrollBars]::Vertical
$results.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]575,[System.Int32]240))
$results.TabIndex = [System.Int32]3
#
#processPath
#
$processPath.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Tahoma',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Point,([System.Byte][System.Byte]0)))
$processPath.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]211))
$processPath.Name = [System.String]'processPath'
$processPath.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]100,[System.Int32]23))
$processPath.TabIndex = [System.Int32]4
$processPath.Text = [System.String]'Process path'
#
#helpText
#
$helpText.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]32))
$helpText.Name = [System.String]'helpText'
$helpText.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]575,[System.Int32]23))
$helpText.TabIndex = [System.Int32]5
$helpText.Text = [System.String]'Example: disc,ms,ppt,svc,ms,free,obsi,mongo,java,every,lgh,skype,teams'
$helpText.add_Click($Label1_Click)
#
#processName
#
$processName.Font = (New-Object -TypeName System.Drawing.Font -ArgumentList @([System.String]'Tahoma',[System.Single]8.25,[System.Drawing.FontStyle]::Bold,[System.Drawing.GraphicsUnit]::Point,([System.Byte][System.Byte]0)))
$processName.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]12,[System.Int32]72))
$processName.Name = [System.String]'processName'
$processName.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]100,[System.Int32]23))
$processName.TabIndex = [System.Int32]6
$processName.Text = [System.String]'Process Name'
#
#shortcut
#
$shortcut.Cursor = [System.Windows.Forms.Cursors]::Hand
$shortcut.Location = (New-Object -TypeName System.Drawing.Point -ArgumentList @([System.Int32]158,[System.Int32]166))
$shortcut.Name = [System.String]'shortcut'
$shortcut.Padding = (New-Object -TypeName System.Windows.Forms.Padding -ArgumentList @([System.Int32]5))
$shortcut.Size = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]140,[System.Int32]32))
$shortcut.TabIndex = [System.Int32]7
$shortcut.Text = [System.String]'Create Shortcut'
$shortcut.UseVisualStyleBackColor = $true
#
#AppContainer
#
$AppContainer.ClientSize = (New-Object -TypeName System.Drawing.Size -ArgumentList @([System.Int32]599,[System.Int32]489))
$AppContainer.Controls.Add($shortcut)
$AppContainer.Controls.Add($processName)
$AppContainer.Controls.Add($helpText)
$AppContainer.Controls.Add($processPath)
$AppContainer.Controls.Add($results)
$AppContainer.Controls.Add($processArray)
$AppContainer.Controls.Add($runningProcess)
$AppContainer.Controls.Add($getRunningProcess)
$AppContainer.StartPosition = [System.Windows.Forms.FormStartPosition]::CenterScreen
$AppContainer.Text = [System.String]'Get process path'
$AppContainer.ResumeLayout($false)
$AppContainer.PerformLayout()
Add-Member -InputObject $AppContainer -Name getRunningProcess -Value $getRunningProcess -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name runningProcess -Value $runningProcess -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name processArray -Value $processArray -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name results -Value $results -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name processPath -Value $processPath -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name helpText -Value $helpText -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name processName -Value $processName -MemberType NoteProperty
Add-Member -InputObject $AppContainer -Name shortcut -Value $shortcut -MemberType NoteProperty
}
. InitializeComponent

gpp.ps1

Here we show the form dialogue GUI and add click event to the Find process path button.

It should also throw an error if you typed a process that do not exist or is not actually running in your machine.

As a extra feature I made couple of action accessible from the keyboard, such as Exit the GUI if you press ESC, also you can run the click event for the button Find process path using ENTER.

# Import designer and utility functions

Add-Type -AssemblyName System.Windows.Forms
. (Join-Path $PSScriptRoot 'gpp.designer.ps1')
. (Join-Path $PSScriptRoot 'utils.ps1')

[System.Windows.Forms.Application]::EnableVisualStyles()

# Enable some keyboard shortcut

$AppContainer.KeyPreview = $true

$AppContainer.Add_KeyDown({

    if ($_.KeyCode -eq "Enter")
    {
        # if enter, perform click
        $getRunningProcess.PerformClick()
    }

})

$AppContainer.Add_KeyDown({

    if ($_.KeyCode -eq "Escape")
    {
        # if escape, exit
        $AppContainer.Close()
    }
})

# Add click event.
# Should append the process path to a TextBox or else print an error message.

$getRunningProcess.add_Click({

    $results.Clear()

    $processes = $processArray.Text.Split(",")

    if(([string]::IsNullOrWhitespace($processes))) {

        $results.AppendText("Error: You must enter a valid process name")

        InvalidProcessName

        $results.Clear()

        return

    }
    else {

        Write-Host "`n Getting process path for: $processes" -ForegroundColor Green

        $paths = GetRunningProcessPath $processes

        $paths | ForEach-Object {

            $results.AppendText("`r`n")

            $results.AppendText($_)

            $results.AppendText("`r`n")

        }

    }

})

# Add a click event to handle adding a desktop shortcut, else throw a error message.
# If the desktop shortcut already exist, it will throw an error as it can't be overridden.
# Creating a shortcut require elevation.

$shortcut.add_Click({

    $processes = $processArray.Text.Split(",")

    if(([string]::IsNullOrWhitespace($processes))) {

            $results.AppendText("Error: You must enter a valid process name")

            InvalidProcessName

            $results.Clear()

            return

    }
    else {

        $paths = GetRunningProcessPath $processes

        $paths | ForEach-Object {

            CreateShortcut $_

        }

    }


})

# Open the GUI

$AppContainer.ShowDialog()

$AppContainer.Dispose()

utils.ps1

  • GetRunningProcessPath, here we get the process Name first then we pipe it to the Property Path and we will get only unique path if a process has multiple instances, example: Chrome, Edge.

  • InvalidProcessName, will show a dialogue with a text error if a process you typed do not exist or not currently running.

  • CreateShortcut, if pretty self explanatory, it create a desktop shortcut of the application.

  • ShortcutExist, if shortcut was already created show a modal dialogue with an error as it can't be created again.

function GetRunningProcessPath() {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [System.Object]$processes
    )

    $processesPath = @()

    foreach ($process in $processes) {

        try {

            if($null -ne (Get-Process | Where-Object {$_.Name -like "$process*"} | Select-Object -Property Path | Sort-Object -Unique)) {

                $processesPath += Get-Process | Where-Object {$_.Name -like "$process*"} | Select-Object -Property Path | Sort-Object -Unique

            }
            else {

                Write-Host "`n > Process $process not found" -ForegroundColor Red

                $processesPath += [PSCustomObject]@{
                    Path = "Process $process not found"
                }

            }

        }
        catch {

            Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red

        }

    }

    #$processesPath | Out-GridView -Title "Process Path" -PassThru | Out-Null

    $sb = New-Object -TypeName System.Text.StringBuilder

    $processesPath | ForEach-Object{

        $temp = $sb.AppendLine(("`n > $($_.Path)"))

    }

    Write-Host $sb.ToString()

    return $processesPath.Path

}

#GetRunningProcessPath -process @("sharex", "windowsterminal", "openvpn", "pptxtopdf","Wsdfreur987wef9sd")

function InvalidProcessName() {

    [void] [System.Windows.Forms.MessageBox]::Show(

        "Error: You must enter a valid process name",

        "Error",

        "OK",

        "Error"
    )

}

function CreateShortcut() {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory=$true)]
        [System.Object]$processesPath
    )

    $app = Split-Path -Path $processesPath -Leaf -Resolve

    $desktopPath = [Environment]::GetFolderPath("Desktop")

    try {

        if(Test-Path -Path $desktopPath\$app.lnk) {

            ShortcutExist

        }
        else {

            New-Item -ItemType SymbolicLink -Path $desktopPath -Name "$app.lnk" -Value $processesPath

        }

    }
    catch {

        Write-Host "Error: $($_.Exception.Message)" -ForegroundColor Red

    }

}

function ShortcutExist() {

    [void] [System.Windows.Forms.MessageBox]::Show(

        "Error: Cannot create symbolic link because the path C:\Users\reg\Desktop\Discord.exe.lnk already exists.",

        "Error",

        "OK",

        "Error"
    )

}

Show Comments