0

I searched but didn't find anything that specifically addresses this question.

Consider the code, can the new IE window be created in front of all other open windows? VBScript had the Run Method (Windows Script Host) that offered intWindowStyle Optional. Integer value indicating the appearance of the program's window. Note that not all programs make use of this information.

Does Powershell's new com object have anything similar?

Param(
[Parameter(Mandatory=$false)]
[string]$svr,
[Parameter(Mandatory=$false)]
[string]$last,
[Parameter(Mandatory=$false)]
[string]$desc,
[Parameter(Mandatory=$false)]
[string]$date)
$ie = new-object -comobject InternetExplorer.Application
$ie.navigate("http://www.stackoverflow.com")
# Wait for the page to finish loading
 do {sleep 1} until (-not ($ie.Busy))
$doc = $ie.document
$link = $doc.getElementById("Sym_Msg").Value = "$svr"
$link = $doc.getElementById("Lname").Value = "$last"
$link = $doc.getElementById("Desc").Value = "$desc"
$link = $doc.getElementById("Date_Ent").Value = "$date"
$button = $doc.getElementById("submit1")
$ie.Visible = $true
$button.click();
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie) | Out-Null
user4317867
  • 2,397
  • 4
  • 31
  • 57
  • Do you want the window put on top of all others, or merely in the foreground? – Nathan Tuggy Dec 24 '14 at 02:48
  • The goal is to get the newly opened IE window to be on top of all others. Windows will make the IE icon in the task bar flash but I'm aiming for something even more user friendly. – user4317867 Jan 01 '15 at 00:00

4 Answers4

2

