Folder Idle Time

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory=$true)]
        [string]$FolderPath
    )

    $shell = New-Object -ComObject Shell.Application
    $openWindows = $shell.Windows()

    $resolvedPath = (Resolve-Path -Path $FolderPath).Path

    foreach ($window in $openWindows) {
        if ($window.Document.Folder.Self.Path -eq $resolvedPath) {
            return $true
        }
    }
    return $false
}
$folderToCheck = "E:\Folder"
if (Test-ExplorerFolderOpen -FolderPath $folderToCheck) {
    Write-Host "The folder '$folderToCheck' is open in Explorer."
} else {
    Write-Host "The folder '$folderToCheck' is NOT open in Explorer."
}

How do I create a watcher to detect if a certain folder is opened in explorer.exe and have stayed opened or idled for a certain amount of time, how do I check that and then close it after X minutes/hours ?

How about using a loop with a counter or a timer and exit the loop after the counter or timer reached a certain value? :man_shrugging:

But Register-ObjectEvent System.IO.FileSystemWatcher does not watch folders, only files.

If I got you right you cannot use System.IO.FileSystemWatcher anyway because you don’t want to detect a change on a file or folder you want to detect if a GUI app is in a certain state for a certain time. :man_shrugging: … or did I get something wrong? :thinking:

If I got you wrong and you wanted to monitor folders for file changes you may read

YES, you got it right !! Im just concerned the fact that a certain folder is open in explorer.exe. I am not asking about if there are updated files.

OK … so again …

I do not know how to set a counter or timer. Can you please help ?

How about you try to figure that out first by yourself? :man_shrugging: Spend a little effort, please. If you get stuck on the way you’re welcome to come back and ask a specific question about a particular piece of code you wrote yourself.

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory=$true)]
        [string]$FolderPath
    )
    $shell = New-Object -ComObject Shell.Application
    $openWindows = $shell.Windows()

    $resolvedPath = (Resolve-Path -Path $FolderPath).Path

    foreach ($window in $openWindows) {
        if ($window.Document.Folder.Self.Path -eq $resolvedPath) {
            return $true
        }
    }
    return $false
}
$folderToCheck = "C:\"
if (Test-ExplorerFolderOpen -FolderPath $folderToCheck) {
    Write-Host "The folder '$folderToCheck' is open in Explorer."

                $countdownSeconds = 5

        for ($i = $countdownSeconds; $i -ge 1; $i--) {
            Write-Host "Time remaining: $i seconds"
                Start-Sleep -Seconds 1 
}
Write-Host "$folderToCheck is currently OPEN, please close it"

} else {
    Write-Host "The folder '$folderToCheck' is NOT open in Explorer."
}

Scripted updated. Please advise.

Since you want to …

… you actually don’t want to use a to a specific amount of time or loop count limitted loop. You rather use a while loop …

You can check inside your while loop if the Explorer window is still open. And if you want to close this Explorer window after a certain amount of idle time you check the amount of time gone by inside the loop as well.

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory=$true)]
        [string]$FolderPath
    )
    $shell = New-Object -ComObject Shell.Application
    $openWindows = $shell.Windows()

    $resolvedPath = (Resolve-Path -Path $FolderPath).Path

    foreach ($window in $openWindows) {
        if ($window.Document.Folder.Self.Path -eq $resolvedPath) {
            return $true
        }
    }
    return $false
}
$folderToCheck = "C:\"
if (Test-ExplorerFolderOpen -FolderPath $folderToCheck) {
    Write-Host "The folder '$folderToCheck' is open in Explorer."

                $count = 5

while ($count -ge 1) {
    
    Write-Host "Countdown: $count"
        Start-Sleep -Seconds 1
            $count--
}
    Write-Host "$folderToCheck is currently OPEN, please close it"

} else {
    Write-Host "The folder '$folderToCheck' is NOT open in Explorer."
}

2nd update, please advice

You should read the replies you get mor carefully …

You have to use your function Test-ExplorerFolderOpen INSIDE the while loop

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory=$true)]
        [string]$FolderPath
    )
    $shell = New-Object -ComObject Shell.Application
    $openWindows = $shell.Windows()

    $resolvedPath = (Resolve-Path -Path $FolderPath).Path

    foreach ($window in $openWindows) {
        if ($window.Document.Folder.Self.Path -eq $resolvedPath) {
            return $true
        }
    }
    return $false
}
$folderToCheck = "C:\"

                    $count = 5

while ($count -ge 1) {
    
    Write-Host "Countdown: $count"
        Start-Sleep -Seconds 1
            $count--

Write-Host "$folderToCheck is currently OPEN, please close it"

if (Test-ExplorerFolderOpen -FolderPath $folderToCheck) {
    Write-Host "The folder '$folderToCheck' is open in Explorer."
} else {
    Write-Host "The folder '$folderToCheck' is NOT open in Explorer."
}
    }

3rd update, please advice

What happens? Does the code do what you want? If not - what does it do instead?

Somewhat, yes. I tried attaching start notepad.exe, and it opened 1 for each countdown. How do I make it so when it actually reaches the end, then it performs the action, once only??

Do that more … W A Y more!!! And you should use your prefered internet search engine to look for solutions for your task. In the vast majority of the cases you’re not the very first one with a given task and the chances are usually very high that you find a solution someone shared already fitting to your challenge or needing very little adjustment.

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )
    $shell = New-Object -ComObject Shell.Application
    if($shell.Windows() | Where-Object {$_.Document.Folder.Self.Path -eq $Path}){
        $true
    }
    else {
        $false
    }
}

$Counter = 0
$Limit = 15
$Path = 'C:\_Sample\empty'

do {
    $Counter ++
    Start-Sleep -Seconds 1
    $Counter
} while (
    (Test-ExplorerFolderOpen -Path $Path) -and $Counter -lt $Limit
)
'Time is up or Explorer Window has been closed'

… of course the call for $Counter inside the loop is just for developement purposses. You should remove that later on.

Thankyou for your script. I wish to keep loop the script to keep it active. So I added while($true){your entire script} with everything the same, except for minor change at the end. However, the script runs as if its a $true condition aka folder is OPENED in explorer.exe, when in fact I closed all active explorer.exe windows. If condition is $false shouldn’t it ignore the do while ?

while($true){

function Test-ExplorerFolderOpen {
    param (
        [Parameter(Mandatory = $true)]
        [string]$Path
    )
    $shell = New-Object -ComObject Shell.Application
    if($shell.Windows() | Where-Object {$_.Document.Folder.Self.Path -eq $Path}){
        $true
    }
    else {
        $false
    }
}

$Counter = 0
$Limit = 15
$Path = 'C:\_Sample\empty'

do {
    $Counter ++
    Start-Sleep -Seconds 1
    $Counter
} while (
    (Test-ExplorerFolderOpen -Path $Path) -and $Counter -lt $Limit
)
'Time is up or Explorer Window has been closed'

                start notepad.exe     #new addition 
}

That’s the folder I used. Do you have such a folder as well?

If the script kills the desired Explorer window the needed condition for your check to keep it alive is not there anymore. :man_shrugging:

Yes, I have created that exact folder. I have included some actions after explorer.exe window is closed. But if the needed condition is not there anymore why did it still run start notepad.exe part ? How do I make it so that if condition is $false, it just reloops till it senses a $true condition ?

Because the command comes AFTER the while loop. The while loop is exited when the condition to keep it alive is not met anymore. :man_shrugging:

One way would be to create a loop around :man_shrugging: … I’d recommend to include a sleep command in that outer loop to reduce the CPU usage of the script.