2

I have a PS script to monitor a logging file for a specific list of servers in the network. If the script logic finds the issue I'm monitoring for, I want to interrupt the script process with a launch and wait of windows explorer for the related server network folder path.

Windows explorer does show the requested folder, however PS doesn't wait for it to close.

This is the script I'm testing with:

# Sample networkfolderpath
$networkfolderpath = '\\server\d$\parent\child'

Start-Process explorer.exe -ArgumentList $networkfolderpath -Wait

FYI: I have a RDP function that is setup the same way and it does wait as expected.

Start-Process mstsc /v:$computername -Wait  

I'm presuming at this point that windows explorer just behaves differently than some other exe.

What am I missing?

Michael
  • 45
  • 5
  • 2
    It only works with `mstsc` because closing the main window is the same as closing the process. For Explorer, you'll need to open the folder window and then prompt the user for continuation (eg. `Invoke-Item $networkfolderpath; $null = Read-Host "Edit the files, then hit enter to continue..."`) – Mathias R. Jessen Feb 07 '22 at 17:10
  • Thank you! Does the job I need! – Michael Feb 07 '22 at 17:22

2 Answers2

2

As mentioned in the comments, the example with mstsc only works because there's a 1-to-1 relationship between closing the main window it produces and exiting the process.

This relationship does not exist with explorer - it'll detect on launch that the desktop session already has a shell, notify it of the request, and then exit immediately.

Instead, use Read-Host to block further execution of the script until the user hits enter:

# launch folder window
Invoke-Item $networkfolderpath
# block the runtime from doing anything further by prompting the user (then discard the input)
$null = Read-Host "Edit the files, then hit enter to continue..."
Mathias R. Jessen
  • 157,619
  • 12
  • 148
  • 206
0

Here is some proof-of-concept code that opens the given folder and waits until the new shell (Explorer) window has been closed.

This is made possible by the Shell.Application COM object. Its Windows() method returns a list of currently open shell windows. We can query the LocationURL property of each shell window to find the window for a given folder path. Since there could already be a shell window that shows the folder we want to open, I check the number of shell windows to be sure a new window has been opened. Alternatively you could choose to bring an existing shell window to front. Then just loop until the Visible property of the shell window equals $False to wait until the Window has been closed.

Function Start-Explorer {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)] [String] $Path,
        [Parameter()]          [Switch] $Wait
    )

    $shell = New-Object -ComObject Shell.Application

    $shellWndCountBefore = $shell.Windows().Count

    Invoke-Item $Path

    if( $wait ) {
        Write-Verbose 'Waiting for new shell window...'

        $pathUri = ([System.Uri] (Convert-Path $Path)).AbsoluteUri

        $explorerWnd = $null 

        # Loop until the new shell window is found or timeout (30 s) is exceeded.
        foreach( $i in 0..300 ) {
            if( $shell.Windows().Count -gt $shellWndCountBefore ) {
                if( $explorerWnd = $shell.Windows() | Where-Object { $_.Visible -and $_.LocationURL -eq $pathUri }) {
                    break
                }
            }
            Start-Sleep -Milliseconds 100
        }

        if( -not $explorerWnd ) {
            $PSCmdlet.WriteError( [Management.Automation.ErrorRecord]::new( 
                [Exception]::new( 'Could not find shell window' ), 'Start-Explorer', [Management.Automation.ErrorCategory]::OperationTimeout, $Path ) )
            return
        }

        Write-Verbose "Found $($explorerWnd.Count) matching explorer window(s)"
        #Write-Verbose ($explorerWnd | Out-String)

        Write-Verbose 'Waiting for user to close explorer window(s)...'

        try {
            while( $explorerWnd.Visible -eq $true ) {
                Start-Sleep -Milliseconds 100
            }
        }
        catch {
            # There might be an exception when the COM object dies before we see Visible = false
            Write-Verbose "Catched exception: $($_.Exception.Message)"
        }

        Write-Verbose 'Explorer window(s) closed'
    }
}

Start-Explorer 'c:\' -Wait -Verbose -EA Stop
zett42
  • 25,437
  • 3
  • 35
  • 72