Unfortunately I don’t think this is part of ‘new-object’. There are several PowerShell extensions that implement this as cmdlet (Such as http://pscx.codeplex.com/ "Set-ForegroundWindow").

The way this is implemented is a call to "user32.dll".

In your code this should work:

#Load DLL
$pinvoke = '[DllImport("user32.dll")] public static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow)'   
Add-Type -MemberDefinition $pinvoke -name NativeMethods -namespace Win32

#Get WindowHandle of the COM Object
$hwnd = $ie.HWND

# Minimize window
[Win32.NativeMethods]::ShowWindowAsync($hwnd, 2)

# Restore window
[Win32.NativeMethods]::ShowWindowAsync($hwnd, 4)

--Edited to add ' after nCmdShow)

user4317867
  • 2,397
  • 4
  • 31
  • 57
Jan Chrbolka
  • 4,184
  • 2
  • 29
  • 38
  • Thank you Jan, ended up using the Restore method and now the newly created IE window appears in front of other IE windows. Strangely enough, it's still behind the HTA application I'm launching the PS1 scripts from. – user4317867 Dec 24 '14 at 02:57
  • You may have better luck with Nathans variant below. Using the SetWindowPos function from the same DLL and setting hWndInsertAfter to -1 may work better. Haven’t tested this myself. – Jan Chrbolka Dec 24 '14 at 03:11
1

This was incredibly helpful for me. I needed to do the same with a windows form, not IE, and so I needed to do a few tweaks. I borrowed the form creation code from someone else on the internet.

This works great when the SCCM client executes a script-based installer.

In particular I had to add the following at the end, and tweak a few other things:

$appContext = New-Object System.Windows.Forms.ApplicationContext 
[void][System.Windows.Forms.Application]::Run($appContext)

Here's the code I used:

Add-Type -AssemblyName PresentationFramework, System.Drawing, System.Windows.Forms, WindowsFormsIntegration

    $objForm = New-Object System.Windows.Forms.Form 
    $objForm.Text = "Test"
    $objForm.Size = New-Object System.Drawing.Size(400,200) 
    $objForm.StartPosition = "CenterScreen"
    $objform.icon = "$StrInstDir\source\favicon.ico"

    $objForm.KeyPreview = $True
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Enter") 
        {$output = "OK";$objForm.Close()}})
    $objForm.Add_KeyDown({if ($_.KeyCode -eq "Escape") 
        {$output = "Cancel";$objForm.Close()}})

    $OKButton = New-Object System.Windows.Forms.Button
    $OKButton.Location = New-Object System.Drawing.Size(105,120)
    $OKButton.Size = New-Object System.Drawing.Size(75,23)
    $OKButton.Text = "OK"
    $OKButton.Add_Click({$global:output="OK";$objForm.Close()})
    $objForm.Controls.Add($OKButton)

    $CancelButton = New-Object System.Windows.Forms.Button
    $CancelButton.Location = New-Object System.Drawing.Size(220,120)
    $CancelButton.Size = New-Object System.Drawing.Size(75,23)
    $CancelButton.Text = "Cancel"
    $CancelButton.Add_Click({$global:output = "Cancel";$objForm.Close()})
    $objForm.Controls.Add($CancelButton)

    $objform.Add_Closing({[System.Windows.Forms.Application]::Exit()})

    $objLabel = New-Object System.Windows.Forms.Label
    $objLabel.Location = New-Object System.Drawing.Size(60,20) 
    $objLabel.Size = New-Object System.Drawing.Size(280,200) 
    $objLabel.Text = "Test Text"
    $objForm.Controls.Add($objLabel) 


    [void] $objForm.Show()
    $objForm.Add_Shown({$objForm.Activate()})



    $signature = @"

    [DllImport("user32.dll")]  
    public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  

    public static IntPtr FindWindow(string windowName){
        return FindWindow(null,windowName);
    }

    [DllImport("user32.dll")]
    public static extern bool SetWindowPos(IntPtr hWnd, 
    IntPtr hWndInsertAfter, int X,int Y, int cx, int cy, uint uFlags);

    [DllImport("user32.dll")]  
    public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 

    static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
    static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);

    const UInt32 SWP_NOSIZE = 0x0001;
    const UInt32 SWP_NOMOVE = 0x0002;

    const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

    public static void MakeTopMost (IntPtr fHandle)
    {
        SetWindowPos(fHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
    }

    public static void MakeNormal (IntPtr fHandle)
    {
        SetWindowPos(fHandle, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
    }
"@
    $hWnd = $objform.handle
    $app = Add-Type -MemberDefinition $signature -Name Win32Window -Namespace ScriptFanatic.WinAPI -ReferencedAssemblies System.Windows.Forms -Using System.Windows.Forms -PassThru
    $null = $app::MakeTopMost($hWnd)
    $objform.Visible = $true

    $appContext = New-Object System.Windows.Forms.ApplicationContext 
    [void][System.Windows.Forms.Application]::Run($appContext)
0

For future reference, the only way to make a window topmost involves some P/Invoke digging into Win32 APIs. Fun stuff, especially from PowerShell!

Add-Type -Namespace PInvoke -Name SWP '[DllImport("user32.dll", SetLastError=true)] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, int uFlags);'
[PInvoke.SWP]::SetWindowPos($hWnd, -1, 0, 0, 0, 0, 3)

This code was cobbled together from this answer, Lee Holmes' old blog post on P/Invoke in PoSh, and the pinvoke.net/MSDN docs.

Community
  • 1
  • 1
Nathan Tuggy
  • 2,237
  • 27
  • 30
  • 38
  • Thank you for the reply Nathan, it seems the IE window created still appears behind other windows. – user4317867 Dec 24 '14 at 04:40
  • Oh bother, I forgot to include my caveat that IE has some weird stuff going on with reduced privileges such that, while this does and will work on literally any other window, it won't work on IE without turning Protected Mode off or something. (You might be able to run a script in reduced-privilege mode.) – Nathan Tuggy Dec 24 '14 at 04:42
  • @user4317867, I'm gonna try digging up a workaround as mentioned, probably by running PowerShell in low-integrity. – Nathan Tuggy Dec 24 '14 at 05:16
  • Interesting, of course Protected mode is enabled. This isn't some must have feature, it would be nice to have. I'm trying to clean up this HTA to share with co-workers and want to make things as clean and easy as possible. – user4317867 Dec 24 '14 at 06:07
  • I also located this blog post, which might be helpful http://blogs.msdn.com/b/ieinternals/archive/2011/08/03/internet-explorer-automation-protected-mode-lcie-default-integrity-level-medium.aspx – user4317867 Dec 24 '14 at 06:48
  • Just an update, I doubt this is helpful but [this post](http://blogs.technet.com/b/heyscriptingguy/archive/2011/11/08/use-powershell-to-pause-a-script-while-another-process-exits.aspx) under `GetProcessInfoDisplayHTMLtrackProcessAndRemoveTmpFile.ps1` seemingly starts IE and captures its `PID` – user4317867 Mar 17 '15 at 06:33
0

Finally with the pointer from @Nathan Tuggy, I discovered this page which ends up working great. The new IE window is created then brought to the front of all open windows.

Summary of code in PowerShell to create a new IE ComObject and bring it to the front.

$ie = New-Object -ComObject InternetExplorer.Application
$ie.navigate("http://www.stackoverflow.com")
do {sleep 1} until (-not ($ie.Busy))
$signature = @"

[DllImport("user32.dll")]  
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);  

public static IntPtr FindWindow(string windowName){
    return FindWindow(null,windowName);
}

[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, 
IntPtr hWndInsertAfter, int X,int Y, int cx, int cy, uint uFlags);

[DllImport("user32.dll")]  
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); 

static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);

const UInt32 SWP_NOSIZE = 0x0001;
const UInt32 SWP_NOMOVE = 0x0002;

const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

public static void MakeTopMost (IntPtr fHandle)
{
    SetWindowPos(fHandle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}

public static void MakeNormal (IntPtr fHandle)
{
    SetWindowPos(fHandle, HWND_NOTOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);
}
"@
$hWnd = $ie.HWND
$app = Add-Type -MemberDefinition $signature -Name Win32Window -Namespace ScriptFanatic.WinAPI -ReferencedAssemblies System.Windows.Forms -Using System.Windows.Forms -PassThru
$null = $app::MakeTopMost($hWnd)
$ie.Visible = $true
$button.click();
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ie) | Out-Null
user4317867
  • 2,397
  • 4
  • 31
  • 57