Boy! Lie down for a nap, wake up a few weeks later, and I find my name being taken in vain!!!
In my defense, aside from the
$Shell
transcription error:
- The code snippet that came from another post was offered there ass a quick example with the words "...something like...". It wasn't intended for distribution.
- My familaariy with
Shell.Application
com objects has been mainly with the Folder
& FolderItem
objects, but I had only used the Windows()
collection for closing Explorer windows, and LocationURL
was the only apparent information avaiaable on a cursory examination of the InternetExplorer
objects that comprise the collection. - The code did work within the severe limitations noted: it only worked for folders that displayed file system locations and namespace paths were lost (
This PC\Documemts
reopens to C:\Users\<UserName>\Documents
)
But with a fresh look, more research, and the all-important playtime in the
PowerShell console, I have two improved options to offer. The first is just a few lines, very similar to the code that was posted earlier in this thread, but it handles all the
permanent virtual folders,
Quick Access,
This PC,
Network,
Control Paneel, etc. as well as file sytem locations. But again, the Namespace paths are lost. For some users, that may not matter. The second option conquors the Namespace path issue. Both still have limitations regarding
Libraries
and neither can restore
Search Results...
folders.
The critical info I was unaware of earlier was how to obtain the
Folder/
FolderItem obects associated with the folder from the
InternetExplorer objects returned in the
ShellWindows collection. It turns out the associated
Folder object is a property of the window's
Document property.
Option 1 - Short & Sweet:
Code:
$Shell = New-Object -Com shell.Application
$SavedPaths = ( $Shell.Windows() | ? Name -eq 'File Explorer' ).Document.Folder.Self.Path
Get-Process explorer | Stop-Process
$SavedPaths | %{ $shell.Open(( $_ -replace ('^::','Shell:::'))) }
Option 2 - NameSpace Matters:
So while the Namespace path is not directly available from any of the associated objects, every Folder object has a ParentFolder property which itself is a Folder object. So we can construct the Namespace path for a folder by working our way back from the folder to the root of the Shell namespace, the virtual Desktop. When it's time to restore the folder, we start from the Desktop and use the Namespace path elements to obtain the
FolderItem associated with the saved fodler. So this version defines two recursvie functdions to accomplish those tasks.
A
FolderItem is roughly eqivalent in functionaality to a folder that appears as asubfolder in the Folder Pane of
Explorer, you can invoke context menu commands like
Open
,
Copy
, etc. So we can "doulbe-click" the
FolderItem ( which is internally Namespace-aware) to open
Explorer via the same path the original folder used.
Code:
Function Get-NSPath ( $oFolder ) {
If ( $oParentFolder = $oFolder.ParentFolder ) {
(( Get-NSPath $oParentFolder ) , $oFolder.Title -join '\' ).TrimStart('\')
}
}
Function Open-NSFolder ( $ParentFolder , $ChildPath ) {
If ( $Null -eq $ChildPath ) { # Target is rooted Desktop
$ParentFolder.Self.InvokeVerb() # Open target folder
} Else {
$ChildItem = $ParentFolder.Items() |
? IsFolder -eq $True |
? Name -eq $ChildPath.Split('\')[0]
If ( $ChildPath -notMatch '\\' ) { # Path leaf found
$ChildItem.InvokeVerb() # Open target folder
} Else { ### ELSE Recurese ###
Open-NSFolder $ChildItem.GetFolder ( $ChildPath -replace '^.+?\\' , '' )
}
}
}
###### Execution begins here ########
$Shell = New-Object -Com shell.Application
$SavedFolderInfo = ( $Shell.Windows() |
? Name -eq 'File Explorer').Document.Folder |
ForEach{ [PSCustomObject]@{
'IsFileSystem' = $_.Self.IsFileSystem
'FolderItemPath' = $_.Self.Path
'NameSpacePath' = Get-NSPath $_
}}
Get-Process explorer | Stop-Process
$oDesktop = $Shell.NameSpace("shell:Desktop")
$SavedFolderInfo | %{
If ( $_.IsFileSystem ) {
Open-NSFolder $oDesktop $_.NameSpacePath
} Else {
$Shell.Open( ($_.FolderItemPath -replace ('^::','Shell:::')) )
}
}
Will add additional notes later...