2

I'm trying to run some inline C# code in PowerShell with the purpose of refreshing Windows explorer.

Here is the code (based on this question) :

function Request-ExplorerRefresh {

$code = @"
using System;
namespace VSYSRefresh
{
    public static class Util
    {

        public static void RefreshExplorer(){

            Console.WriteLine("Refreshing Explorer");
            
            Guid CLSID_ShellApplication = new Guid("13709620-C279-11CE-A49E-444553540000");
            Type shellApplicationType = Type.GetTypeFromCLSID(CLSID_ShellApplication, true);

            object shellApplication = Activator.CreateInstance(shellApplicationType);
            object windows = shellApplicationType.InvokeMember("Windows", System.Reflection.BindingFlags.InvokeMethod, null, shellApplication, new object[] { });

            Type windowsType = windows.GetType();
            object count = windowsType.InvokeMember("Count", System.Reflection.BindingFlags.GetProperty, null, windows, null);
            for (int i = 0; i < (int)count; i++)
            {
                object item = windowsType.InvokeMember("Item", System.Reflection.BindingFlags.InvokeMethod, null, windows, new object[] { i });
                if(item != null){
                    Type itemType = item.GetType();
                }
                // only refresh windows explorer
                string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
                if ((itemName == "Windows Explorer") || (itemName == "File Explorer")) {
                    itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
                }
            }
        }
    }
}
"@
    Add-Type -TypeDefinition $code -Language CSharp
    Invoke-Expression "[VSYSRefresh.Util]::RefreshExplorer()"

}

I am getting the following errors:

(26,43): error CS0165: Use of unassigned local variable 'itemType'
(string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);

Cannot add type. Compilation errors occurred.

Unable to find type [VSYSRefresh.Util].

I can't even get Console.WriteLine() to work. Do I need to reference certain assemblies to get this working?

I'm at a dead end and any help would be greatly appreciated.

zett42
  • 25,437
  • 3
  • 35
  • 72
fmotion1
  • 237
  • 4
  • 12
  • Can you post the errors as test please. See https://meta.stackoverflow.com/questions/285551/why-should-i-not-upload-images-of-code-data-errors-when-asking-a-question for more details... – mclayton Aug 09 '22 at 14:38
  • Is this topic what you are searching ? https://stackoverflow.com/questions/71661569/executing-c-sharp-code-in-powershell-results-in-an-error-verify-that-the-assem – ahmet gül Aug 09 '22 at 14:40
  • In general you should get the C# working in VS or VS Code first. – David Browne - Microsoft Aug 09 '22 at 14:42
  • By the way, using only PowerShell this code could be reduced to just a handful of lines: `$shellApplication = New-Object -com Shell.Application` and then use its methods directly, e. g. `$shellApplication.Windows().Count()` – zett42 Aug 09 '22 at 14:46
  • @zett42 How would you use that implementation? Can you provide more code? If there is a more efficient way to do this I would love to know how. – fmotion1 Aug 09 '22 at 14:48

2 Answers2

3

The error is in your for loop here:

                if(item != null){
                    Type itemType = item.GetType();
                }
                // only refresh windows explorer
                string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);

Since you're declaring Type itemType inside the if statement, the next line won't be able to run since it's out of context. Change this block to:

                if (item != null) {
                    Type itemType = item.GetType();
                    // only refresh windows explorer
                    string itemName = (string)itemType.InvokeMember("Name", System.Reflection.BindingFlags.GetProperty, null, item, null);
                    if ((itemName == "Windows Explorer") || (itemName == "File Explorer")) {
                        itemType.InvokeMember("Refresh", System.Reflection.BindingFlags.InvokeMethod, null, item, null);
                    }
                }
Bron Davies
  • 5,930
  • 3
  • 30
  • 41
0

Complementing the existing answer, that solves the problem with your current code, here is a rewrite of the code using PowerShell only. With the help of the New-Object command a COM object can be created in PowerShell by specifying its ProgID:

'Refreshing Explorer'

$shellApplication = New-Object -ComObject Shell.Application
$windows = $shellApplication.Windows()
$count = $windows.Count()

foreach( $i in 0..($count-1) ) {
    $item = $windows.Item( $i )
    if( $item.Name() -like '*Explorer*' ) {
        $item.Refresh()
    }    
}

Pretty straightforward. The only thing to note is that properties of COM objects are called like methods.

Also, on my system the Explorer windows are named just "Explorer", so I made the condition more generic.

zett42
  • 25,437
  • 3
  • 35
  • 72