Reputation: 3
I am a total new comer to powershell so please forgive me if my question sounds stupid. I found the script below from Yuri Posidelov which I tweaked to activate a process and show the window and send keystrokes to shut down the process which works great. However it fails if there are two process with the same name can anyone help me with this.
param([string] $proc="SBDDesktop", [string]$adm)
cls
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class WinAp {
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
"@
$p = Get-Process |where {$_.mainWindowTItle }|where {$_.Name -like "$proc"}
if (($p -eq $null) -and ($adm -ne ""))
{
Start-Process "$proc" -Verb runAs
}
elseif (($p -eq $null) -and ($adm -eq ""))
{
Start-Process "$proc" #-Verb runAs
}
else
{
$h = $p.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h,3);
$wshell = New-Object -ComObject wscript.shell;
#$wshell.SendKeys('~')
$wshell.SendKeys('%fx')
sleep 1
$wshell.SendKeys('N')
}
#|format-table id,name,mainwindowtitle –AutoSize
# static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
# powershell.exe -windowstyle hidden -file *.ps1 -adm "a"
Upvotes: -1
Views: 119
Reputation: 308
The Get-Process
will return all the processes that match your criteria which means it will return multiple objects to the variable $p
.
So you need to iterate over them you can simply use foreach
loop
foreach($process in $p){
if (($process -eq $null) -and ($adm -ne ""))
{
Start-Process "$proc" -Verb runAs
}
elseif (($$process -eq $null) -and ($adm -eq ""))
{
Start-Process "$proc" #-Verb runAs
}
else
{
$h = $process.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h,3);
$wshell = New-Object -ComObject wscript.shell;
#$wshell.SendKeys('~')
$wshell.SendKeys('%fx')
sleep 1
$wshell.SendKeys('N')
}
}
Upvotes: 0
Reputation: 1782
If more than one windowhandle, do a loop:
$processList = [object[]]@( Get-Process |where {$_.mainWindowTItle }|where {$_.Name -like "$proc"} )
foreach( $p in $processList ) {
if (($p -eq $null) -and ($adm -ne "")) {
Start-Process "$proc" -Verb runAs
}
elseif (($p -eq $null) -and ($adm -eq "")) {
Start-Process "$proc" #-Verb runAs
}
else {
$h = $p.MainWindowHandle
[WinAp]::SetForegroundWindow($h) | Out-Null
[WinAp]::ShowWindow($h,3) | Out-Null
$wshell = New-Object -ComObject wscript.shell;
#[void]$wshell.SendKeys('~')
[void]$wshell.SendKeys('%fx')
sleep 1 | Out-Null
[void]$wshell.SendKeys('N')
}
}
Upvotes: 0
Reputation: 1884
The problem is that the line $p = Get-Process |where {$_.mainWindowTItle }|where {$_.Name -like "$proc"}
will create an object of type array
if it's more than one process. Else it will create an object of type System.ComponentModel.Component
. You can test this with:
$p.GetType()
To compensate this you can execute your code foreach
process in the array even if there is only one element in that array:
...
[array]$array = Get-Process |where {$_.mainWindowTItle }|where {$_.Name -like "$proc"}
foreach ($p in $array){
if (($p -eq $null) -and ($adm -ne ""))
{
Start-Process "$proc" -Verb runAs
}
elseif (($p -eq $null) -and ($adm -eq ""))
{
Start-Process "$proc" #-Verb runAs
}
else
{
$h = $p.MainWindowHandle
[void] [WinAp]::SetForegroundWindow($h)
[void] [WinAp]::ShowWindow($h,3);
$wshell = New-Object -ComObject wscript.shell;
#$wshell.SendKeys('~')
$wshell.SendKeys('%fx')
sleep 1
$wshell.SendKeys('N')
}
#|format-table id,name,mainwindowtitle –AutoSize
# static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
# powershell.exe -windowstyle hidden -file *.ps1 -adm "a"
}
Upvotes: 1