After $IE.Quit(), the Internet Explorer still exists in Task manager - powershell

My case happens when I run $IE.quit() already, but internet explorer still exists in the task manager.
if I run the quit function at "quit IE 1" there, the Internet Explorer will close/end (not exits in Task Manager),
but when I run it at "quit IE 2" there, the IE not end (still exist in Task Manager)
if run with $IE.Visible = $true it has no such problem.
Environment: Windows Server 2016, PowerShell v5.1
May I know what may cause this?
May I know after the "confirm page loaded", what happened to $IE? And possibly cause IE not to quit.
Or how I can trace this kind of problem?
I do try to run this without try/catch, but the same thing happens. I try to put $IE = null, but the same, while, the $IE.Quit() description as to force the end of IE, suppose no wonder what is running on the IE. It will end the task.
Here is the PowerShell script:
$looping = 10
timenowhms = (Get-Date -f HH:mm:ss)
try {
$Url = "http://localhost:8080/commandcenter/checking.aspx"
$IE = New-Object -Com InternetExplorer.Application
$IE.Height = 700
$IE.Width = 750
$IE.Top = 10
$IE.Left = 10
$IE.Visible = $false; # can turn on for testing purpose
$IE.Navigate2($url);
$IEPID = [IntPtr]::Zero
[Win32Api]::GetWindowThreadProcessId($IE.HWND, [ref]$IEPID);
# quit IE 1
$IE.Quit();
} catch {
$timenowhms = (Get-Date -f HH:mm:ss);
echo "$td_date $timenowhms Open website failed";
if ((Get-Process -Name "iexplore*" | ? {$_.Id -eq $IEPID} | measure).Count -eq 1) {
Stop-Process -Id $IEPID -force
};
exit 1
}
# confirm page loaded
while ($ie.Busy -eq $true) {
if ($looping -eq 0) {
$timenowhms = (Get-Date -f HH:mm:ss);
echo "$td_date $timenowhms Timeout, page not show";
if ((Get-Process -Name "iexplore*" | ? {$_.Id -eq $IEPID} | measure).Count -eq 1) {
Stop-Process -Id $IEPID -Force
};
exit 1
} else {
Start-Sleep -Milliseconds 2500;
$looping--;
}
}
# quit IE 2
# $IE.Quit();
exit

Related

powershell click on internet explorer popup

