Pojawił się zestaw ostatnio zadawanych pytań dotyczących robienia czegoś z Internet Explorerem za pośrednictwem PowerShell. Wszystkie zawierają kody do uruchamiania IE z PowerShell jako obiektu, poprzez $ie=new-object -comobject InternetExplorer.Application
. Problem polega na tym, że właściwa metoda blokowania IE, która składa się z wywołania $ie.quit()
, nie działa - po pierwsze, jeśli IE miałby mieć więcej niż jedną otwartą kartę, IE nie wychodzi jako całość i tylko karta który odpowiada obiektowi COM jest zamknięty, a po drugie, jeśli ma tylko jedną kartę, okno zostaje zamknięte, ale procesy pozostają.Jak prawidłowo zamknąć Internet Explorer po uruchomieniu z PowerShell?
PS > get-process iexplore
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
352 31 7724 24968 142 0,58 3236 iexplore
228 24 22800 15384 156 0,19 3432 iexplore
Próbowałem metod badawczych, jak zamknąć proces rozpoczęty przez New-Object -ComObject
, i odkryli to: How to get rid of a COMObject. Przykładem tego COMObject jest Excel.Application
, który rzeczywiście zachowuje się zgodnie z przeznaczeniem - wywołanie quit()
powoduje zamknięcie okna, a wykonanie [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ex)
, jeśli $ex
jest utworzonym COMObject, zatrzymuje proces Excel. Ale tak nie jest w przypadku Internet Explorera.
Znalazłem również to pytanie: How to get existing COM Object of a running IE, które zapewnia kod do łączenia się z IE za pośrednictwem listy otwartych okien i działa w pewnym zakresie IE uruchamiany z innego miejsca, ale jeśli obiekt COM jest tworzony za pomocą PowerShell, ten skrypt nie jest w stanie całkowicie powstrzymać procesy tj, w przypadku zmian jako takich:
$shellapp = New-Object -ComObject "Shell.Application"
$ShellWindows = $shellapp.Windows()
for ($i = 0; $i -lt $ShellWindows.Count; $i++)
{
if ($ShellWindows.Item($i).FullName -like "*iexplore.exe")
{
$ie = $ShellWindows.Item($i)
$ie.quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie)
}
}
w przypadku IE uruchomiony poza PowerShell, procesy są zatrzymane, ale w przypadku IE uruchomiony w ciągu PowerShell dwa procesy pozostają, a to raporty kod nie znaleźli okien IE, aby dotrzeć do obiektów COM, dlatego procesy IE (jeszcze) nie mogą zostać zatrzymane.
A zatem, jak osiągnąć pozornie osierocone procesy bez okien IE i z wdziękiem je zatrzymać? Jestem świadomy Get-Process iexplore | Stop-Process
, ale to zatrzyma wszystkie IE, nie tylko te uruchomione przez skrypt, a jeśli skrypt zostanie uruchomiony jako administrator lub SYSTEM
na, powiedzmy, serwerze zdalnego pulpitu, wszystkie IE zostaną zatrzymane.
Środowisko: System operacyjny Windows 7 x64, PowerShell 4 (zainstalowany powyżej wersji PS 2), wersja IE11 11.0.9600.17691 (automatycznie aktualizowany). IE ustawiony na "Otwórz stronę początkową" po uruchomieniu, więc przynajmniej jedna zakładka jest zawsze otwarta.
Swoją drogą, właśnie tego próbowałem i zauważyłem interesującą rzecz. Kiedy wywołuję '[Runtime.Interopservices.Marshal] :: ReleaseComObject()' w stosunku do utworzonego COMObject IE zwraca wartość różną od zera - to najwyraźniej wskazuje, że jest więcej linków do tego obiektu COM w systemie. Również w moim przypadku rozpoczęto trzy procesy, a nie dwa. Może się to różnić w zależności od wersji IE i wersji systemu operacyjnego, więc sprawdzę ponownie na innych komputerach. Jak dotąd wygląda jak błąd wprowadzony w IE11 lub błąd w .NET 4.5, jeśli problem ten pojawiłby się również na komputerze z Win8.1 i IE11 (który nie jest dostępny teraz). – Vesper
Hmm, może to być spowodowane tym, że system operacyjny to x64, dwa pozostałe procesy to jeden x64 i jeden x32, a zabicie tylko x32 daje efektowne zatrzymanie x64. Tak naprawdę może to być (jeszcze jeden) błąd w IE jawnie :) – Vesper
@Vesper Wątpię. Demonstracja w mojej odpowiedzi pochodzi także z 64-bitowego systemu Windows 8.1 (z Internet Explorerem 11). –