diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/ContextMenuLoader.cs b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/ContextMenuLoader.cs
index a1465db07b..cf1a3d63b7 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/ContextMenuLoader.cs
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/ContextMenuLoader.cs
@@ -6,8 +6,9 @@ using System.Windows;
using Wox.Infrastructure.Logger;
using Wox.Plugin;
using Microsoft.Plugin.Indexer.SearchHelper;
-using System.Windows.Input;
-using System.Reflection;
+using System.Windows.Input;
+using System.Reflection;
+using System.Threading.Tasks;
using Wox.Infrastructure;
namespace Microsoft.Plugin.Indexer
@@ -22,6 +23,9 @@ namespace Microsoft.Plugin.Indexer
File
}
+ // Extensions for adding run as admin context menu item for applications
+ private readonly string[] appExtensions = { ".exe", ".bat", ".appref-ms", ".lnk" };
+
public ContextMenuLoader(PluginInitContext context)
{
_context = context;
@@ -39,6 +43,12 @@ namespace Microsoft.Plugin.Indexer
contextMenus.Add(CreateOpenContainingFolderResult(record));
}
+ // Test to check if File can be Run as admin, if yes, we add a 'run as admin' context menu item
+ if(CanFileBeRunAsAdmin(record.Path))
+ {
+ contextMenus.Add(CreateRunAsAdminContextMenu(record));
+ }
+
contextMenus.Add(new ContextMenuResult
{
PluginName = Assembly.GetExecutingAssembly().GetName().Name,
@@ -98,8 +108,51 @@ namespace Microsoft.Plugin.Indexer
}
return contextMenus;
- }
-
+ }
+
+ // Function to add the context menu item to run as admin
+ private ContextMenuResult CreateRunAsAdminContextMenu(SearchResult record)
+ {
+ return new ContextMenuResult
+ {
+ PluginName = Assembly.GetExecutingAssembly().GetName().Name,
+ Title = _context.API.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"),
+ Glyph = "\xE7EF",
+ FontFamily = "Segoe MDL2 Assets",
+ AcceleratorKey = Key.Enter,
+ AcceleratorModifiers = (ModifierKeys.Control | ModifierKeys.Shift),
+ Action = _ =>
+ {
+ try
+ {
+ Task.Run(() => Helper.RunAsAdmin(record.Path));
+ return true;
+ }
+ catch(Exception e)
+ {
+ Log.Exception($"|Microsoft.Plugin.Indexer.ContextMenu| Failed to run {record.Path} as admin, {e.Message}", e);
+ return false;
+ }
+
+ }
+ };
+ }
+
+ // Function to test if the file can be run as admin
+ private bool CanFileBeRunAsAdmin(string path)
+ {
+ string fileExtension = Path.GetExtension(path);
+ foreach(string extension in appExtensions)
+ {
+ if(extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+
private ContextMenuResult CreateOpenContainingFolderResult(SearchResult record)
{
return new ContextMenuResult
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/de.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/de.xaml
index f00dd4e5b2..973a26d871 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/de.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/de.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/en.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/en.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/en.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/en.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/ja.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/ja.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/ja.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/ja.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/pl.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/pl.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/pl.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/pl.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/tr.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/tr.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/tr.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/tr.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-cn.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-cn.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-cn.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-cn.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-tw.xaml b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-tw.xaml
index 9aa0049b2e..6865b58564 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-tw.xaml
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Languages/zh-tw.xaml
@@ -4,6 +4,7 @@
Copy path (Ctrl+C)
Open containing folder (Ctrl+Shift+E)
+ Run As Administrator (Ctrl+Shift+Enter)
Open path in console (Ctrl+Shift+C)
Name
Path
diff --git a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Microsoft.Plugin.Indexer.csproj b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Microsoft.Plugin.Indexer.csproj
index c41c6568bb..d2709f8ab0 100644
--- a/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Microsoft.Plugin.Indexer.csproj
+++ b/src/modules/launcher/Plugins/Microsoft.Plugin.Indexer/Microsoft.Plugin.Indexer.csproj
@@ -57,12 +57,6 @@
PreserveNewest
-
-
-
- <_Parameter1>Wox.Test
-
-
@@ -101,4 +95,11 @@
PreserveNewest
+
+
+
+ <_Parameter1>Wox.Test
+
+
+
diff --git a/src/modules/launcher/Wox.Infrastructure/Helper.cs b/src/modules/launcher/Wox.Infrastructure/Helper.cs
index 37554e42ef..16feaeb5b8 100644
--- a/src/modules/launcher/Wox.Infrastructure/Helper.cs
+++ b/src/modules/launcher/Wox.Infrastructure/Helper.cs
@@ -3,6 +3,7 @@ using System.Diagnostics;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
+using Wox.Infrastructure.Logger;
namespace Wox.Infrastructure
{
@@ -76,6 +77,26 @@ namespace Wox.Infrastructure
return formatted;
}
+ // Function to run as admin for context menu items
+ public static void RunAsAdmin(string path)
+ {
+ var info = new ProcessStartInfo
+ {
+ FileName = path,
+ WorkingDirectory = Path.GetDirectoryName(path),
+ Verb = "runas",
+ UseShellExecute = true
+ };
+
+ try
+ {
+ Process.Start(info);
+ }
+ catch(System.Exception ex)
+ {
+ Log.Exception($"Wox.Infrastructure.Helper| Unable to Run {path} as admin : {ex.Message}", ex);
+ }
+ }
public static Process OpenInConsole(string path)
{
var processStartInfo = new ProcessStartInfo
diff --git a/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs b/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs
index b90e46144a..39ca0c6d42 100644
--- a/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs
+++ b/src/modules/launcher/Wox.Test/Plugins/WindowsIndexerTest.cs
@@ -1,14 +1,13 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
-using System.Data.OleDb;
using Microsoft.Search.Interop;
using Microsoft.Plugin.Indexer.SearchHelper;
using Microsoft.Plugin.Indexer.Interface;
-using Moq;
-using System.Linq;
using Microsoft.Plugin.Indexer;
+using Moq;
using Wox.Plugin;
+using System.Linq;
namespace Wox.Test.Plugins
{
@@ -217,45 +216,86 @@ namespace Wox.Test.Plugins
Assert.IsTrue(windowsSearchAPIResults.Any(x => x.Title == "file2.txt"));
}
- [Test]
- public void ContextMenuLoader_ReturnContextMenuForFolderWithOpenInConsole_WhenLoadContextMenusIsCalled()
+ [TestCase("item.exe")]
+ [TestCase("item.bat")]
+ [TestCase("item.appref-ms")]
+ [TestCase("item.lnk")]
+ public void LoadContextMenus_MustLoadAllItems_WhenFileIsAnApp(string path)
{
- // Arrange
- var mock = new Mock();
- mock.Setup(api => api.GetTranslation(It.IsAny())).Returns(It.IsAny());
- var pluginInitContext = new PluginInitContext() { API = mock.Object };
- var contextMenuLoader = new ContextMenuLoader(pluginInitContext);
- var searchResult = new SearchResult() { Path = "C:/DummyFolder", Title = "DummyFolder" };
- var result = new Result() { ContextData = searchResult };
+ // Arrange
+ var mockapi = new Mock();
+ var pluginInitContext = new PluginInitContext() { API = mockapi.Object };
+
+ ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);
// Act
- List contextMenuResults = contextMenuLoader.LoadContextMenus(result);
+ Result result = new Result
+ {
+ ContextData = new SearchResult { Path = path }
+ };
+
+ List contextMenuItems = _contextMenuLoader.LoadContextMenus(result);
// Assert
- Assert.AreEqual(contextMenuResults.Count, 2);
- mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
- mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
+ Assert.AreEqual(contextMenuItems.Count, 4);
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
}
- [Test]
- public void ContextMenuLoader_ReturnContextMenuForFileWithOpenInConsole_WhenLoadContextMenusIsCalled()
+ [TestCase("item.pdf")]
+ [TestCase("item.xls")]
+ [TestCase("item.ppt")]
+ [TestCase("C:/DummyFile.cs")]
+ public void LoadContextMenus_MustNotLoadRunAsAdmin_WhenFileIsAnNotApp(string path)
{
- // Arrange
- var mock = new Mock();
- mock.Setup(api => api.GetTranslation(It.IsAny())).Returns(It.IsAny());
- var pluginInitContext = new PluginInitContext() { API = mock.Object };
- var contextMenuLoader = new ContextMenuLoader(pluginInitContext);
- var searchResult = new SearchResult() { Path = "C:/DummyFile.cs", Title = "DummyFile.cs" };
- var result = new Result() { ContextData = searchResult };
+ // Arrange
+ var mockapi = new Mock();
+ var pluginInitContext = new PluginInitContext() { API = mockapi.Object };
+
+ ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);
// Act
- List contextMenuResults = contextMenuLoader.LoadContextMenus(result);
+ Result result = new Result
+ {
+ ContextData = new SearchResult { Path = path }
+ };
+
+ List contextMenuItems = _contextMenuLoader.LoadContextMenus(result);
// Assert
- Assert.AreEqual(contextMenuResults.Count, 3);
- mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
- mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
- mock.Verify(x => x.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
+ Assert.AreEqual(contextMenuItems.Count, 3);
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Never());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
+ }
+
+ [TestCase("C:/DummyFolder")]
+ [TestCase("TestFolder")]
+ public void LoadContextMenus_MustNotLoadRunAsAdminAndOpenContainingFolder_ForFolder(string path)
+ {
+ // Arrange
+ var mockapi = new Mock();
+ var pluginInitContext = new PluginInitContext() { API = mockapi.Object };
+
+ ContextMenuLoader _contextMenuLoader = new ContextMenuLoader(pluginInitContext);
+
+ // Act
+ Result result = new Result
+ {
+ ContextData = new SearchResult { Path = path }
+ };
+
+ List contextMenuItems = _contextMenuLoader.LoadContextMenus(result);
+
+ // Assert
+ Assert.AreEqual(contextMenuItems.Count, 2);
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_copy_path"), Times.Once());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_run_as_administrator"), Times.Never());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_containing_folder"), Times.Never());
+ mockapi.Verify(m => m.GetTranslation("Microsoft_plugin_indexer_open_in_console"), Times.Once());
}
}
}