I need to use PowerShell to hit close on this pop up window which appears when I open internet explorer. Hitting enter key also closes the pop up.
What I've tried
[void] [System.Reflection.Assembly]::LoadWithPartialName("'System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("'Microsoft.VisualBasic")
$ie = new-object -com internetexplorer.application
$ie.visible = $true
$ie.navigate('http://website/')
while ($ie.busy) { Start-Sleep 3 }
[Microsoft.VisualBasic.Interaction]::AppActivate("internet explorer")
[System.Windows.Forms.SendKeys]::Sendwait("{ENTER}");
Start-Sleep 3
$link = $ie.Document.getElementsByTagName('Button') | where-object { $_.innerText -eq 'Simple Setup' }
$link.click()
Start-Sleep 2
$ie.quit()
Continuing from my comment.
Others have run into this dialog and others, and, as stated, used Selenium, AutoIT, et., to deal with that; while others have tried different means.
For Example:
# using the process handle of that dialog
$ws = New-Object -ComObject WScript.Shell
$ld = (gps iex* | where {$_.MainWindowTitle }).id
if($ld.Count -gt 1)
{
$ws.AppActivate($ld[1])
$ws.sendkeys("{ENTER}")
}
# Using the WASP module
# (note - though the code for this module is still available, the DLL is not. So, you have to compile that yourself.)
Import-Module WASP
while ($true) {
[System.Threading.Thread]::Sleep(200)
$confirmation = Select-Window iexplore
if ($confirmation -ne $null)
{
Select-ChildWindow -Window $confirmation |
Select-Control -title "OK" -recurse |
Send-Click
}
}
btw..
"Hitting enter key also closes the pop up"
... that is because modal dialogs always take focus until they are dismissed.

How to limit while loop by time in powershell

I have a script which starts a process only after specific service is running.
It's a loop that's trying to Get-Service its status.
I can't find how to limit loop by time.
The part where I'm stuck:
#add Start button
$button_start = New-Object System.Windows.Forms.Button
$button_start.Location = New-Object System.Drawing.Size(25,70)
$button_start.Size = New-Object System.Drawing.Size(240,32)
$button_start.TextAlign = "MiddleCenter"
$button_start.font = New-Object System.Drawing.Font("Segoe UI",14,[System.Drawing.FontStyle]::Regular)
$button_start.BackColor = "seashell"
$button_start.Text = "Start"
$button_start.Add_Click({
#add statement
while ((Get-Service -ComputerName $textBox_IP.text -ServiceName wscsvc).Status -ne "Running") {
# Pause before next check
Start-Sleep -Seconds 1
}
#only then..
Start-Process -FilePath "C:\Users\username\Desktop\software.exe" -verb RunAs -ArgumentList $textBox_IP.text
})
$Form_remoteControl.Controls.Add($button_start)
I've tried internet searching information on network without any success.
Define a time limit and check if the current time exceeds that limit.
$limit = (Get-Date).AddMinutes(5)
while (... -or (Get-Date) -le $limit) {
Start-Sleep -Seconds 1
}
If you want to skip starting the external program when the service still isn't running after that add another check after the loop upon which you return:
if ((Get-Service ...).Status -ne "Running") {
return
}
This is an example how to stop a service and wait until it is stopped or timeout applies.
You can modify to start a service.
Function StopService ($serv)
{
Write-Host "Config service " $serv " ..."
$service = Get-Service $serv -ErrorAction SilentlyContinue
if ($service)
{
if($service.status -eq "running")
{
write-host "Stop service" $serv
Stop-Service $serv -Force
# Wait until service is stopped (max. 1 minute)
$acttime = 0
$waittime = 100
$maxtime = 60000
$TestService = Get-Service $serv
While($TestService | Where-Object {$_.Status -eq 'Running'})
{
Start-Sleep -m $waittime
$acttime += $waittime
if ($acttime -gt $maxtime)
{
write-host "ERROR: Service" $serv " could not be stopped!" -ForegroundColor Red
return $False
}
}
}
else
{
write-host "Service already stopped!" -ForegroundColor Green
return $True
}
}
else
{
write-host "Service not installed" -ForegroundColor Green
return $True
}
}
I recommend you not using any polling While loops (with Start-Sleep cmdlets) in a Windows forms interface. It will stall your interface for important form events as button clicks etc.
Instead, I would anticipate on the Windows.Forms Timer class by creating a timer event and take appropriate checks and actions after a certain time period (e.g. a new Start-Process depending on a service state).

Open a set of URLs in IE if another URL is open using PowerShell

On the second run of this script, I can open Microsoft and Yahoo if I first close Bing; how can I open those sites without first closing Bing? The error:
Method invocation failed because [System.Object[]] doesn't contain a method named 'Navigate2'.
+ $ie.Navigate2 <<<< ("www.microsoft.com", $navOpenInNewTab);
+ CategoryInfo : InvalidOperation: (Navigate2:String) [], Runtime Exception
+ FullyQualifiedErrorId : MethodNotFound
Why does it fail when I have Bing and Google open, but not when I have Google open?
# Set BrowserNavConstants to open URL in new tab
# Full list of BrowserNavConstants: https://msdn.microsoft.com/en-us/library/aa768360.aspx
$navOpenInNewTab = 0x800;
$navOpenInBackgroundTab = 0x1000;
$ie = $null
if (Get-Process iexplore -ea silentlycontinue | Where-Object {$_.MainWindowTitle -ne ""}) {
$ie = (New-Object -COM "Shell.Application").Windows() | ? { $_.Name -eq "Internet Explorer" }
} else {
$ie = New-Object -COM "InternetExplorer.Application"
sleep -milliseconds 50
$ie.visible = $true
}
$today = (get-date).DayOfWeek
switch ($today) {
"Someday" {
$ie.Navigate("www.bing.com");
$ie.Navigate2("www.yahoo.com", $navOpenInBackgroundTab); break
}
default {
$google = $false
# Check if Google open
foreach ($tab in $ie) {
if ($tab.LocationURL.Contains("google"))
{ $google = $true; break }
}
# If Google open on second run, open Microsoft and Yahoo
if ($google) {
$ie.Navigate2("www.microsoft.com", $navOpenInNewTab);
$ie.Navigate2("www.yahoo.com", $navOpenInBackgroundTab);
} else {
# On first run, open Bing and Google
$ie.Navigate("www.bing.com");
$ie.Navigate2("www.google.com", $navOpenInBackgroundTab);
}
break
}
}
# Cleanup
'ie' | ForEach-Object {Remove-Variable $_ -Force}
Your problem seems to be, that the script fails to find (the right) open IE instance on the second run. Debug the Script in the PowerShell ISE (or the PowerShell PowerGUI) and set a breakpoint at $ie=(New-Object -COM "Shell.Application").Windows() | ? {$_.Name -eq "Internet Explorer"}
Run the following command in the interactive PowerShell Window below: (New-Object -COM "Shell.Application").Windows() | Select-Object { $_.Name }
Do you get something like this as output?
File Explorer
Internet Explorer
Internet Explorer
Internet Explorer
Internet Explorer
Try to adjust your code as needed when your IE windows have different Names.
The following code works on my machine: I select just the first IE instance (otherwise you get problems since you open multiple sites).
...
# If Google open on second run, open Microsoft and Yahoo
if ($google) {
sleep -milliseconds 50
$ie[0].Navigate2("www.microsoft.com", $navOpenInBackgroundTab);
sleep -milliseconds 50
$ie[0].Navigate2("www.yahoo.com", $navOpenInBackgroundTab);
} else { ...

How to ensure IIS website is completely stopped in Powershell?

I've got a Powershell script that stops an IIS website and corresponding app pool and then deletes the app logs (log4net logs). Here is the script snippet:
stop-website -name "MyWebsite"
stop-webapppool -name "MyWebsite"
del c:\inetpub\MyWebsite\logs\*.*
The problem is stop-website and stop-webapppool seem to return before the website is completely shutdown which results in the delete failing saying the file is being used by another process:
del : Cannot remove item C:\inetpub\MyWebsite\logs\App.log: The process cannot access the file 'C:\inetpub\MyWebsite\logs\App.log' because it is being used by another process.
If I add a 10 second sleep between the stop commands and the del command then the logs are deleted successfully. This is very hackish though and not reliable. Is there a way to force the stop-website/stop-webapppool commands to not return until the website/apppool is completely stopped?
Thanks.
Implemented solution from the below link. I will wait ~60 seconds and then kill the IIS process if it hasn't stopped.
https://greenfinch.ie/blog/powershellscript.html
"Stopping IIS site [$name]" >> $logFile
stop-website -name $name
"Stopping app pool [$name]" >> $logFile
stop-webapppool -name $name
$sleepTime = 5
$processId = $TRUE
while ($processId)
{
$processId = Get-WmiObject -Class win32_process -filter "name='w3wp.exe'" |
?{ ($_.CommandLine).Split("`"")[1] -eq $name } |
%{ $_.ProcessId }
if ($sleepTime -gt 60)
{
"Waited [$sleepTime] sec for process [$processId] to stop and it is still running. Killing it." >> $logFile
Stop-Process $processId
break
}
if ($processId)
{
"App pool [$name] is running with process ID: [$processId]. Sleeping for [$sleepTime] sec and then checking again." >> $logFile
Start-Sleep -s $sleepTime
$sleepTime = $sleepTime + 10
}
}
You can use these two commands to check the status of the website/app, say after 10 seconds, then use an If statement to delete logs only when the status returned is stopped
Get-WebsiteState -name "MyWebsite"
Get-WebAppPoolState -name "MyWebsite"
This loop should help you too
$currentRetry = 0;
$success = $false;
do{
$status = Get-WebAppPoolState -name "MyWebsite"
if ($status -eq "Stopped"){
<....your code here....>
$success = $true;
}
Start-Sleep -s 10
$currentRetry = $currentRetry + 1;
}
while (!$success -and $currentRetry -le 4)
Updated Apr 24, 2019
Based on comment and current cmdlet document, it appears the return type is indeed an object. Thus presumably can be handled as commented or the line snippet below. Author no longer have access to Windows Server environment therefore did not directly modify original answer nor able to test the update
if ($status.Value -eq "Stopped")
After you run 'Stop-WebAppPool' the state of the WebAppPool will be "Stopping" and it may take a few seconds before the state of the WebAppPool is actually "Stopped".
Here is a little function to help with the WebAppPoolState
function Stop-AppPool ($webAppPoolName,[int]$secs) {
$retvalue = $false
$wsec = (get-date).AddSeconds($secs)
Stop-WebAppPool -Name $webAppPoolName
Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
$poolNotStopped = $true
while (((get-date) -lt $wsec) -and $poolNotStopped) {
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if ($pstate.Value -eq "Stopped") {
Write-Output "$(Get-Date): WebAppPool '$webAppPoolName' is stopped"
$poolNotStopped = $false
$retvalue = $true
}
}
return $retvalue
}
you can run this function using e.g.
Stop-AppPool "MyWebsite" 30
and check the return-value to see if the WebAppPool has stopped within the given seconds
The simplest way to stop the app pool and get it into Stopped state is to use appcmd.exe. It will return when the app pool is really stopped or you'll get an error
Just do this on PowerShell:
& $env:windir\system32\inetsrv\appcmd.exe stop apppool /apppool.name:"YourAppPoolName"
When your AppPool is correctly stooped you'll get this message:
"YourAppPoolName" successfully stopped
I fix the #user4531 code It would be failed if the app pool is stopped before :
function Stop-AppPool ($webAppPoolName,[int]$secs) {
$retvalue = $false
$wsec = (get-date).AddSeconds($secs)
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if($pstate.Value -eq "Stopped") {
Write-Output "WebAppPool '$webAppPoolName' is stopped already"
return $true
}
Stop-WebAppPool -Name $webAppPoolName
Write-Output "$(Get-Date) waiting up to $secs seconds for the WebAppPool '$webAppPoolName' to stop"
$poolNotStopped = $true
while (((get-date) -lt $wsec) -and $poolNotStopped) {
$pstate = Get-WebAppPoolState -Name $webAppPoolName
if ($pstate.Value -eq "Stopped") {
Write-Output "WebAppPool '$webAppPoolName' is stopped"
$poolNotStopped = $false
$retvalue = $true
}
}
return $retvalue
}
It can use like this :
Stop-AppPool "SSO" 30
Here is how I did it with Get-IISServerManager.
$manager = Get-IISServerManager
$site = $manager.Sites["mySiteName"]
if($site.State -ne "Stopped") {
$site.Stop()
}
while ($site.State -ne "Stopped") {
"waiting 1 second for site to stop..."
Start-Sleep -s 1
}
"site stopped"

Windows Server 2008 R2 PowerShell and Internet Explorer 9

This is a Powershell script that runs just fine under Server 2003. We're needing to move to Server 2008 R2 and the script isn't working. Specifically the script is not sleeping while waiting for IE to finish loading the page.
$objIE = New-Object -ComObject "InternetExplorer.Application"
if($objIE.ReadyState -notmatch "0|1|2|3|4")
{
$objIE = [System.Runtime.InteropServices.Marshal]::GetActiveObject("InternetExplorer.Application")
if($objIE.ReadyState -notmatch "0|1|2|3|4")
{
Stop-Process -processname iexplore
$objIE = New-Object -ComObject "InternetExplorer.Application"
}
}
$objIE.Visible = $giShowResults
$objIE.Navigate($gsURL + "APAdmin.asp?cmd=login&loginname=" + $gsAdminName + "&password=" >>+ $gsAdminPassword)
while($objIE.Busy -eq $true)
{
$dtNow = Get-Date
Start-Sleep 1 # Sleep for one second
}
$objIE.Navigate($gsURL + "APAdmProcessClosings.asp?cmd=run&AutomatedProcess=y")
while($objIE.Busy -eq $true)
{
Start-Sleep 1 # Sleep for one second
}
When I run with Visible set to true I can see IE open, the APAdmin.asp page loads, and then the script says it's finished without running the APAdmProcessClosings.asp page.
I've searched the Net but haven't been able to find any reason why yet.
It appears the Enhanced Security Configuration was the problem. Once I added the site to the list of trusted sites then the job would run successfully.