diff --git a/Agent.Installer.Win/Agent.Installer.Win.csproj b/Agent.Installer.Win/Agent.Installer.Win.csproj
index e08b3dc1..a3df7ba2 100644
--- a/Agent.Installer.Win/Agent.Installer.Win.csproj
+++ b/Agent.Installer.Win/Agent.Installer.Win.csproj
@@ -50,10 +50,12 @@
+
C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Runtime.Serialization.dll
+
@@ -72,10 +74,18 @@
MSBuild:Compile
Designer
-
+
+ Models\ConnectionInfo.cs
+
+
+ Models\InstallerSettings.cs
+
+
+
+
diff --git a/Agent.Installer.Win/App.xaml b/Agent.Installer.Win/App.xaml
index 459d3733..aa4b0db2 100644
--- a/Agent.Installer.Win/App.xaml
+++ b/Agent.Installer.Win/App.xaml
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Remotely.Agent.Installer.Win"
- StartupUri="MainWindow.xaml" Startup="App_Startup">
+ StartupUri="MainWindow.xaml">
diff --git a/Agent.Installer.Win/App.xaml.cs b/Agent.Installer.Win/App.xaml.cs
index 482fc9ce..370b45ca 100644
--- a/Agent.Installer.Win/App.xaml.cs
+++ b/Agent.Installer.Win/App.xaml.cs
@@ -17,24 +17,6 @@ namespace Remotely.Agent.Installer.Win
///
public partial class App : Application
{
- public void App_Startup(object sender, StartupEventArgs e)
- {
- if (e.Args.Contains("-uninstall"))
- {
- try
- {
- Logger.Write("Uninstall command received. Preparing temp directory.");
- var targetPath = Path.Combine(Path.GetTempPath(), "Remotely_Installer.exe");
- File.Copy(Assembly.GetExecutingAssembly().Location, targetPath, true);
- Logger.Write("Launching uninstaller.");
- Process.Start(targetPath, "-rununinstall");
- Environment.Exit(0);
- }
- catch (Exception ex)
- {
- Logger.Write(ex);
- }
- }
- }
+
}
}
diff --git a/Agent.Installer.Win/MainWindow.xaml b/Agent.Installer.Win/MainWindow.xaml
index 08c2036f..c5e674c0 100644
--- a/Agent.Installer.Win/MainWindow.xaml
+++ b/Agent.Installer.Win/MainWindow.xaml
@@ -7,9 +7,11 @@
xmlns:local="clr-namespace:Remotely.Agent.Installer.Win"
mc:Ignorable="d"
WindowStyle="None"
- ResizeMode="NoResize"
+ ResizeMode="CanResizeWithGrip"
+ AllowsTransparency="True"
MouseLeftButtonDown="Window_MouseLeftButtonDown"
Loaded="Window_Loaded"
+ WindowStartupLocation="CenterScreen"
Title="Remotely Installer" Height="325" Width="500" Icon="Assets/favicon.ico">
@@ -36,17 +38,25 @@
-
- Provider:
-
-
-
- Server URL:
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -70,6 +80,7 @@
HorizontalAlignment="Right"
Style="{StaticResource NormalButton}"
Margin="5,0,0,0"
+ IsEnabled="{Binding IsReadyState}"
Visibility="{Binding IsServiceMissing, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding InstallCommand}">
Install
@@ -78,6 +89,7 @@
HorizontalAlignment="Right"
Style="{StaticResource NormalButton}"
Margin="5,0,0,0"
+ IsEnabled="{Binding IsReadyState}"
Visibility="{Binding IsServiceInstalled, Converter={StaticResource BooleanToVisibilityConverter}}"
Command="{Binding UninstallCommand}">
Uninstall
diff --git a/Agent.Installer.Win/MainWindow.xaml.cs b/Agent.Installer.Win/MainWindow.xaml.cs
index ca5ea623..94e808ba 100644
--- a/Agent.Installer.Win/MainWindow.xaml.cs
+++ b/Agent.Installer.Win/MainWindow.xaml.cs
@@ -1,4 +1,5 @@
-using Remotely.Agent.Installer.Win.ViewModels;
+using Remotely.Agent.Installer.Win.Services;
+using Remotely.Agent.Installer.Win.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
@@ -23,6 +24,12 @@ namespace Remotely.Agent.Installer.Win
{
public MainWindow()
{
+ if (CommandLineParser.CommandLineArgs.ContainsKey("quiet"))
+ {
+ Hide();
+ ShowInTaskbar = false;
+ _ = new MainWindowViewModel().Init();
+ }
InitializeComponent();
}
@@ -31,9 +38,9 @@ namespace Remotely.Agent.Installer.Win
DragMove();
}
- private void Window_Loaded(object sender, RoutedEventArgs e)
+ private async void Window_Loaded(object sender, RoutedEventArgs e)
{
- (DataContext as MainWindowViewModel).Init();
+ await (DataContext as MainWindowViewModel).Init();
}
private void CloseButton_Click(object sender, RoutedEventArgs e)
diff --git a/Agent.Installer.Win/Models/InstallerSettings.cs b/Agent.Installer.Win/Models/InstallerSettings.cs
deleted file mode 100644
index 9d37316f..00000000
--- a/Agent.Installer.Win/Models/InstallerSettings.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.Serialization;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace Remotely.Agent.Installer.Win
-{
- [DataContract]
- public class InstallerSettings
- {
- [DataMember]
- public string OrganizationID { get; set; }
-
- [DataMember]
- public string OrganizationName { get; set; }
-
- [DataMember]
- public string ServerUrl { get; set; }
- }
-}
diff --git a/Agent.Installer.Win/Services/CommandLineParser.cs b/Agent.Installer.Win/Services/CommandLineParser.cs
new file mode 100644
index 00000000..454776f6
--- /dev/null
+++ b/Agent.Installer.Win/Services/CommandLineParser.cs
@@ -0,0 +1,67 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Remotely.Agent.Installer.Win.Services
+{
+ public class CommandLineParser
+ {
+ private static Dictionary commandLineArgs;
+ public static Dictionary CommandLineArgs
+ {
+ get
+ {
+ if (commandLineArgs is null)
+ {
+ commandLineArgs = new Dictionary();
+ var args = Environment.GetCommandLineArgs();
+ for (var i = 1; i < args.Length; i += 2)
+ {
+ try
+ {
+ var key = args?[i];
+ if (key != null)
+ {
+ if (!key.Contains("-"))
+ {
+ Logger.Write("Command line arguments are invalid.");
+ MessageBoxWrapper.Show("Command line arguments are invalid.", "Invalid Arguments", MessageBoxButton.OK, MessageBoxImage.Error);
+ i -= 1;
+ continue;
+ }
+ key = key.Trim().Replace("-", "").ToLower();
+ if (i + 1 == args.Length)
+ {
+ commandLineArgs.Add(key, "true");
+ continue;
+ }
+ var value = args?[i + 1];
+ if (value != null)
+ {
+ if (value.StartsWith("-"))
+ {
+ commandLineArgs.Add(key, "true");
+ i -= 1;
+ }
+ else
+ {
+ commandLineArgs.Add(key, args[i + 1].Trim());
+ }
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+
+ }
+ }
+ return commandLineArgs;
+ }
+ }
+ }
+}
diff --git a/Agent.Installer.Win/Services/InstallerService.cs b/Agent.Installer.Win/Services/InstallerService.cs
index 283fb434..acee5d2b 100644
--- a/Agent.Installer.Win/Services/InstallerService.cs
+++ b/Agent.Installer.Win/Services/InstallerService.cs
@@ -1,38 +1,74 @@
-using System;
+using Microsoft.Win32;
+using Remotely.Shared.Models;
+using System;
using System.Collections.Generic;
using System.Configuration.Install;
using System.Diagnostics;
using System.IO;
+using System.IO.Compression;
using System.Linq;
+using System.Net;
+using System.Reflection;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
+using System.Web.Script.Serialization;
using System.Windows;
namespace Remotely.Agent.Installer.Win.Services
{
public class InstallerService
{
- public bool Install()
+ public event EventHandler ProgressMessageChanged;
+ public event EventHandler ProgressValueChanged;
+
+ private string InstallPath => Path.Combine(Path.GetPathRoot(Environment.SystemDirectory), "Program Files", "Remotely");
+ private string Platform => Environment.Is64BitOperatingSystem ? "x64" : "x86";
+ private JavaScriptSerializer Serializer { get; } = new JavaScriptSerializer();
+ public async Task Install(string serverUrl,
+ string organizationId,
+ string deviceGroup,
+ string deviceAlias)
{
try
{
+ Logger.Write("Install started.");
if (!CheckIsAdministrator())
{
return false;
}
+ await InstallDesktpRuntimeIfNeeded();
+
+ StopService();
+
+ BackupOrCreateDirectory();
+
+ var connectionInfo = GetConnectionInfo(organizationId, serverUrl);
+
+ ClearInstallDirectory();
+
+ await DownloadRemotelyAgent(serverUrl);
+
+ File.WriteAllText(Path.Combine(InstallPath, "ConnectionInfo.json"), Serializer.Serialize(connectionInfo));
+
+ File.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(InstallPath, "Remotely_Installer.exe"));
+
+ CreateDeviceSetupOptions(deviceGroup, deviceAlias);
+
+ AddFirewallRule();
+
InstallService();
- var programPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Remotely", "ScreenCast", "Remotely_ScreenCast.exe");
- Process.Start("netsh", "advfirewall firewall delete rule name=\"Remotely ScreenCast\"").WaitForExit();
- Process.Start("netsh", $"advfirewall firewall add rule name=\"Remotely ScreenCast\" program=\"{programPath}\" protocol=any dir=in enable=yes action=allow profile=Private,Domain description=\"The agent that allows screen sharing and remote control for Remotely.\"").WaitForExit();
+ CreateUninstallKey();
+
return true;
}
catch (Exception ex)
{
Logger.Write(ex);
+ RestoreBackup();
return false;
}
@@ -47,8 +83,12 @@ namespace Remotely.Agent.Installer.Win.Services
return false;
}
- Process.Start("cmd.exe", "/c sc delete Remotely_Service").WaitForExit();
+ StopService();
+ ProcessWrapper.StartHidden("cmd.exe", "/c sc delete Remotely_Service").WaitForExit();
+
+
+ ProgressMessageChanged?.Invoke(this, "Stopping Remotely processes.");
var procs = Process.GetProcessesByName("Remotely_Agent").Concat(Process.GetProcessesByName("Remotely_ScreenCast"));
foreach (var proc in procs)
@@ -58,9 +98,13 @@ namespace Remotely.Agent.Installer.Win.Services
await Task.Delay(500);
- Directory.Delete(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Remotely"), true);
+ ProgressMessageChanged?.Invoke(this, "Deleting files.");
+ ClearInstallDirectory();
+ ProcessWrapper.StartHidden("cmd.exe", $"/c timeout 5 & rd /s /q \"{InstallPath}\"");
- Process.Start("netsh", "advfirewall firewall delete rule name=\"Remotely ScreenCast\"").WaitForExit();
+ ProcessWrapper.StartHidden("netsh", "advfirewall firewall delete rule name=\"Remotely ScreenCast\"").WaitForExit();
+
+ Registry.LocalMachine.DeleteSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remotely", false);
return true;
@@ -72,6 +116,32 @@ namespace Remotely.Agent.Installer.Win.Services
}
}
+ private void AddFirewallRule()
+ {
+ var screenCastPath = Path.Combine(InstallPath, "ScreenCast", "Remotely_ScreenCast.exe");
+ ProcessWrapper.StartHidden("netsh", "advfirewall firewall delete rule name=\"Remotely ScreenCast\"").WaitForExit();
+ ProcessWrapper.StartHidden("netsh", $"advfirewall firewall add rule name=\"Remotely ScreenCast\" program=\"{screenCastPath}\" protocol=any dir=in enable=yes action=allow profile=Private,Domain description=\"The agent that allows screen sharing and remote control for Remotely.\"").WaitForExit();
+ }
+
+ private void BackupOrCreateDirectory()
+ {
+ if (Directory.Exists(InstallPath))
+ {
+ Logger.Write("Backing up current installation.");
+ ProgressMessageChanged?.Invoke(this, "Backing up current installation.");
+ var backupPath = Path.Combine(Path.GetTempPath(), "Remotely_Backup.zip");
+ if (File.Exists(backupPath))
+ {
+ File.Delete(backupPath);
+ }
+ ZipFile.CreateFromDirectory(InstallPath, backupPath, CompressionLevel.Fastest, false);
+ }
+ else
+ {
+ Directory.CreateDirectory(InstallPath);
+ }
+ }
+
private bool CheckIsAdministrator()
{
var identity = WindowsIdentity.GetCurrent();
@@ -79,19 +149,159 @@ namespace Remotely.Agent.Installer.Win.Services
var result = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!result)
{
- MessageBox.Show("Elevated privileges are required. Please restart the installer using 'Run as administrator'.", "Elevation Required", MessageBoxButton.OK, MessageBoxImage.Warning);
+ MessageBoxWrapper.Show("Elevated privileges are required. Please restart the installer using 'Run as administrator'.", "Elevation Required", MessageBoxButton.OK, MessageBoxImage.Warning);
}
return result;
}
+ private void ClearInstallDirectory()
+ {
+ if (Directory.Exists(InstallPath))
+ {
+ foreach (var entry in Directory.GetFileSystemEntries(InstallPath))
+ {
+ try
+ {
+ if (File.Exists(entry))
+ {
+ File.Delete(entry);
+ }
+ else if (Directory.Exists(entry))
+ {
+ Directory.Delete(entry, true);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+ }
+ }
+
+ private void CreateDeviceSetupOptions(string deviceGroup, string deviceAlias)
+ {
+ if (!string.IsNullOrWhiteSpace(deviceGroup) ||
+ !string.IsNullOrWhiteSpace(deviceAlias))
+ {
+ var setupOptions = new
+ {
+ DeviceGroup = deviceGroup,
+ DeviceAlias = deviceAlias
+ };
+
+ File.WriteAllText(Path.Combine(InstallPath, "DeviceSetupOptions.json"), Serializer.Serialize(setupOptions));
+ }
+ }
+
+ private void CreateUninstallKey()
+ {
+ var remotelyKey = Registry.LocalMachine.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remotely", true);
+ remotelyKey.SetValue("DisplayIcon", Path.Combine(InstallPath, "Remotely_Agent.exe"));
+ remotelyKey.SetValue("DisplayName", "Remotely");
+ remotelyKey.SetValue("DisplayVersion", Assembly.GetExecutingAssembly().GetName().Version.ToString());
+ remotelyKey.SetValue("InstallDate", DateTime.Now.ToShortDateString());
+ remotelyKey.SetValue("Publisher", "Translucency Software");
+ remotelyKey.SetValue("VersionMajor", Assembly.GetExecutingAssembly().GetName().Version.Major.ToString(), RegistryValueKind.DWord);
+ remotelyKey.SetValue("VersionMinor", Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString(), RegistryValueKind.DWord);
+ remotelyKey.SetValue("UninstallString", Path.Combine(InstallPath, "Remotely_Installer.exe -uninstall"));
+ remotelyKey.SetValue("QuietUninstallString", Path.Combine(InstallPath, "Remotely_Installer.exe -uninstall -quiet"));
+ }
+ private async Task DownloadRemotelyAgent(string serverUrl)
+ {
+ ProgressMessageChanged.Invoke(this, "Downloading Remotely agent.");
+ var client = new WebClient();
+ client.DownloadProgressChanged += (sender, args) =>
+ {
+ ProgressValueChanged?.Invoke(this, args.ProgressPercentage);
+ };
+ var targetFile = Path.Combine(Path.GetTempPath(), $"Remotely-Agent.zip");
+ await client.DownloadFileTaskAsync($"{serverUrl}/Downloads/Remotely-Win10-{Platform}.zip", targetFile);
+
+ ProgressMessageChanged.Invoke(this, "Extracting Remotely files.");
+ ProgressValueChanged?.Invoke(this, 0);
+ await Task.Run(() => { ZipFile.ExtractToDirectory(targetFile, InstallPath); });
+ }
+
+ private ConnectionInfo GetConnectionInfo(string organizationId, string serverUrl)
+ {
+ ConnectionInfo connectionInfo;
+ var connectionInfoPath = Path.Combine(InstallPath, "ConnectionInfo.json");
+ if (File.Exists(connectionInfoPath))
+ {
+ connectionInfo = Serializer.Deserialize(File.ReadAllText(connectionInfoPath));
+ connectionInfo.ServerVerificationToken = null;
+ }
+ else
+ {
+ connectionInfo = new ConnectionInfo()
+ {
+ DeviceID = Guid.NewGuid().ToString()
+ };
+ }
+
+ connectionInfo.OrganizationID = organizationId;
+ connectionInfo.Host = serverUrl;
+ return connectionInfo;
+ }
+
+ private async Task InstallDesktpRuntimeIfNeeded()
+ {
+ Logger.Write("Checking for .NET Core runtime.");
+ var uninstallKeys = new List();
+ var runtimeInstalled = false;
+
+ foreach (var subkeyName in Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\", false).GetSubKeyNames())
+ {
+ var subkey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" + subkeyName, false);
+ if (subkey?.GetValue("DisplayName")?.ToString()?.Contains("Microsoft Windows Desktop Runtime - 3.1.2") == true)
+ {
+ runtimeInstalled = true;
+ break;
+ }
+ }
+
+ if (!runtimeInstalled)
+ {
+ Logger.Write("Downloading .NET Core runtime.");
+ ProgressMessageChanged.Invoke(this, "Downloading the .NET Core runtime.");
+ var client = new WebClient();
+ client.DownloadProgressChanged += (sender, args) =>
+ {
+ ProgressValueChanged?.Invoke(this, args.ProgressPercentage);
+ };
+ var downloadUrl = string.Empty;
+ if (Environment.Is64BitOperatingSystem)
+ {
+ downloadUrl = "https://download.visualstudio.microsoft.com/download/pr/3240250e-6fe0-4258-af69-85abef6c00de/e01ee0af6c65d894f4a02bdf6705ec7b/windowsdesktop-runtime-3.1.2-win-x64.exe";
+ }
+ else
+ {
+ downloadUrl = "https://download.visualstudio.microsoft.com/download/pr/b824906f-bd6e-4067-86a6-95c61620674d/cfcdab84a01cee94fdaa31271c3d4d47/windowsdesktop-runtime-3.1.2-win-x86.exe";
+ }
+ var targetFile = Path.Combine(Path.GetTempPath(), "windowsdesktop-runtime.exe");
+ await client.DownloadFileTaskAsync(downloadUrl, targetFile);
+
+ Logger.Write("Installing .NET Core runtime.");
+ ProgressMessageChanged?.Invoke(this, "Installing the .NET Core runtime.");
+ ProgressValueChanged?.Invoke(this, 0);
+
+ await Task.Run(() => { ProcessWrapper.StartHidden(targetFile, "/install /quiet /norestart").WaitForExit(); });
+ }
+ else
+ {
+ Logger.Write(".NET Core runtime already installed.");
+ }
+ }
+
private void InstallService()
{
- Logger.Write("Install started.");
- var installPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
+ Logger.Write("Installing service.");
+ ProgressMessageChanged?.Invoke(this, "Installing Remotely service.");
var serv = ServiceController.GetServices().FirstOrDefault(ser => ser.ServiceName == "Remotely_Service");
if (serv == null)
{
- var command = new string[] { "/assemblypath=" + installPath };
+ var command = new string[] { "/assemblypath=" + Path.Combine(InstallPath, "Remotely_Agent.exe") };
var serviceInstaller = new ServiceInstaller();
var context = new InstallContext("", command);
serviceInstaller.Context = context;
@@ -104,16 +314,51 @@ namespace Remotely.Agent.Installer.Win.Services
var state = new System.Collections.Specialized.ListDictionary();
serviceInstaller.Install(state);
Logger.Write("Service installed.");
+ serv = ServiceController.GetServices().FirstOrDefault(ser => ser.ServiceName == "Remotely_Service");
+
+ ProcessWrapper.StartHidden("cmd.exe", "/c sc.exe failure \"Remotely_Service\" reset=5 actions=restart/5000");
}
- serv = ServiceController.GetServices().FirstOrDefault(ser => ser.ServiceName == "Remotely_Service");
if (serv.Status != ServiceControllerStatus.Running)
{
serv.Start();
}
Logger.Write("Service started.");
- var psi = new ProcessStartInfo("cmd.exe", "/c sc.exe failure \"Remotely_Service\" reset=5 actions=restart/5000");
- psi.WindowStyle = ProcessWindowStyle.Hidden;
- Process.Start(psi).WaitForExit();
+ }
+
+ private void RestoreBackup()
+ {
+ try
+ {
+ var backupPath = Path.Combine(Path.GetTempPath(), "Remotely_Backup.zip");
+ if (File.Exists(backupPath))
+ {
+ Logger.Write("Restoring backup.");
+ ClearInstallDirectory();
+ ZipFile.ExtractToDirectory(backupPath, InstallPath);
+ }
+ }
+ catch (Exception ex)
+ {
+ Logger.Write(ex);
+ }
+ }
+ private void StopService()
+ {
+ try
+ {
+ var remotelyService = ServiceController.GetServices().FirstOrDefault(x => x.ServiceName == "Remotely_Service");
+ if (remotelyService != null)
+ {
+ Logger.Write("Stopping existing Remotely service.");
+ ProgressMessageChanged?.Invoke(this, "Stopping existing Remotely service.");
+ remotelyService.Stop();
+ remotelyService.WaitForStatus(ServiceControllerStatus.Stopped);
+ }
+ }
+ catch(Exception ex)
+ {
+ Logger.Write(ex);
+ }
}
}
}
diff --git a/Agent.Installer.Win/Services/MessageBoxWrapper.cs b/Agent.Installer.Win/Services/MessageBoxWrapper.cs
new file mode 100644
index 00000000..4670a7a4
--- /dev/null
+++ b/Agent.Installer.Win/Services/MessageBoxWrapper.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Remotely.Agent.Installer.Win.Services
+{
+ public class MessageBoxWrapper
+ {
+ public static MessageBoxResult Show(string message, string caption, MessageBoxButton messageBoxButton, MessageBoxImage messageBoxImage)
+ {
+ if (!CommandLineParser.CommandLineArgs.ContainsKey("quiet"))
+ {
+ return MessageBox.Show(message, caption, messageBoxButton, messageBoxImage);
+ }
+ return MessageBoxResult.None;
+ }
+ }
+}
diff --git a/Agent.Installer.Win/Services/ProcessWrapper.cs b/Agent.Installer.Win/Services/ProcessWrapper.cs
new file mode 100644
index 00000000..b00c3fcd
--- /dev/null
+++ b/Agent.Installer.Win/Services/ProcessWrapper.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Remotely.Agent.Installer.Win.Services
+{
+ public static class ProcessWrapper
+ {
+ public static Process StartHidden(string filePath, string arguments)
+ {
+ var psi = new ProcessStartInfo()
+ {
+ WindowStyle = ProcessWindowStyle.Hidden,
+ CreateNoWindow = true,
+ Arguments = arguments,
+ FileName = filePath
+ };
+ return Process.Start(psi);
+ }
+ }
+}
diff --git a/Agent.Installer.Win/ViewModels/MainWindowViewModel.cs b/Agent.Installer.Win/ViewModels/MainWindowViewModel.cs
index fe8ab098..964f50ae 100644
--- a/Agent.Installer.Win/ViewModels/MainWindowViewModel.cs
+++ b/Agent.Installer.Win/ViewModels/MainWindowViewModel.cs
@@ -1,16 +1,17 @@
using Remotely.Agent.Installer.Win.Services;
+using Remotely.Shared.Models;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Runtime.Serialization.Json;
using System.Security.Principal;
using System.ServiceProcess;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
+using System.Web.Script.Serialization;
using System.Windows;
using System.Windows.Input;
@@ -20,6 +21,7 @@ namespace Remotely.Agent.Installer.Win.ViewModels
{
private string headerMessage;
+ private bool isReadyState = true;
private bool isServiceInstalled;
private string organizationName;
@@ -30,8 +32,6 @@ namespace Remotely.Agent.Installer.Win.ViewModels
private string statusMessage;
- private string subMessage;
-
public MainWindowViewModel()
{
Installer = new InstallerService();
@@ -49,10 +49,23 @@ namespace Remotely.Agent.Installer.Win.ViewModels
}
}
- public ICommand InstallCommand => new Executor(Install);
+ public ICommand InstallCommand => new Executor(async (param) => { await Install(param); });
public bool IsProgressVisible => Progress > 0;
+ public bool IsReadyState
+ {
+ get
+ {
+ return isReadyState;
+ }
+ set
+ {
+ isReadyState = value;
+ FirePropertyChanged(nameof(IsReadyState));
+ }
+ }
+
public bool IsServiceInstalled
{
get
@@ -81,8 +94,8 @@ namespace Remotely.Agent.Installer.Win.ViewModels
Process.Start(logPath);
}
else
- {
- MessageBox.Show("Log file doesn't exist.", "No Logs", MessageBoxButton.OK, MessageBoxImage.Information);
+ {
+ MessageBoxWrapper.Show("Log file doesn't exist.", "No Logs", MessageBoxButton.OK, MessageBoxImage.Information);
}
});
}
@@ -141,33 +154,34 @@ namespace Remotely.Agent.Installer.Win.ViewModels
}
}
- public string SubMessage
- {
- get
- {
- return subMessage;
- }
- set
- {
- subMessage = value;
- FirePropertyChanged(nameof(SubMessage));
- }
- }
-
public ICommand UninstallCommand => new Executor(async (param) => { await Uninstall(param); });
+
+ private string DeviceAlias { get; set; }
+ private string DeviceGroup { get; set; }
private InstallerService Installer { get; }
public async Task Init()
{
+
+ Installer.ProgressMessageChanged += (sender, arg) =>
+ {
+ StatusMessage = arg;
+ };
+
+ Installer.ProgressValueChanged += (sender, arg) =>
+ {
+ Progress = arg;
+ };
+
IsServiceInstalled = ServiceController.GetServices().Any(x => x.ServiceName == "Remotely_Service");
- if (IsServiceInstalled)
+ if (IsServiceMissing)
{
HeaderMessage = "Install the Remotely service.";
- SubMessage = "Installing the Remotely service will allow remote access by the above service provider.";
+ StatusMessage = "Installing the Remotely service will allow remote access by the above service provider.";
}
else
{
HeaderMessage = "Uninstall the Remotely service.";
- SubMessage = "Uninstalling the Remotely service will remove all remote acess for the above service provider.";
+ StatusMessage = "Uninstalling the Remotely service will remove all remote acess for the above service provider.";
}
var installerSettings = ReadInstallerSettings();
@@ -176,10 +190,23 @@ namespace Remotely.Agent.Installer.Win.ViewModels
ServerUrl = installerSettings?.ServerUrl;
OrganizationID = installerSettings?.OrganizationID;
- if (Environment.GetCommandLineArgs().Contains("-rununinstaller"))
+ CopyCommandLineArgs();
+
+ if (CommandLineParser.CommandLineArgs.ContainsKey("install"))
+ {
+ await Install(null);
+ }
+ else if (CommandLineParser.CommandLineArgs.ContainsKey("uninstall"))
{
await Uninstall(null);
}
+
+ if (CommandLineParser.CommandLineArgs.ContainsKey("quiet"))
+ {
+ App.Current.Shutdown();
+ }
+
+ CheckParams();
}
public InstallerSettings ReadInstallerSettings()
@@ -194,19 +221,16 @@ namespace Remotely.Agent.Installer.Win.ViewModels
var payloadSize = br.ReadInt32();
peStream.Seek(-4 - payloadSize, SeekOrigin.End);
var payloadBytes = br.ReadBytes(payloadSize);
- using (var settingsStream = new MemoryStream(payloadBytes))
- {
- settingsStream.Seek(0, SeekOrigin.Begin);
- var serializer = new DataContractJsonSerializer(typeof(InstallerSettings));
- var installerSettings = (InstallerSettings)serializer.ReadObject(settingsStream);
- return installerSettings;
- }
+ var payloadJson = Encoding.UTF8.GetString(payloadBytes);
+ var serializer = new JavaScriptSerializer();
+ var installerSettings = serializer.Deserialize(payloadJson);
+ return installerSettings;
}
}
catch (Exception ex)
{
Logger.Write(ex);
- MessageBox.Show("There was an error reading the installer settings. Try re-downloading the installer.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Error);
+ MessageBoxWrapper.Show("There was an error reading the installer settings. Try re-downloading the installer.", "Configuration Error", MessageBoxButton.OK, MessageBoxImage.Error);
return null;
}
}
@@ -218,7 +242,7 @@ namespace Remotely.Agent.Installer.Win.ViewModels
var result = principal.IsInRole(WindowsBuiltInRole.Administrator);
if (!result)
{
- MessageBox.Show("Elevated privileges are required. Please restart the installer using 'Run as administrator'.", "Elevation Required", MessageBoxButton.OK, MessageBoxImage.Warning);
+ MessageBoxWrapper.Show("Elevated privileges are required. Please restart the installer using 'Run as administrator'.", "Elevation Required", MessageBoxButton.OK, MessageBoxImage.Warning);
}
return result;
}
@@ -228,33 +252,66 @@ namespace Remotely.Agent.Installer.Win.ViewModels
var result = !string.IsNullOrWhiteSpace(OrganizationID) && !string.IsNullOrWhiteSpace(ServerUrl);
if (!result)
{
- MessageBox.Show("Required settings are missing. Try re-downloading the installer.", "Invalid Installer", MessageBoxButton.OK, MessageBoxImage.Error);
+ MessageBoxWrapper.Show("Required settings are missing. Try re-downloading the installer.", "Invalid Installer", MessageBoxButton.OK, MessageBoxImage.Error);
}
return result;
}
- private void Install(object param)
+ private void CopyCommandLineArgs()
+ {
+ if (CommandLineParser.CommandLineArgs.TryGetValue("organization", out var orgName))
+ {
+ OrganizationName = orgName;
+ }
+
+ if (CommandLineParser.CommandLineArgs.TryGetValue("organizationid", out var orgID))
+ {
+ OrganizationID = orgID;
+ }
+
+ if (CommandLineParser.CommandLineArgs.TryGetValue("serverurl", out var serverUrl))
+ {
+ ServerUrl = serverUrl;
+ }
+
+ if (CommandLineParser.CommandLineArgs.TryGetValue("devicegroup", out var deviceGroup))
+ {
+ DeviceGroup = deviceGroup;
+ }
+
+ if (CommandLineParser.CommandLineArgs.TryGetValue("devicealias", out var deviceAlias))
+ {
+ DeviceAlias = deviceAlias;
+ }
+
+ if (ServerUrl?.EndsWith("/") == true)
+ {
+ ServerUrl = ServerUrl.Substring(0, ServerUrl.LastIndexOf("/"));
+ }
+ }
+ private async Task Install(object param)
{
try
{
+ IsReadyState = false;
if (!CheckParams())
{
return;
}
- if (Installer.Install())
+ if (await Installer.Install(ServerUrl, OrganizationID, DeviceGroup, DeviceAlias))
{
IsServiceInstalled = true;
Progress = 0;
HeaderMessage = "Installation completed.";
- SubMessage = "Remotely has been installed. You can now close this window.";
+ StatusMessage = "Remotely has been installed. You can now close this window.";
}
else
{
Progress = 0;
HeaderMessage = "An error occurred during installation.";
- SubMessage = "There was an error during installation. Check the logs for details.";
+ StatusMessage = "There was an error during installation. Check the logs for details.";
}
if (!CheckIsAdministrator())
{
@@ -265,12 +322,20 @@ namespace Remotely.Agent.Installer.Win.ViewModels
{
Logger.Write(ex);
}
-
+ finally
+ {
+ IsReadyState = true;
+ }
}
+
+
+
private async Task Uninstall(object param)
{
try
{
+ IsReadyState = false;
+
if (!CheckParams())
{
return;
@@ -281,13 +346,13 @@ namespace Remotely.Agent.Installer.Win.ViewModels
IsServiceInstalled = false;
Progress = 0;
HeaderMessage = "Uninstall completed.";
- SubMessage = "Remotely has been uninstalled. You can now close this window.";
+ StatusMessage = "Remotely has been uninstalled. You can now close this window.";
}
else
{
Progress = 0;
HeaderMessage = "An error occurred during uninstall.";
- SubMessage = "There was an error during uninstall. Check the logs for details.";
+ StatusMessage = "There was an error during uninstall. Check the logs for details.";
}
}
@@ -295,6 +360,10 @@ namespace Remotely.Agent.Installer.Win.ViewModels
{
Logger.Write(ex);
}
+ finally
+ {
+ IsReadyState = true;
+ }
}
}
}
diff --git a/Agent/Agent.csproj b/Agent/Agent.csproj
index e7920aa4..5acc5e7d 100644
--- a/Agent/Agent.csproj
+++ b/Agent/Agent.csproj
@@ -23,11 +23,11 @@
-
-
-
+
+
+
-
+
diff --git a/ScreenCast.Core/ScreenCast.Core.csproj b/ScreenCast.Core/ScreenCast.Core.csproj
index ea44bfc4..04e3e0cb 100644
--- a/ScreenCast.Core/ScreenCast.Core.csproj
+++ b/ScreenCast.Core/ScreenCast.Core.csproj
@@ -32,10 +32,10 @@
-
-
-
-
+
+
+
+
diff --git a/ScreenCast.Win/ScreenCast.Win.csproj b/ScreenCast.Win/ScreenCast.Win.csproj
index 2f1ca421..f1fba3be 100644
--- a/ScreenCast.Win/ScreenCast.Win.csproj
+++ b/ScreenCast.Win/ScreenCast.Win.csproj
@@ -23,8 +23,8 @@
-
-
+
+
diff --git a/Server/Server.csproj b/Server/Server.csproj
index 4f0a7db4..fc46cdf7 100644
--- a/Server/Server.csproj
+++ b/Server/Server.csproj
@@ -63,20 +63,20 @@
-
-
-
-
-
-
+
+
+
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
-
+
diff --git a/Shared/Models/InstallerSettings.cs b/Shared/Models/InstallerSettings.cs
index 95b6c76c..68b5ef9e 100644
--- a/Shared/Models/InstallerSettings.cs
+++ b/Shared/Models/InstallerSettings.cs
@@ -7,16 +7,12 @@ using System.Threading.Tasks;
namespace Remotely.Shared.Models
{
- [DataContract]
public class InstallerSettings
{
- [DataMember]
public string OrganizationID { get; set; }
- [DataMember]
public string OrganizationName { get; set; }
- [DataMember]
public string ServerUrl { get; set; }
}
}
diff --git a/Shared/Shared.csproj b/Shared/Shared.csproj
index b2f8bc4d..f3c79058 100644
--- a/Shared/Shared.csproj
+++ b/Shared/Shared.csproj
@@ -8,10 +8,10 @@
-
+
-
+