├── img └── remoteDesktopWindow.png ├── src ├── .editorconfig ├── RdpProtocolHandler │ ├── test.reg │ ├── Properties │ │ ├── PublishProfiles │ │ │ └── FolderProfile.pubxml │ │ └── AssemblyInfo.cs │ ├── NLog.config │ ├── RdpProtocolHandler.csproj │ ├── ConsoleWrapper.cs │ ├── LoggerHelper.cs │ ├── RdpHandler.cs │ ├── Program.cs │ └── Installer.cs └── RdpProtocolHandler.sln ├── LICENSE ├── README.md ├── .github └── workflows │ └── dotnet.yml └── .gitignore /img/remoteDesktopWindow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/konradsikorski/RdpProtocolHandler/HEAD/img/remoteDesktopWindow.png -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # IDE0063: Use simple 'using' statement 4 | csharp_prefer_simple_using_statement = false 5 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/test.reg: -------------------------------------------------------------------------------- 1 | REGEDIT4 2 | 3 | [HKEY_CLASSES_ROOT\RDP-Protocol] 4 | @="rdp:Remote Desktop Protocol" 5 | "URL Protocol"="" 6 | 7 | [HKEY_CLASSES_ROOT\RDP-Protocol\DefaultIcon] 8 | @="\"C:\\Windows\\System32\\mstsc.exe\"" 9 | 10 | [HKEY_CLASSES_ROOT\RDP-Protocol\shell] 11 | 12 | [HKEY_CLASSES_ROOT\RDP-Protocol\shell\open] 13 | 14 | [HKEY_CLASSES_ROOT\RDP-Protocol\shell\open\command] 15 | @="\"C:\\Windows\\System32\\rdphandler.exe\" \"%1\"" -------------------------------------------------------------------------------- /src/RdpProtocolHandler/Properties/PublishProfiles/FolderProfile.pubxml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | Release 8 | Any CPU 9 | publish\win-x64\ 10 | FileSystem 11 | <_TargetId>Folder 12 | net7.0 13 | win-x64 14 | false 15 | false 16 | 17 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/NLog.config: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/RdpProtocolHandler.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net7.0 4 | WinExe 5 | KonradSikorski.Tools.RdpProtocolHandler 6 | false 7 | true 8 | true 9 | win-x64 10 | embedded 11 | 12 | 13 | 14 | 15 | true 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Konrad Sikorski 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.5.33326.253 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RdpProtocolHandler", "RdpProtocolHandler\RdpProtocolHandler.csproj", "{9BCAEE56-8E0E-4156-9FB8-A1203E2001F9}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{FC47C625-8A77-4C95-81BB-F869C794327F}" 9 | ProjectSection(SolutionItems) = preProject 10 | .editorconfig = .editorconfig 11 | README.md = README.md 12 | EndProjectSection 13 | EndProject 14 | Global 15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 16 | Debug|Any CPU = Debug|Any CPU 17 | Release|Any CPU = Release|Any CPU 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {9BCAEE56-8E0E-4156-9FB8-A1203E2001F9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {9BCAEE56-8E0E-4156-9FB8-A1203E2001F9}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {9BCAEE56-8E0E-4156-9FB8-A1203E2001F9}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {9BCAEE56-8E0E-4156-9FB8-A1203E2001F9}.Release|Any CPU.Build.0 = Release|Any CPU 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/ConsoleWrapper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.InteropServices; 3 | 4 | namespace KonradSikorski.Tools.RdpProtocolHandler 5 | { 6 | public static partial class ConsoleWrapper 7 | { 8 | public static bool Initialized { get; private set; } 9 | 10 | [LibraryImport("kernel32.dll", SetLastError = true)] 11 | [return: MarshalAs(UnmanagedType.Bool)] 12 | private static partial bool AllocConsole(); 13 | 14 | public static void Alloc() 15 | { 16 | if (Initialized) return; 17 | 18 | AllocConsole(); 19 | Initialized = true; 20 | } 21 | 22 | public static ConsoleColor ForegroundColor 23 | { 24 | get 25 | { 26 | Alloc(); 27 | return Console.ForegroundColor; 28 | } 29 | set 30 | { 31 | Alloc(); 32 | Console.ForegroundColor = value; 33 | } 34 | } 35 | 36 | public static void WriteLine(string format) 37 | { 38 | Alloc(); 39 | Console.WriteLine(format); 40 | } 41 | 42 | public static void WaitForClose() 43 | { 44 | if (!Initialized) return; 45 | 46 | Console.WriteLine("Press any key to close..."); 47 | Console.ReadKey(); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/LoggerHelper.cs: -------------------------------------------------------------------------------- 1 | using NLog.Config; 2 | using NLog.Targets; 3 | using NLog; 4 | using System; 5 | using System.Diagnostics; 6 | using System.IO; 7 | using System.Linq; 8 | 9 | namespace KonradSikorski.Tools.RdpProtocolHandler 10 | { 11 | internal static class LoggerHelper 12 | { 13 | internal static void ConfigureNLog() 14 | { 15 | if (LogManager.Configuration != null) return; 16 | 17 | var logConfiguration = new LoggingConfiguration(); 18 | var fileTarget = new FileTarget("file") 19 | { 20 | Layout = "${longdate} ${uppercase:${level}} ${message}", 21 | FileName = Path.Combine(Path.GetTempPath(), @"rdppotocolhandler-logs\${shortdate}.log") 22 | }; 23 | 24 | var rule = new LoggingRule("*", LogLevel.Debug, fileTarget); 25 | logConfiguration.LoggingRules.Add(rule); 26 | 27 | LogManager.Configuration = logConfiguration; 28 | } 29 | 30 | internal static void OpenLogFile() 31 | { 32 | var fileTarget = LogManager.Configuration.AllTargets.OfType().FirstOrDefault(); 33 | 34 | if (fileTarget == null) return; 35 | 36 | var logEventInfo = new LogEventInfo { TimeStamp = DateTime.Now }; 37 | var fileName = fileTarget.FileName.Render(logEventInfo); 38 | if (File.Exists(fileName)) 39 | Process.Start(fileName); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/RdpHandler.cs: -------------------------------------------------------------------------------- 1 | using NLog; 2 | using System; 3 | using System.Diagnostics; 4 | 5 | namespace KonradSikorski.Tools.RdpProtocolHandler 6 | { 7 | internal static class RdpHandler 8 | { 9 | private static readonly Logger Log = LogManager.GetCurrentClassLogger(); 10 | 11 | internal static void Run(string parameter) 12 | { 13 | Log.Debug("Start RDP: " + parameter); 14 | 15 | var rdpAppPath = GetPathToRemoteDesktopApp(); 16 | var rdpParametersChain = BuildParameters(parameter); 17 | 18 | Process.Start(rdpAppPath, rdpParametersChain); 19 | Log.Debug("End RDP"); 20 | } 21 | 22 | private static string GetPathToRemoteDesktopApp() 23 | { 24 | return $"{Environment.GetEnvironmentVariable("systemroot")}\\system32\\mstsc.exe"; 25 | } 26 | 27 | private static string BuildParameters(string parameter) 28 | { 29 | var uri = parameter.Substring("rdp://".Length).TrimEnd('/'); 30 | var rdpParameters = uri.Split(','); 31 | 32 | rdpParameters[0] = $"/v:{rdpParameters[0]}"; 33 | for (int i = 1; i < rdpParameters.Length; i++) 34 | { 35 | var rdpParam = rdpParameters[i]; 36 | if (!string.IsNullOrWhiteSpace(rdpParam)) rdpParameters[i] = "/" + rdpParam; 37 | } 38 | 39 | var rdpParametersChain = string.Join(" ", rdpParameters); 40 | Log.Debug("rdpParametersChain: " + rdpParametersChain); 41 | return rdpParametersChain; 42 | } 43 | 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("Rdp Protocol Handler")] 8 | [assembly: AssemblyDescription("Handle rdp:// uri in the system and start Remote Desktop Connection")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("Konrad Sikorski")] 11 | [assembly: AssemblyProduct("Rdp Protocol Handler")] 12 | [assembly: AssemblyCopyright("Copyright © Konrad Sikorski 2017")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("9bcaee56-8e0e-4156-9fb8-a1203e2001f9")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("2.1.0.0")] 35 | [assembly: AssemblyFileVersion("2.1.0.0")] 36 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics.CodeAnalysis; 3 | using System.Runtime.Versioning; 4 | using NLog; 5 | 6 | namespace KonradSikorski.Tools.RdpProtocolHandler 7 | { 8 | [SupportedOSPlatform("windows")] 9 | static class Program 10 | { 11 | private static readonly Logger Log = LogManager.GetCurrentClassLogger(); 12 | 13 | [RequiresAssemblyFiles("Calls KonradSikorski.Tools.RdpProtocolHandler.Installer.Install(Boolean)")] 14 | static void Main(string[] args) 15 | { 16 | AppDomain.CurrentDomain.UnhandledException += UnhandledException; 17 | LoggerHelper.ConfigureNLog(); 18 | Log.Info($"{string.Join(" | ", args)}"); 19 | 20 | if (args.Length == 0) Installer.Install(); 21 | else 22 | { 23 | var parameter = args[0]; 24 | switch (parameter.ToLower()) 25 | { 26 | case "/uninstall": Installer.Uninstall(); break; 27 | case "/install": Installer.Install(); break; 28 | case "/log": LoggerHelper.OpenLogFile(); break; 29 | case "/help": 30 | case "/?": 31 | Help(); 32 | break; 33 | default: 34 | RdpHandler.Run(parameter); 35 | break; 36 | } 37 | } 38 | 39 | ConsoleWrapper.WaitForClose(); 40 | } 41 | 42 | private static void UnhandledException(object sender, UnhandledExceptionEventArgs e) 43 | { 44 | ConsoleWrapper.Alloc(); 45 | Log.Error(e.ExceptionObject); 46 | ConsoleWrapper.WriteLine("Error occurred. Please check the log file for details"); 47 | Environment.Exit(1); 48 | } 49 | 50 | private static void Help() 51 | { 52 | ConsoleWrapper.Alloc(); 53 | ConsoleWrapper.WriteLine("For help go to: https://github.com/konradsikorski/RdpProtocolHandler"); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # RDP Protocol Handler 2 | This simple app allows you to use `rdp://` uri to start remote desktop session. So you can use uri like this: 3 | 4 | `rdp://remote.server.address` 5 | 6 | and you will see Remote Desktop Connection window if you do not have saved credentials, otherwise you will be automatically connected. 7 | 8 | ![Remote Desktop Connection window](img/remoteDesktopWindow.png "Logo Title Text 1") 9 | 10 | ### [Release Notes and Download](https://github.com/konradsikorski/RdpProtocolHandler/releases) 11 | 12 | ## How to install 13 | Place the `.exe` file in desired location on your PC, then run it **as administrator** with `/install` parameter like this: 14 | 15 | `rdpProtocoleHandler.exe /install` 16 | 17 | After installation do not move the `.exe` file to other location. When you change the file location the protocol handler will not work until you run it again with `/install` parameter. 18 | 19 | ## How to use 20 | Just open uri which start with `rdp://` using browser or any other way. 21 | 22 | ### Uri format 23 | The uri format used by application is as following: 24 | 25 | `rdp://,,,...` 26 | 27 | Each parameter in the uri is separated by comma `,`. First parameter is always the remote server address. Other parameters are exactly the same which mstsc.exe use (except the rdp file path). To see all parameters for mstsc.exe run following command: 28 | 29 | `mstsc /?` 30 | 31 | #### Examples 32 | Run Remote Desktop with specific window width and high 33 | 34 | `rdp://remote.server.address,/w:600,/h:400` 35 | 36 | Run Remote Desktop using all monitors 37 | 38 | `rdp://remote.server.address,/multimon` 39 | 40 | ## RDP Protocol Handler parameters 41 | `rdpProtocoleHandler.exe [/install] [/uninstall] [/log] [/help] [/?]` 42 | 43 | Parameter | Description 44 | -------------- | ------------- 45 | /install | Run the installation procedure and register the rdp uri handler. **Require administration privileges** 46 | /uninstall | Run the uninstallation procedure and unregister the rdp uri handler. **Require administration privileges** 47 | /log | Open the log file 48 | /help | Open the help 49 | /? | Open the help 50 | 51 | #### Examples 52 | Install rdp uri handler 53 | 54 | `rdpProtocoleHandler.exe /install` 55 | 56 | Uninstall rdp uri handler 57 | 58 | `rdpProtocoleHandler.exe /uninstall` 59 | 60 | ## Log file 61 | The app logs its usages to file using [NLog](http://nlog-project.org). By default, log file is created in `C:\Users\\AppData\Local\Temp\rdppotocolhandler-logs`. You can change the logging behavior by creating the NLog.config file (for details go to NLog documentation). 62 | -------------------------------------------------------------------------------- /.github/workflows/dotnet.yml: -------------------------------------------------------------------------------- 1 | name: .NET Core 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | jobs: 10 | 11 | build: 12 | 13 | strategy: 14 | matrix: 15 | configuration: [Release] # [Debug, Release] 16 | 17 | runs-on: windows-latest # For a list of available runner types, refer to 18 | # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on 19 | 20 | env: 21 | SOLUTION_PATH: src/RdpProtocolHandler.sln 22 | 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | with: 27 | fetch-depth: 0 28 | 29 | # Install the .NET Core workload 30 | - name: Install .NET Core 31 | uses: actions/setup-dotnet@v3 32 | with: 33 | dotnet-version: 7.0.x 34 | 35 | - name: Restore dependencies 36 | run: dotnet restore ${{ env.SOLUTION_PATH }} 37 | 38 | - name: Build application 39 | run: dotnet build ${{ env.SOLUTION_PATH }} --no-restore --configuration ${{ env.Configuration }} 40 | env: 41 | Configuration: ${{ matrix.configuration }} 42 | 43 | - name: Check code formatting 44 | run: dotnet format ${{ env.SOLUTION_PATH }} --severity warn --include-generated --verify-no-changes 45 | 46 | - name: Set up JDK 11 47 | uses: actions/setup-java@v3 48 | with: 49 | java-version: 11 50 | distribution: 'zulu' # Alternative distribution options are available. 51 | - uses: actions/checkout@v3 52 | with: 53 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 54 | 55 | - name: Cache SonarCloud packages 56 | uses: actions/cache@v3 57 | with: 58 | path: ~\sonar\cache 59 | key: ${{ runner.os }}-sonar 60 | restore-keys: ${{ runner.os }}-sonar 61 | 62 | - name: Cache SonarCloud scanner 63 | id: cache-sonar-scanner 64 | uses: actions/cache@v3 65 | with: 66 | path: .\.sonar\scanner 67 | key: ${{ runner.os }}-sonar-scanner 68 | restore-keys: ${{ runner.os }}-sonar-scanner 69 | 70 | - name: Install SonarCloud scanner 71 | if: steps.cache-sonar-scanner.outputs.cache-hit != 'true' 72 | shell: powershell 73 | run: | 74 | New-Item -Path .\.sonar\scanner -ItemType Directory 75 | dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner 76 | 77 | - name: Build and analyze 78 | env: 79 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any 80 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 81 | shell: powershell 82 | run: | 83 | .\.sonar\scanner\dotnet-sonarscanner begin /k:"konradsikorski_RdpProtocolHandler" /o:"konrad" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io" 84 | dotnet build ${{ env.SOLUTION_PATH }} 85 | .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" 86 | -------------------------------------------------------------------------------- /src/RdpProtocolHandler/Installer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Win32; 2 | using NLog; 3 | using System; 4 | using System.Diagnostics; 5 | using System.Diagnostics.CodeAnalysis; 6 | using System.IO; 7 | using System.Reflection; 8 | using System.Runtime.Versioning; 9 | using System.Security.Principal; 10 | 11 | namespace KonradSikorski.Tools.RdpProtocolHandler 12 | { 13 | [SupportedOSPlatform("windows")] 14 | internal static class Installer 15 | { 16 | private static readonly Logger Log = LogManager.GetCurrentClassLogger(); 17 | private const string REGISTRY_KEY_NAME = "RDP"; 18 | 19 | internal static void Uninstall() 20 | { 21 | ConsoleWrapper.Alloc(); 22 | if (!RequireAdministratorPrivileges()) return; 23 | 24 | Registry.ClassesRoot.DeleteSubKeyTree(REGISTRY_KEY_NAME, false); 25 | ConsoleWrapper.WriteLine("RDP Protocol Handler uninstalled."); 26 | Log.Info("RDP Protocol Handler uninstalled."); 27 | } 28 | 29 | [RequiresAssemblyFiles("Calls System.Reflection.Assembly.Location")] 30 | internal static void Install() 31 | { 32 | ConsoleWrapper.Alloc(); 33 | 34 | if (!RequireAdministratorPrivileges()) return; 35 | 36 | Uninstall(); 37 | 38 | //-- get assembly info 39 | var handlerLocation = GetAppPath(); 40 | 41 | //-- create registry structure 42 | var rootKey = Registry.ClassesRoot.CreateSubKey(REGISTRY_KEY_NAME); 43 | var defaultIconKey = rootKey?.CreateSubKey("DefaultIcon"); 44 | var commandKey = rootKey?.CreateSubKey("shell")?.CreateSubKey("open")?.CreateSubKey("command"); 45 | 46 | rootKey?.SetValue("", "rdp:Remote Desktop Protocol"); 47 | rootKey?.SetValue("URL Protocol", ""); 48 | defaultIconKey?.SetValue("", @"C:\Windows\System32\mstsc.exe"); 49 | commandKey?.SetValue("", $@"""{handlerLocation}"" ""%1"""); 50 | 51 | //-- 52 | Log.Info("RDP Protocol Handler installed"); 53 | ConsoleWrapper.WriteLine("RDP Protocol Handler installed"); 54 | ConsoleWrapper.WriteLine($"WARNING: Do not move this file '{handlerLocation}' to other location, otherwise handler will not work. If you change the location run installation process again."); 55 | } 56 | 57 | private static string GetAppPath() 58 | { 59 | // Get filename 60 | string fileName = Process.GetCurrentProcess().MainModule.FileName; 61 | 62 | // If published as single file, the fileName will be the temp path to the actual binary 63 | // You can use Path.GetFileName to get the executable name and combine it with AppContext.BaseDirectory 64 | if (fileName.StartsWith(Path.GetTempPath())) 65 | { 66 | var directory = AppContext.BaseDirectory; 67 | fileName = Path.Combine(directory, Path.GetFileName(fileName)); 68 | } 69 | 70 | return fileName; 71 | } 72 | 73 | private static bool RequireAdministratorPrivileges() 74 | { 75 | var isAdmin = IsUserAdministrator(); 76 | 77 | if (!isAdmin) 78 | { 79 | var oldColor = ConsoleWrapper.ForegroundColor; 80 | ConsoleWrapper.ForegroundColor = ConsoleColor.Red; 81 | ConsoleWrapper.WriteLine("You must be system administrator"); 82 | ConsoleWrapper.ForegroundColor = oldColor; 83 | Log.Error("You must be system administrator"); 84 | } 85 | 86 | return isAdmin; 87 | } 88 | 89 | private static bool IsUserAdministrator() 90 | { 91 | using (var user = WindowsIdentity.GetCurrent()) 92 | { 93 | try 94 | { 95 | //get the currently logged in user 96 | var principal = new WindowsPrincipal(user); 97 | return principal.IsInRole(WindowsBuiltInRole.Administrator); 98 | } 99 | catch (UnauthorizedAccessException) 100 | { 101 | return false; 102 | } 103 | } 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | ## Ignore Visual Studio temporary files, build results, and 6 | ## files generated by popular Visual Studio add-ons. 7 | ## 8 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 9 | 10 | # User-specific files 11 | *.rsuser 12 | *.suo 13 | *.user 14 | *.userosscache 15 | *.sln.docstates 16 | 17 | # User-specific files (MonoDevelop/Xamarin Studio) 18 | *.userprefs 19 | 20 | # Mono auto generated files 21 | mono_crash.* 22 | 23 | # Build results 24 | [Dd]ebug/ 25 | [Dd]ebugPublic/ 26 | [Rr]elease/ 27 | [Rr]eleases/ 28 | x64/ 29 | x86/ 30 | [Ww][Ii][Nn]32/ 31 | [Aa][Rr][Mm]/ 32 | [Aa][Rr][Mm]64/ 33 | bld/ 34 | [Bb]in/ 35 | [Oo]bj/ 36 | [Ll]og/ 37 | [Ll]ogs/ 38 | [Pp]ublish 39 | 40 | # Visual Studio 2015/2017 cache/options directory 41 | .vs/ 42 | # Uncomment if you have tasks that create the project's static files in wwwroot 43 | #wwwroot/ 44 | 45 | # Visual Studio 2017 auto generated files 46 | Generated\ Files/ 47 | 48 | # MSTest test Results 49 | [Tt]est[Rr]esult*/ 50 | [Bb]uild[Ll]og.* 51 | 52 | # NUnit 53 | *.VisualState.xml 54 | TestResult.xml 55 | nunit-*.xml 56 | 57 | # Build Results of an ATL Project 58 | [Dd]ebugPS/ 59 | [Rr]eleasePS/ 60 | dlldata.c 61 | 62 | # Benchmark Results 63 | BenchmarkDotNet.Artifacts/ 64 | 65 | # .NET Core 66 | project.lock.json 67 | project.fragment.lock.json 68 | artifacts/ 69 | 70 | # ASP.NET Scaffolding 71 | ScaffoldingReadMe.txt 72 | 73 | # StyleCop 74 | StyleCopReport.xml 75 | 76 | # Files built by Visual Studio 77 | *_i.c 78 | *_p.c 79 | *_h.h 80 | *.ilk 81 | *.meta 82 | *.obj 83 | *.iobj 84 | *.pch 85 | *.pdb 86 | *.ipdb 87 | *.pgc 88 | *.pgd 89 | *.rsp 90 | *.sbr 91 | *.tlb 92 | *.tli 93 | *.tlh 94 | *.tmp 95 | *.tmp_proj 96 | *_wpftmp.csproj 97 | *.log 98 | *.tlog 99 | *.vspscc 100 | *.vssscc 101 | .builds 102 | *.pidb 103 | *.svclog 104 | *.scc 105 | 106 | # Chutzpah Test files 107 | _Chutzpah* 108 | 109 | # Visual C++ cache files 110 | ipch/ 111 | *.aps 112 | *.ncb 113 | *.opendb 114 | *.opensdf 115 | *.sdf 116 | *.cachefile 117 | *.VC.db 118 | *.VC.VC.opendb 119 | 120 | # Visual Studio profiler 121 | *.psess 122 | *.vsp 123 | *.vspx 124 | *.sap 125 | 126 | # Visual Studio Trace Files 127 | *.e2e 128 | 129 | # TFS 2012 Local Workspace 130 | $tf/ 131 | 132 | # Guidance Automation Toolkit 133 | *.gpState 134 | 135 | # ReSharper is a .NET coding add-in 136 | _ReSharper*/ 137 | *.[Rr]e[Ss]harper 138 | *.DotSettings.user 139 | 140 | # TeamCity is a build add-in 141 | _TeamCity* 142 | 143 | # DotCover is a Code Coverage Tool 144 | *.dotCover 145 | 146 | # AxoCover is a Code Coverage Tool 147 | .axoCover/* 148 | !.axoCover/settings.json 149 | 150 | # Coverlet is a free, cross platform Code Coverage Tool 151 | coverage*.json 152 | coverage*.xml 153 | coverage*.info 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # NuGet Symbol Packages 203 | *.snupkg 204 | # The packages folder can be ignored because of Package Restore 205 | **/[Pp]ackages/* 206 | # except build/, which is used as an MSBuild target. 207 | !**/[Pp]ackages/build/ 208 | # Uncomment if necessary however generally it will be regenerated when needed 209 | #!**/[Pp]ackages/repositories.config 210 | # NuGet v3's project.json files produces more ignorable files 211 | *.nuget.props 212 | *.nuget.targets 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 303 | *.vbp 304 | 305 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 306 | *.dsw 307 | *.dsp 308 | 309 | # Visual Studio 6 technical files 310 | *.ncb 311 | *.aps 312 | 313 | # Visual Studio LightSwitch build output 314 | **/*.HTMLClient/GeneratedArtifacts 315 | **/*.DesktopClient/GeneratedArtifacts 316 | **/*.DesktopClient/ModelManifest.xml 317 | **/*.Server/GeneratedArtifacts 318 | **/*.Server/ModelManifest.xml 319 | _Pvt_Extensions 320 | 321 | # Paket dependency manager 322 | .paket/paket.exe 323 | paket-files/ 324 | 325 | # FAKE - F# Make 326 | .fake/ 327 | 328 | # CodeRush personal settings 329 | .cr/personal 330 | 331 | # Python Tools for Visual Studio (PTVS) 332 | __pycache__/ 333 | *.pyc 334 | 335 | # Cake - Uncomment if you are using it 336 | # tools/** 337 | # !tools/packages.config 338 | 339 | # Tabs Studio 340 | *.tss 341 | 342 | # Telerik's JustMock configuration file 343 | *.jmconfig 344 | 345 | # BizTalk build output 346 | *.btp.cs 347 | *.btm.cs 348 | *.odx.cs 349 | *.xsd.cs 350 | 351 | # OpenCover UI analysis results 352 | OpenCover/ 353 | 354 | # Azure Stream Analytics local run output 355 | ASALocalRun/ 356 | 357 | # MSBuild Binary and Structured Log 358 | *.binlog 359 | 360 | # NVidia Nsight GPU debugger configuration file 361 | *.nvuser 362 | 363 | # MFractors (Xamarin productivity tool) working folder 364 | .mfractor/ 365 | 366 | # Local History for Visual Studio 367 | .localhistory/ 368 | 369 | # Visual Studio History (VSHistory) files 370 | .vshistory/ 371 | 372 | # BeatPulse healthcheck temp database 373 | healthchecksdb 374 | 375 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 376 | MigrationBackup/ 377 | 378 | # Ionide (cross platform F# VS Code tools) working folder 379 | .ionide/ 380 | 381 | # Fody - auto-generated XML schema 382 | FodyWeavers.xsd 383 | 384 | # VS Code files for those working on multiple tools 385 | .vscode/* 386 | !.vscode/settings.json 387 | !.vscode/tasks.json 388 | !.vscode/launch.json 389 | !.vscode/extensions.json 390 | *.code-workspace 391 | 392 | # Local History for Visual Studio Code 393 | .history/ 394 | 395 | # Windows Installer files from build outputs 396 | *.cab 397 | *.msi 398 | *.msix 399 | *.msm 400 | *.msp 401 | 402 | # JetBrains Rider 403 | *.sln.iml 404 | --------------------------------------------------------------------------------