mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
Remove now-unused installer project.
This commit is contained in:
parent
1afcc8c8b5
commit
699b779b41
@ -1,210 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{A3D0368C-0850-4614-B5B5-41B9D5135AA9}</ProjectGuid>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<RootNamespace>Remotely.Agent.Installer.Win</RootNamespace>
|
||||
<AssemblyName>Remotely_Installer</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
<Deterministic>true</Deterministic>
|
||||
<TargetFrameworkProfile />
|
||||
<LangVersion>10</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RuntimeIdentifiers>win;win-x64;win10-x64;win-x64;win10-x86;</RuntimeIdentifiers>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationIcon>Assets\favicon.ico</ApplicationIcon>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x64\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>bin\x86\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<OutputPath>bin\x86\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<StartupObject>
|
||||
</StartupObject>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.VisualBasic" />
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration.Install" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.IO.Compression.FileSystem" />
|
||||
<Reference Include="System.Runtime.Serialization">
|
||||
<HintPath>C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.2\System.Runtime.Serialization.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.ServiceProcess" />
|
||||
<Reference Include="System.Web.Extensions" />
|
||||
<Reference Include="System.Xml" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xaml">
|
||||
<RequiredTargetFramework>4.0</RequiredTargetFramework>
|
||||
</Reference>
|
||||
<Reference Include="WindowsBase" />
|
||||
<Reference Include="PresentationCore" />
|
||||
<Reference Include="PresentationFramework" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ApplicationDefinition Include="App.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="..\Shared\AppConstants.cs">
|
||||
<Link>AppConstants.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Models\ConnectionInfo.cs">
|
||||
<Link>Models\ConnectionInfo.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="..\Shared\Models\DeviceSetupOptions.cs">
|
||||
<Link>Models\DeviceSetupOptions.cs</Link>
|
||||
</Compile>
|
||||
<Compile Include="Models\BrandingInfo.cs" />
|
||||
<Compile Include="Models\EmbeddedServerData.cs" />
|
||||
<Compile Include="Services\EmbeddedServerDataReader.cs" />
|
||||
<Compile Include="Utilities\CommandLineParser.cs" />
|
||||
<Compile Include="Utilities\MessageBoxEx.cs" />
|
||||
<Compile Include="Services\RelayCommand.cs" />
|
||||
<Compile Include="Services\InstallerService.cs" />
|
||||
<Compile Include="Utilities\Logger.cs" />
|
||||
<Compile Include="Utilities\ProcessEx.cs" />
|
||||
<Compile Include="ViewModels\MainWindowViewModel.cs" />
|
||||
<Compile Include="ViewModels\ViewModelBase.cs" />
|
||||
<Page Include="MainWindow.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Compile Include="App.xaml.cs">
|
||||
<DependentUpon>App.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="MainWindow.xaml.cs">
|
||||
<DependentUpon>MainWindow.xaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Properties\AssemblyInfo.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Resources.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\Settings.Designer.cs">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="Properties\Resources.resx">
|
||||
<Generator>ResXFileCodeGenerator</Generator>
|
||||
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<None Include="app.manifest" />
|
||||
<None Include="Properties\Settings.settings">
|
||||
<Generator>SettingsSingleFileGenerator</Generator>
|
||||
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Assets\favicon.ico" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<EmbeddedResource Include="Assets\Remotely_Icon.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<COMReference Include="IWshRuntimeLibrary">
|
||||
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||
<VersionMajor>1</VersionMajor>
|
||||
<VersionMinor>0</VersionMinor>
|
||||
<Lcid>0</Lcid>
|
||||
<WrapperTool>tlbimp</WrapperTool>
|
||||
<Isolated>False</Isolated>
|
||||
<EmbedInteropTypes>True</EmbedInteropTypes>
|
||||
</COMReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
|
||||
</startup>
|
||||
</configuration>
|
||||
@ -1,31 +0,0 @@
|
||||
<Application x:Class="Remotely.Agent.Installer.Win.App"
|
||||
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">
|
||||
<Application.Resources>
|
||||
<Style x:Key="TitlebarButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="#FF464646"></Setter>
|
||||
<Setter Property="DockPanel.Dock" Value="Right"></Setter>
|
||||
<Setter Property="HorizontalAlignment" Value="Right"></Setter>
|
||||
<Setter Property="BorderBrush" Value="{x:Null}"></Setter>
|
||||
<Setter Property="Foreground" Value="White"></Setter>
|
||||
<Setter Property="FontWeight" Value="Bold"></Setter>
|
||||
<Setter Property="Height" Value="30"></Setter>
|
||||
<Setter Property="Width" Value="30"></Setter>
|
||||
<Setter Property="Cursor" Value="Hand"></Setter>
|
||||
<Setter Property="Margin" Value="5,0,5,0"></Setter>
|
||||
</Style>
|
||||
<Style x:Key="SectionHeader" TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="Bold"></Setter>
|
||||
<Setter Property="FontSize" Value="18"></Setter>
|
||||
</Style>
|
||||
<Style x:Key="NormalButton" TargetType="Button">
|
||||
<Setter Property="Background" Value="White"></Setter>
|
||||
<Setter Property="BorderThickness" Value="1"></Setter>
|
||||
<Setter Property="BorderBrush" Value="Black"></Setter>
|
||||
<Setter Property="Padding" Value="6,4"></Setter>
|
||||
<Setter Property="FontSize" Value="14"></Setter>
|
||||
</Style>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
@ -1,11 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for App.xaml
|
||||
/// </summary>
|
||||
public partial class App : Application
|
||||
{
|
||||
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 103 KiB |
@ -1,144 +0,0 @@
|
||||
<Window x:Class="Remotely.Agent.Installer.Win.MainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ViewModels="clr-namespace:Remotely.Agent.Installer.Win.ViewModels"
|
||||
xmlns:local="clr-namespace:Remotely.Agent.Installer.Win"
|
||||
mc:Ignorable="d"
|
||||
ResizeMode="CanResizeWithGrip"
|
||||
MouseLeftButtonDown="Window_MouseLeftButtonDown"
|
||||
Loaded="Window_Loaded"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
Title="Remotely Installer" Height="335" Width="500" Icon="{Binding Icon}">
|
||||
<Window.Resources>
|
||||
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
|
||||
</Window.Resources>
|
||||
<Window.DataContext>
|
||||
<ViewModels:MainWindowViewModel/>
|
||||
</Window.DataContext>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid Grid.Row="0" Margin="10,15,10,0">
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource SectionHeader}" Text="{Binding HeaderMessage}" Margin="0,0,0,10"></TextBlock>
|
||||
<Grid Margin="25,5,0,0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition/>
|
||||
<RowDefinition Height="20" />
|
||||
<RowDefinition/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="0">
|
||||
<TextBlock FontSize="14">Server URL:</TextBlock>
|
||||
|
||||
<Button Grid.Column="1" Grid.Row="0"
|
||||
Background="White"
|
||||
FontSize="14"
|
||||
Margin="5,0"
|
||||
BorderThickness="0"
|
||||
Padding="3"
|
||||
Cursor="Hand"
|
||||
Click="ShowServerUrlHelp">
|
||||
<TextBlock Text=""
|
||||
FontWeight="Bold"
|
||||
FontFamily="Segoe MDL2 Assets"
|
||||
PreviewMouseUp="ShowServerUrlHelp"></TextBlock>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<TextBox Grid.Column="1" Grid.Row="0" TextWrapping="Wrap" Text="{Binding ServerUrl}" FontSize="14" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="2">
|
||||
<TextBlock FontSize="14">Organization ID</TextBlock>
|
||||
|
||||
<Button Grid.Column="1" Grid.Row="0"
|
||||
Background="White"
|
||||
FontSize="14"
|
||||
Margin="5,0"
|
||||
BorderThickness="0"
|
||||
Padding="3"
|
||||
Cursor="Hand"
|
||||
Click="ShowOrganizationIdHelp">
|
||||
<TextBlock Text=""
|
||||
FontWeight="Bold"
|
||||
FontFamily="Segoe MDL2 Assets"></TextBlock>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
|
||||
<TextBox Grid.Column="1" Grid.Row="2" TextWrapping="Wrap" Text="{Binding OrganizationID}" FontSize="14" />
|
||||
|
||||
<StackPanel Orientation="Horizontal" Grid.Column="0" Grid.Row="4">
|
||||
<TextBlock FontSize="14">Support Shortcut</TextBlock>
|
||||
|
||||
<Button Grid.Column="1" Grid.Row="0"
|
||||
Background="White"
|
||||
FontSize="14"
|
||||
Margin="5,0"
|
||||
BorderThickness="0"
|
||||
Padding="3"
|
||||
Cursor="Hand"
|
||||
Click="ShowSupportShortcutHelp">
|
||||
<TextBlock Text=""
|
||||
FontWeight="Bold"
|
||||
FontFamily="Segoe MDL2 Assets"></TextBlock>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<CheckBox Grid.Column="1" Grid.Row="4" VerticalAlignment="Center" IsChecked="{Binding CreateSupportShortcut}" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" Margin="40,25,40,0" Text="{Binding StatusMessage}" FontSize="14"></TextBlock>
|
||||
<ProgressBar Height="25" Margin="40,10,40,0" Value="{Binding Progress}" Visibility="{Binding IsProgressVisible, Converter={StaticResource BooleanToVisibilityConverter}}"></ProgressBar>
|
||||
</StackPanel>
|
||||
|
||||
</Grid>
|
||||
|
||||
<DockPanel Margin="10" Grid.Row="1">
|
||||
<Button DockPanel.Dock="Left"
|
||||
HorizontalAlignment="Left"
|
||||
Style="{StaticResource NormalButton}"
|
||||
Margin="5,0,0,0"
|
||||
Command="{Binding OpenLogsCommand}">
|
||||
Logs
|
||||
</Button>
|
||||
|
||||
<Button DockPanel.Dock="Right"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource NormalButton}"
|
||||
Margin="5,0,0,0"
|
||||
Click="CloseButton_Click">
|
||||
Close
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource NormalButton}"
|
||||
Margin="5,0,0,0"
|
||||
IsEnabled="{Binding IsReadyState}"
|
||||
Visibility="{Binding IsServiceInstalled, Converter={StaticResource BooleanToVisibilityConverter}}"
|
||||
Command="{Binding UninstallCommand}">
|
||||
Uninstall
|
||||
</Button>
|
||||
<Button DockPanel.Dock="Right"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource NormalButton}"
|
||||
Content="{Binding InstallButtonText}"
|
||||
Margin="5,0,0,0"
|
||||
IsEnabled="{Binding IsReadyState}"
|
||||
Command="{Binding InstallCommand}">
|
||||
</Button>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
@ -1,76 +0,0 @@
|
||||
using Remotely.Agent.Installer.Win.Utilities;
|
||||
using Remotely.Agent.Installer.Win.ViewModels;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win;
|
||||
|
||||
/// <summary>
|
||||
/// Interaction logic for MainWindow.xaml
|
||||
/// </summary>
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
if (CommandLineParser.CommandLineArgs.ContainsKey("quiet"))
|
||||
{
|
||||
Hide();
|
||||
ShowInTaskbar = false;
|
||||
_ = new MainWindowViewModel().Init();
|
||||
}
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
DragMove();
|
||||
}
|
||||
|
||||
private async void Window_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DataContext is MainWindowViewModel viewModel)
|
||||
{
|
||||
await viewModel.Init();
|
||||
}
|
||||
}
|
||||
|
||||
private void CloseButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
App.Current.Shutdown();
|
||||
}
|
||||
|
||||
private void MinimizeButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.WindowState = WindowState.Minimized;
|
||||
}
|
||||
|
||||
private void ShowServerUrlHelp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show(
|
||||
"This is the URL of the Remotely server that you're hosting. The device will connect to this URL.",
|
||||
"Server URL",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
private void ShowOrganizationIdHelp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show(
|
||||
"This is your organization ID on the Remotely server. Since Remotely supports multi-tenancy, " +
|
||||
"this ID needs to be provided to determine who should have access."
|
||||
+ Environment.NewLine + Environment.NewLine +
|
||||
"You can find this ID on the Organization tab on the web app.",
|
||||
"Organization ID",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Information);
|
||||
}
|
||||
private void ShowSupportShortcutHelp(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageBox.Show("If selected, the installer will create a desktop shortcut to the Get Support page for this device.",
|
||||
"Support Shortcut",
|
||||
MessageBoxButton.OK,
|
||||
MessageBoxImage.Information);
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Models;
|
||||
|
||||
public class BrandingInfo
|
||||
{
|
||||
public string Product { get; set; } = "Remotely";
|
||||
|
||||
public string? Icon { get; set; }
|
||||
}
|
||||
@ -1,28 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Remotely.Agent.Installer.Models;
|
||||
|
||||
[DataContract]
|
||||
public class EmbeddedServerData
|
||||
{
|
||||
/// <summary>
|
||||
/// Parameterless constructor for JsonSerializer.
|
||||
/// </summary>
|
||||
public EmbeddedServerData() { }
|
||||
|
||||
public EmbeddedServerData(Uri serverUrl, string organizationId)
|
||||
{
|
||||
ServerUrl = serverUrl;
|
||||
OrganizationId = organizationId;
|
||||
}
|
||||
|
||||
public static EmbeddedServerData Empty { get; } = new EmbeddedServerData();
|
||||
|
||||
[DataMember]
|
||||
public string OrganizationId { get; set; } = string.Empty;
|
||||
|
||||
[DataMember]
|
||||
public Uri? ServerUrl { get; set; }
|
||||
}
|
||||
@ -1,53 +0,0 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Remotely Installer")]
|
||||
[assembly: AssemblyDescription("An installer for the Remotely service, which provides unattended remote access and remote scripting.")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Immense Networks")]
|
||||
[assembly: AssemblyProduct("Remotely Installer")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2020 Immense Networks")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
63
Agent.Installer.Win/Properties/Resources.Designer.cs
generated
63
Agent.Installer.Win/Properties/Resources.Designer.cs
generated
@ -1,63 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Properties {
|
||||
using System;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||
/// </summary>
|
||||
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||
// class via a tool like ResGen or Visual Studio.
|
||||
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||
// with the /str option, or rebuild your VS project.
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
internal class Resources {
|
||||
|
||||
private static global::System.Resources.ResourceManager resourceMan;
|
||||
|
||||
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||
|
||||
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||
internal Resources() {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the cached ResourceManager instance used by this class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Resources.ResourceManager ResourceManager {
|
||||
get {
|
||||
if (object.ReferenceEquals(resourceMan, null)) {
|
||||
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Remotely.Agent.Installer.Win.Properties.Resources", typeof(Resources).Assembly);
|
||||
resourceMan = temp;
|
||||
}
|
||||
return resourceMan;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the current thread's CurrentUICulture property for all
|
||||
/// resource lookups using this strongly typed resource class.
|
||||
/// </summary>
|
||||
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||
internal static global::System.Globalization.CultureInfo Culture {
|
||||
get {
|
||||
return resourceCulture;
|
||||
}
|
||||
set {
|
||||
resourceCulture = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,117 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
26
Agent.Installer.Win/Properties/Settings.Designer.cs
generated
26
Agent.Installer.Win/Properties/Settings.Designer.cs
generated
@ -1,26 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version:4.0.30319.42000
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Properties {
|
||||
|
||||
|
||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.8.1.0")]
|
||||
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
|
||||
|
||||
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
|
||||
|
||||
public static Settings Default {
|
||||
get {
|
||||
return defaultInstance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
|
||||
<Profiles>
|
||||
<Profile Name="(Default)" />
|
||||
</Profiles>
|
||||
<Settings />
|
||||
</SettingsFile>
|
||||
@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Script.Serialization;
|
||||
using Remotely.Agent.Installer.Models;
|
||||
using Remotely.Agent.Installer.Win.Utilities;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Services;
|
||||
|
||||
internal class EmbeddedServerDataReader
|
||||
{
|
||||
private readonly JavaScriptSerializer _serializer = new JavaScriptSerializer();
|
||||
|
||||
public async Task<EmbeddedServerData> TryGetEmbeddedData(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new Exception($"File path does not exist: {filePath}");
|
||||
}
|
||||
|
||||
using var fs = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
using var br = new BinaryReader(fs);
|
||||
using var sr = new StreamReader(fs);
|
||||
|
||||
fs.Seek(-4, SeekOrigin.End);
|
||||
var dataSize = br.ReadInt32();
|
||||
fs.Seek(-dataSize - 4, SeekOrigin.End);
|
||||
|
||||
if (dataSize == 0)
|
||||
{
|
||||
return EmbeddedServerData.Empty;
|
||||
}
|
||||
|
||||
var buffer = new byte[dataSize];
|
||||
await fs.ReadAsync(buffer, 0, dataSize);
|
||||
var json = Encoding.UTF8.GetString(buffer);
|
||||
|
||||
Logger.Write($"Extracted embedded data from EXE: {json}");
|
||||
|
||||
var embeddedData = _serializer.Deserialize<EmbeddedServerData>(json);
|
||||
if (embeddedData is not null)
|
||||
{
|
||||
return embeddedData;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
return EmbeddedServerData.Empty;
|
||||
}
|
||||
}
|
||||
@ -1,455 +0,0 @@
|
||||
#nullable enable
|
||||
using IWshRuntimeLibrary;
|
||||
using Microsoft.VisualBasic.FileIO;
|
||||
using Microsoft.Win32;
|
||||
using Remotely.Agent.Installer.Win.Utilities;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
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.Threading.Tasks;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Windows;
|
||||
using FileIO = System.IO.File;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Services;
|
||||
|
||||
public class InstallerService
|
||||
{
|
||||
private readonly string _installPath = Path.Combine(Path.GetPathRoot(Environment.SystemDirectory), "Program Files", "Remotely");
|
||||
private readonly string _platform = Environment.Is64BitOperatingSystem ? "x64" : "x86";
|
||||
private readonly JavaScriptSerializer _serializer = new JavaScriptSerializer();
|
||||
|
||||
public event EventHandler<string>? ProgressMessageChanged;
|
||||
public event EventHandler<int>? ProgressValueChanged;
|
||||
|
||||
public async Task<bool> Install(string serverUrl,
|
||||
string organizationId,
|
||||
string? deviceGroup,
|
||||
string? deviceAlias,
|
||||
string? deviceUuid,
|
||||
bool createSupportShortcut)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger.Write("Install started.");
|
||||
if (!CheckIsAdministrator())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StopService();
|
||||
|
||||
await StopProcesses();
|
||||
|
||||
BackupDirectory();
|
||||
|
||||
var connectionInfo = GetConnectionInfo(organizationId, serverUrl, deviceUuid);
|
||||
|
||||
ClearInstallDirectory();
|
||||
|
||||
await DownloadRemotelyAgent(serverUrl);
|
||||
|
||||
FileIO.WriteAllText(Path.Combine(_installPath, "ConnectionInfo.json"), _serializer.Serialize(connectionInfo));
|
||||
|
||||
FileIO.Copy(Assembly.GetExecutingAssembly().Location, Path.Combine(_installPath, "Remotely_Installer.exe"));
|
||||
|
||||
await CreateDeviceOnServer(connectionInfo.DeviceID, serverUrl, deviceGroup, deviceAlias, organizationId);
|
||||
|
||||
AddFirewallRule();
|
||||
|
||||
InstallService();
|
||||
|
||||
CreateUninstallKey();
|
||||
|
||||
CreateSupportShortcut(serverUrl, connectionInfo.DeviceID, createSupportShortcut);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
RestoreBackup();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public async Task<bool> Uninstall()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!CheckIsAdministrator())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
StopService();
|
||||
|
||||
ProcessEx.StartHidden("cmd.exe", "/c sc delete Remotely_Service").WaitForExit();
|
||||
|
||||
await StopProcesses();
|
||||
|
||||
ProgressMessageChanged?.Invoke(this, "Deleting files.");
|
||||
ClearInstallDirectory();
|
||||
ProcessEx.StartHidden("cmd.exe", $"/c timeout 5 & rd /s /q \"{_installPath}\"");
|
||||
|
||||
ProcessEx.StartHidden("netsh", "advfirewall firewall delete rule name=\"Remotely Desktop Unattended\"").WaitForExit();
|
||||
|
||||
GetRegistryBaseKey().DeleteSubKeyTree(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remotely", false);
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void AddFirewallRule()
|
||||
{
|
||||
var desktopExePath = Path.Combine(_installPath, "Desktop", "Remotely_Desktop.exe");
|
||||
ProcessEx.StartHidden("netsh", "advfirewall firewall delete rule name=\"Remotely Desktop Unattended\"").WaitForExit();
|
||||
ProcessEx.StartHidden("netsh", $"advfirewall firewall add rule name=\"Remotely Desktop Unattended\" program=\"{desktopExePath}\" protocol=any dir=in enable=yes action=allow description=\"The agent that allows screen sharing and remote control for Remotely.\"").WaitForExit();
|
||||
}
|
||||
|
||||
private void BackupDirectory()
|
||||
{
|
||||
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 (FileIO.Exists(backupPath))
|
||||
{
|
||||
FileIO.Delete(backupPath);
|
||||
}
|
||||
ZipFile.CreateFromDirectory(_installPath, backupPath, CompressionLevel.Fastest, false);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckIsAdministrator()
|
||||
{
|
||||
var identity = WindowsIdentity.GetCurrent();
|
||||
var principal = new WindowsPrincipal(identity);
|
||||
var result = principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
if (!result)
|
||||
{
|
||||
MessageBoxEx.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 (FileIO.Exists(entry))
|
||||
{
|
||||
FileIO.Delete(entry);
|
||||
}
|
||||
else if (Directory.Exists(entry))
|
||||
{
|
||||
Directory.Delete(entry, true);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CreateDeviceOnServer(string deviceUuid,
|
||||
string serverUrl,
|
||||
string? deviceGroup,
|
||||
string? deviceAlias,
|
||||
string organizationId)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(deviceGroup) ||
|
||||
!string.IsNullOrWhiteSpace(deviceAlias))
|
||||
{
|
||||
var setupOptions = new DeviceSetupOptions()
|
||||
{
|
||||
DeviceID = deviceUuid,
|
||||
DeviceGroupName = deviceGroup,
|
||||
DeviceAlias = deviceAlias,
|
||||
OrganizationID = organizationId
|
||||
};
|
||||
|
||||
var wr = WebRequest.CreateHttp(serverUrl.TrimEnd('/') + "/api/devices");
|
||||
wr.Method = "POST";
|
||||
wr.ContentType = "application/json";
|
||||
using (var rs = await wr.GetRequestStreamAsync())
|
||||
using (var sw = new StreamWriter(rs))
|
||||
{
|
||||
await sw.WriteAsync(_serializer.Serialize(setupOptions));
|
||||
}
|
||||
using var response = await wr.GetResponseAsync();
|
||||
if (response is HttpWebResponse httpResponse)
|
||||
{
|
||||
Logger.Write($"Create device response: {httpResponse.StatusCode}");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException ex) when ((ex.Response is HttpWebResponse response) && response.StatusCode == HttpStatusCode.BadRequest)
|
||||
{
|
||||
Logger.Write("Bad request when creating device. The device ID may already be created.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CreateSupportShortcut(string serverUrl, string deviceUuid, bool createSupportShortcut)
|
||||
{
|
||||
var shell = new WshShell();
|
||||
var shortcutLocation = Path.Combine(_installPath, "Get Support.lnk");
|
||||
var shortcut = (IWshShortcut)shell.CreateShortcut(shortcutLocation);
|
||||
shortcut.Description = "Get IT support";
|
||||
shortcut.IconLocation = Path.Combine(_installPath, "Remotely_Agent.exe");
|
||||
shortcut.TargetPath = serverUrl.TrimEnd('/') + $"/get-support?deviceID={deviceUuid}";
|
||||
shortcut.Save();
|
||||
|
||||
if (createSupportShortcut)
|
||||
{
|
||||
var systemRoot = Path.GetPathRoot(Environment.SystemDirectory);
|
||||
var publicDesktop = Path.Combine(systemRoot, "Users", "Public", "Desktop", "Get Support.lnk");
|
||||
FileIO.Copy(shortcutLocation, publicDesktop, true);
|
||||
}
|
||||
}
|
||||
private void CreateUninstallKey()
|
||||
{
|
||||
var version = FileVersionInfo.GetVersionInfo(Path.Combine(_installPath, "Remotely_Agent.exe"));
|
||||
var baseKey = GetRegistryBaseKey();
|
||||
|
||||
var remotelyKey = baseKey.CreateSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Remotely", true);
|
||||
remotelyKey.SetValue("DisplayIcon", Path.Combine(_installPath, "Remotely_Agent.exe"));
|
||||
remotelyKey.SetValue("DisplayName", "Remotely");
|
||||
remotelyKey.SetValue("DisplayVersion", version.FileVersion);
|
||||
remotelyKey.SetValue("InstallDate", DateTime.Now.ToShortDateString());
|
||||
remotelyKey.SetValue("Publisher", "Immense Networks");
|
||||
remotelyKey.SetValue("VersionMajor", version.FileMajorPart.ToString(), RegistryValueKind.DWord);
|
||||
remotelyKey.SetValue("VersionMinor", version.FileMinorPart.ToString(), RegistryValueKind.DWord);
|
||||
remotelyKey.SetValue("UninstallString", Path.Combine(_installPath, "Remotely_Installer.exe -uninstall -quiet"));
|
||||
remotelyKey.SetValue("QuietUninstallString", Path.Combine(_installPath, "Remotely_Installer.exe -uninstall -quiet"));
|
||||
}
|
||||
|
||||
private async Task DownloadRemotelyAgent(string serverUrl)
|
||||
{
|
||||
var targetFile = Path.Combine(Path.GetTempPath(), $"Remotely-Agent.zip");
|
||||
|
||||
if (CommandLineParser.CommandLineArgs.TryGetValue("path", out var result) &&
|
||||
FileIO.Exists(result))
|
||||
{
|
||||
targetFile = result;
|
||||
}
|
||||
else
|
||||
{
|
||||
ProgressMessageChanged?.Invoke(this, "Downloading Remotely agent.");
|
||||
using (var client = new WebClient())
|
||||
{
|
||||
client.DownloadProgressChanged += (sender, args) =>
|
||||
{
|
||||
ProgressValueChanged?.Invoke(this, args.ProgressPercentage);
|
||||
};
|
||||
|
||||
await client.DownloadFileTaskAsync($"{serverUrl}/Content/Remotely-Win-{_platform}.zip", targetFile);
|
||||
}
|
||||
}
|
||||
|
||||
ProgressMessageChanged?.Invoke(this, "Extracting Remotely files.");
|
||||
ProgressValueChanged?.Invoke(this, 0);
|
||||
|
||||
var tempDir = Path.Combine(Path.GetTempPath(), "RemotelyUpdate");
|
||||
if (Directory.Exists(tempDir))
|
||||
{
|
||||
Directory.Delete(tempDir, true);
|
||||
}
|
||||
|
||||
Directory.CreateDirectory(_installPath);
|
||||
while (!Directory.Exists(_installPath))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
}
|
||||
|
||||
var wr = WebRequest.CreateHttp($"{serverUrl}/Content/Remotely-Win-{_platform}.zip");
|
||||
wr.Method = "Head";
|
||||
using (var response = (HttpWebResponse)await wr.GetResponseAsync())
|
||||
{
|
||||
FileIO.WriteAllText(Path.Combine(_installPath, "etag.txt"), response.Headers["ETag"]);
|
||||
}
|
||||
|
||||
ZipFile.ExtractToDirectory(targetFile, tempDir);
|
||||
var fileSystemEntries = Directory.GetFileSystemEntries(tempDir);
|
||||
for (var i = 0; i < fileSystemEntries.Length; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProgressValueChanged?.Invoke(this, (int)((double)i / (double)fileSystemEntries.Length * 100d));
|
||||
var entry = fileSystemEntries[i];
|
||||
if (FileIO.Exists(entry))
|
||||
{
|
||||
FileIO.Copy(entry, Path.Combine(_installPath, Path.GetFileName(entry)), true);
|
||||
}
|
||||
else if (Directory.Exists(entry))
|
||||
{
|
||||
FileSystem.CopyDirectory(entry, Path.Combine(_installPath, new DirectoryInfo(entry).Name), true);
|
||||
}
|
||||
await Task.Delay(1);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
ProgressValueChanged?.Invoke(this, 0);
|
||||
}
|
||||
|
||||
private ConnectionInfo GetConnectionInfo(string organizationId, string serverUrl, string? deviceUuid)
|
||||
{
|
||||
ConnectionInfo connectionInfo;
|
||||
var connectionInfoPath = Path.Combine(_installPath, "ConnectionInfo.json");
|
||||
if (FileIO.Exists(connectionInfoPath))
|
||||
{
|
||||
connectionInfo = _serializer.Deserialize<ConnectionInfo>(FileIO.ReadAllText(connectionInfoPath));
|
||||
connectionInfo.ServerVerificationToken = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionInfo = new ConnectionInfo()
|
||||
{
|
||||
DeviceID = Guid.NewGuid().ToString()
|
||||
};
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(deviceUuid))
|
||||
{
|
||||
// Clear the server verification token if we're installing this as a new device.
|
||||
if (connectionInfo.DeviceID != deviceUuid)
|
||||
{
|
||||
connectionInfo.ServerVerificationToken = null;
|
||||
}
|
||||
connectionInfo.DeviceID = deviceUuid!;
|
||||
}
|
||||
connectionInfo.OrganizationID = organizationId;
|
||||
connectionInfo.Host = serverUrl;
|
||||
return connectionInfo;
|
||||
}
|
||||
|
||||
private RegistryKey GetRegistryBaseKey()
|
||||
{
|
||||
if (Environment.Is64BitOperatingSystem)
|
||||
{
|
||||
return RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry64);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, RegistryView.Registry32);
|
||||
}
|
||||
}
|
||||
|
||||
private void InstallService()
|
||||
{
|
||||
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=" + Path.Combine(_installPath, "Remotely_Agent.exe") };
|
||||
var context = new InstallContext("", command);
|
||||
var serviceInstaller = new ServiceInstaller()
|
||||
{
|
||||
Context = context,
|
||||
DisplayName = "Remotely Service",
|
||||
Description = "Background service that maintains a connection to the Remotely server. The service is used for remote support and maintenance by this computer's administrators.",
|
||||
ServiceName = "Remotely_Service",
|
||||
StartType = ServiceStartMode.Automatic,
|
||||
Parent = new ServiceProcessInstaller()
|
||||
};
|
||||
|
||||
var state = new System.Collections.Specialized.ListDictionary();
|
||||
serviceInstaller.Install(state);
|
||||
Logger.Write("Service installed.");
|
||||
serv = ServiceController.GetServices().FirstOrDefault(ser => ser.ServiceName == "Remotely_Service");
|
||||
|
||||
ProcessEx.StartHidden("cmd.exe", "/c sc.exe failure \"Remotely_Service\" reset= 5 actions= restart/5000");
|
||||
}
|
||||
if (serv.Status != ServiceControllerStatus.Running)
|
||||
{
|
||||
serv.Start();
|
||||
}
|
||||
Logger.Write("Service started.");
|
||||
}
|
||||
|
||||
private void RestoreBackup()
|
||||
{
|
||||
try
|
||||
{
|
||||
var backupPath = Path.Combine(Path.GetTempPath(), "Remotely_Backup.zip");
|
||||
if (FileIO.Exists(backupPath))
|
||||
{
|
||||
Logger.Write("Restoring backup.");
|
||||
ClearInstallDirectory();
|
||||
ZipFile.ExtractToDirectory(backupPath, _installPath);
|
||||
var serv = ServiceController.GetServices().FirstOrDefault(ser => ser.ServiceName == "Remotely_Service");
|
||||
if (serv?.Status != ServiceControllerStatus.Running)
|
||||
{
|
||||
serv?.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task StopProcesses()
|
||||
{
|
||||
ProgressMessageChanged?.Invoke(this, "Stopping Remotely processes.");
|
||||
var procs = Process.GetProcessesByName("Remotely_Agent").Concat(Process.GetProcessesByName("Remotely_Desktop"));
|
||||
|
||||
foreach (var proc in procs)
|
||||
{
|
||||
proc.Kill();
|
||||
}
|
||||
|
||||
await Task.Delay(500);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,39 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
using System;
|
||||
using System.Windows.Input;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Services;
|
||||
|
||||
public class RelayCommand : ICommand
|
||||
{
|
||||
private readonly Action<object> _action;
|
||||
|
||||
private readonly Predicate<object>? _canExecute;
|
||||
|
||||
public RelayCommand(Action<object> action, Predicate<object>? canExecute = null)
|
||||
{
|
||||
_action = action;
|
||||
_canExecute = canExecute;
|
||||
}
|
||||
|
||||
public event EventHandler CanExecuteChanged
|
||||
{
|
||||
add { CommandManager.RequerySuggested += value; }
|
||||
remove { CommandManager.RequerySuggested -= value; }
|
||||
}
|
||||
|
||||
public bool CanExecute(object parameter)
|
||||
{
|
||||
if (_canExecute is null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return _canExecute.Invoke(parameter);
|
||||
}
|
||||
|
||||
public void Execute(object parameter)
|
||||
{
|
||||
_action?.Invoke(parameter);
|
||||
}
|
||||
}
|
||||
@ -1,78 +0,0 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Utilities;
|
||||
|
||||
public class CommandLineParser
|
||||
{
|
||||
private static Dictionary<string, string>? commandLineArgs;
|
||||
|
||||
private static bool _invalidArgumentFound;
|
||||
|
||||
public static Dictionary<string, string> CommandLineArgs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (commandLineArgs is null)
|
||||
{
|
||||
commandLineArgs = new Dictionary<string, string>();
|
||||
|
||||
var args = Environment.GetCommandLineArgs();
|
||||
|
||||
for (var i = 1; i < args.Length; i += 2)
|
||||
{
|
||||
try
|
||||
{
|
||||
var key = args[i];
|
||||
if (key != null)
|
||||
{
|
||||
if (!key.Contains("-"))
|
||||
{
|
||||
_invalidArgumentFound = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
internal static void VerifyArguments()
|
||||
{
|
||||
if (_invalidArgumentFound)
|
||||
{
|
||||
Logger.Write("Command line arguments are invalid.");
|
||||
MessageBoxEx.Show("Command line arguments are invalid.", "Invalid Arguments", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,82 +0,0 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Utilities;
|
||||
|
||||
public class Logger
|
||||
{
|
||||
public static string LogsDir { get; } = Directory.CreateDirectory(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Remotely", "Logs")).FullName;
|
||||
public static string LogsPath { get; } = Path.Combine(LogsDir, "Installer.log");
|
||||
|
||||
private static readonly object _writeLock = new object();
|
||||
|
||||
public static void Debug(string message)
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
#if DEBUG
|
||||
CheckLogFileExists();
|
||||
|
||||
File.AppendAllText(LogsPath, $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t[Debug]\t{message}{Environment.NewLine}");
|
||||
|
||||
#endif
|
||||
System.Diagnostics.Debug.WriteLine(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void Write(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
CheckLogFileExists();
|
||||
File.AppendAllText(LogsPath, $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t[Info]\t{message}{Environment.NewLine}");
|
||||
Console.WriteLine(message);
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
public static void Write(Exception ex)
|
||||
{
|
||||
lock (_writeLock)
|
||||
{
|
||||
try
|
||||
{
|
||||
CheckLogFileExists();
|
||||
|
||||
var exception = ex;
|
||||
|
||||
while (exception != null)
|
||||
{
|
||||
File.AppendAllText(LogsPath, $"{DateTimeOffset.Now:yyyy-MM-dd HH:mm:ss.fff}\t[Error]\t{exception.Message}\t{exception.StackTrace}\t{exception.Source}{Environment.NewLine}");
|
||||
Console.WriteLine(exception.Message);
|
||||
exception = exception.InnerException;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
}
|
||||
|
||||
private static void CheckLogFileExists()
|
||||
{
|
||||
if (!File.Exists(LogsPath))
|
||||
{
|
||||
File.Create(LogsPath).Close();
|
||||
}
|
||||
|
||||
if (File.Exists(LogsPath))
|
||||
{
|
||||
var fi = new FileInfo(LogsPath);
|
||||
while (fi.Length > 1000000)
|
||||
{
|
||||
var content = File.ReadAllLines(LogsPath);
|
||||
File.WriteAllLines(LogsPath, content.Skip(10));
|
||||
fi = new FileInfo(LogsPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,15 +0,0 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Utilities;
|
||||
|
||||
public static class MessageBoxEx
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.Utilities;
|
||||
|
||||
public static class ProcessEx
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -1,512 +0,0 @@
|
||||
#nullable enable
|
||||
using Remotely.Agent.Installer.Win.Models;
|
||||
using Remotely.Agent.Installer.Win.Services;
|
||||
using Remotely.Agent.Installer.Win.Utilities;
|
||||
using Remotely.Shared.Models;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Principal;
|
||||
using System.ServiceProcess;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Script.Serialization;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Net;
|
||||
using Remotely.Shared;
|
||||
using Remotely.Agent.Installer.Models;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.ViewModels;
|
||||
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
{
|
||||
private readonly EmbeddedServerDataReader _embeddedDataReader;
|
||||
private readonly InstallerService _installer;
|
||||
private BrandingInfo? _brandingInfo;
|
||||
private bool _createSupportShortcut;
|
||||
private string _headerMessage = "Install the service.";
|
||||
private bool _isReadyState = true;
|
||||
private bool _isServiceInstalled;
|
||||
|
||||
private string? _organizationID;
|
||||
|
||||
private int _progress;
|
||||
|
||||
private string _serverUrl = string.Empty;
|
||||
|
||||
private string? _statusMessage;
|
||||
|
||||
public MainWindowViewModel()
|
||||
{
|
||||
_installer = new InstallerService();
|
||||
_embeddedDataReader = new EmbeddedServerDataReader();
|
||||
|
||||
CopyCommandLineArgs();
|
||||
|
||||
ExtractEmbeddedServerData().Wait();
|
||||
|
||||
AddExistingConnectionInfo();
|
||||
}
|
||||
|
||||
public bool CreateSupportShortcut
|
||||
{
|
||||
get
|
||||
{
|
||||
return _createSupportShortcut;
|
||||
}
|
||||
set
|
||||
{
|
||||
_createSupportShortcut = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string HeaderMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _headerMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_headerMessage = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public BitmapImage? Icon { get; set; }
|
||||
public string InstallButtonText => IsServiceMissing ? "Install" : "Reinstall";
|
||||
|
||||
public ICommand InstallCommand => new RelayCommand(async (param) => { await Install(); });
|
||||
|
||||
public bool IsProgressVisible => Progress > 0;
|
||||
|
||||
public bool IsReadyState
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isReadyState;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isReadyState = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsServiceInstalled
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isServiceInstalled;
|
||||
}
|
||||
set
|
||||
{
|
||||
_isServiceInstalled = value;
|
||||
FirePropertyChanged();
|
||||
FirePropertyChanged(nameof(IsServiceMissing));
|
||||
FirePropertyChanged(nameof(InstallButtonText));
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsServiceMissing => !_isServiceInstalled;
|
||||
|
||||
public ICommand OpenLogsCommand
|
||||
{
|
||||
get
|
||||
{
|
||||
return new RelayCommand(param =>
|
||||
{
|
||||
|
||||
if (Directory.Exists(Logger.LogsDir))
|
||||
{
|
||||
Process.Start(Logger.LogsDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBoxEx.Show("Log directory doesn't exist.", "No Logs", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public string? OrganizationID
|
||||
{
|
||||
get
|
||||
{
|
||||
return _organizationID;
|
||||
}
|
||||
set
|
||||
{
|
||||
_organizationID = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string ProductName { get; set; } = "Remotely";
|
||||
|
||||
public int Progress
|
||||
{
|
||||
get
|
||||
{
|
||||
return _progress;
|
||||
}
|
||||
set
|
||||
{
|
||||
_progress = value;
|
||||
FirePropertyChanged();
|
||||
FirePropertyChanged(nameof(IsProgressVisible));
|
||||
}
|
||||
}
|
||||
|
||||
public string ServerUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
return _serverUrl;
|
||||
}
|
||||
set
|
||||
{
|
||||
_serverUrl = value?.TrimEnd('/') ?? string.Empty;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string? StatusMessage
|
||||
{
|
||||
get
|
||||
{
|
||||
return _statusMessage;
|
||||
}
|
||||
set
|
||||
{
|
||||
_statusMessage = value;
|
||||
FirePropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand UninstallCommand => new RelayCommand(async (param) => { await Uninstall(); });
|
||||
private string? DeviceAlias { get; set; }
|
||||
private string? DeviceGroup { get; set; }
|
||||
private string? DeviceUuid { get; set; }
|
||||
|
||||
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 (IsServiceMissing)
|
||||
{
|
||||
HeaderMessage = $"Install the {ProductName} service.";
|
||||
}
|
||||
else
|
||||
{
|
||||
HeaderMessage = $"Modify the {ProductName} installation.";
|
||||
}
|
||||
|
||||
CommandLineParser.VerifyArguments();
|
||||
|
||||
if (CommandLineParser.CommandLineArgs.ContainsKey("install"))
|
||||
{
|
||||
await Install();
|
||||
}
|
||||
else if (CommandLineParser.CommandLineArgs.ContainsKey("uninstall"))
|
||||
{
|
||||
await Uninstall();
|
||||
}
|
||||
|
||||
if (CommandLineParser.CommandLineArgs.ContainsKey("quiet"))
|
||||
{
|
||||
App.Current.Shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private void AddExistingConnectionInfo()
|
||||
{
|
||||
try
|
||||
{
|
||||
var connectionInfoPath = Path.Combine(
|
||||
Path.GetPathRoot(Environment.SystemDirectory),
|
||||
"Program Files",
|
||||
"Remotely",
|
||||
"ConnectionInfo.json");
|
||||
|
||||
if (File.Exists(connectionInfoPath))
|
||||
{
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var connectionInfo = serializer.Deserialize<ConnectionInfo>(File.ReadAllText(connectionInfoPath));
|
||||
|
||||
if (string.IsNullOrWhiteSpace(OrganizationID))
|
||||
{
|
||||
OrganizationID = connectionInfo.OrganizationID;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ServerUrl))
|
||||
{
|
||||
ServerUrl = connectionInfo.Host ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void ApplyBranding(BrandingInfo? brandingInfo)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (brandingInfo is not null &&
|
||||
!string.IsNullOrWhiteSpace(brandingInfo.Product))
|
||||
{
|
||||
ProductName = brandingInfo.Product;
|
||||
}
|
||||
|
||||
Icon = GetBitmapImageIcon(brandingInfo);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private bool CheckIsAdministrator()
|
||||
{
|
||||
var identity = WindowsIdentity.GetCurrent();
|
||||
var principal = new WindowsPrincipal(identity);
|
||||
var result = principal.IsInRole(WindowsBuiltInRole.Administrator);
|
||||
if (!result)
|
||||
{
|
||||
MessageBoxEx.Show("Elevated privileges are required. Please restart the installer using 'Run as administrator'.", "Elevation Required", MessageBoxButton.OK, MessageBoxImage.Warning);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private bool CheckParams()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(OrganizationID) || string.IsNullOrWhiteSpace(ServerUrl))
|
||||
{
|
||||
Logger.Write("ServerUrl or OrganizationID param is missing. Unable to install.");
|
||||
MessageBoxEx.Show("Required settings are missing. Please enter a server URL and organization ID.", "Invalid Input", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Guid.TryParse(OrganizationID, out _))
|
||||
{
|
||||
Logger.Write("OrganizationID is not a valid GUID.");
|
||||
MessageBoxEx.Show("Organization ID must be a valid GUID.", "Invalid Organization ID", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Uri.TryCreate(ServerUrl, UriKind.Absolute, out var serverUri) ||
|
||||
(serverUri.Scheme != Uri.UriSchemeHttp && serverUri.Scheme != Uri.UriSchemeHttps))
|
||||
{
|
||||
Logger.Write("ServerUrl is not valid.");
|
||||
MessageBoxEx.Show("Server URL must be a valid Uri (e.g. https://app.example.com).", "Invalid Server URL", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void CopyCommandLineArgs()
|
||||
{
|
||||
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 (CommandLineParser.CommandLineArgs.TryGetValue("deviceuuid", out var deviceUuid))
|
||||
{
|
||||
DeviceUuid = deviceUuid;
|
||||
}
|
||||
|
||||
if (CommandLineParser.CommandLineArgs.ContainsKey("supportshortcut"))
|
||||
{
|
||||
CreateSupportShortcut = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ExtractEmbeddedServerData()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
var filePath = Process.GetCurrentProcess()?.MainModule?.FileName;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
Logger.Write("Failed to retrieve executing file name.");
|
||||
return;
|
||||
}
|
||||
|
||||
var embeddedData = await _embeddedDataReader.TryGetEmbeddedData(filePath!);
|
||||
|
||||
if (embeddedData is null || embeddedData == EmbeddedServerData.Empty)
|
||||
{
|
||||
Logger.Write("Embedded server data is empty. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (embeddedData.ServerUrl is null)
|
||||
{
|
||||
Logger.Write("ServerUrl is empty. Aborting.");
|
||||
return;
|
||||
}
|
||||
|
||||
OrganizationID = embeddedData.OrganizationId;
|
||||
ServerUrl = embeddedData.ServerUrl.AbsoluteUri;
|
||||
|
||||
using (var httpClient = new HttpClient())
|
||||
{
|
||||
var serializer = new JavaScriptSerializer();
|
||||
var brandingUrl = $"{ServerUrl.TrimEnd('/')}/api/branding/{OrganizationID}";
|
||||
using (var response = await httpClient.GetAsync(brandingUrl).ConfigureAwait(false))
|
||||
{
|
||||
var responseString = await response.Content.ReadAsStringAsync();
|
||||
_brandingInfo = serializer.Deserialize<BrandingInfo>(responseString);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
ApplyBranding(_brandingInfo);
|
||||
}
|
||||
}
|
||||
private BitmapImage GetBitmapImageIcon(BrandingInfo? bi)
|
||||
{
|
||||
Stream imageStream;
|
||||
if (bi is not null &&
|
||||
!string.IsNullOrWhiteSpace(bi.Icon))
|
||||
{
|
||||
imageStream = new MemoryStream(Convert.FromBase64String(bi.Icon));
|
||||
}
|
||||
else
|
||||
{
|
||||
imageStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Remotely.Agent.Installer.Win.Assets.Remotely_Icon.png");
|
||||
}
|
||||
|
||||
var bitmap = new BitmapImage();
|
||||
bitmap.BeginInit();
|
||||
bitmap.StreamSource = imageStream;
|
||||
bitmap.CacheOption = BitmapCacheOption.OnLoad;
|
||||
bitmap.EndInit();
|
||||
bitmap.Freeze();
|
||||
imageStream.Close();
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
private async Task Install()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsReadyState = false;
|
||||
if (!CheckParams())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
HeaderMessage = "Installing Remotely...";
|
||||
|
||||
if (await _installer.Install(
|
||||
ServerUrl,
|
||||
OrganizationID!,
|
||||
DeviceGroup,
|
||||
DeviceAlias,
|
||||
DeviceUuid,
|
||||
CreateSupportShortcut))
|
||||
{
|
||||
IsServiceInstalled = true;
|
||||
Progress = 0;
|
||||
HeaderMessage = "Installation completed.";
|
||||
StatusMessage = "Remotely has been installed. You can now close this window.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Progress = 0;
|
||||
HeaderMessage = "An error occurred during installation.";
|
||||
StatusMessage = "There was an error during installation. Check the logs for details.";
|
||||
}
|
||||
if (!CheckIsAdministrator())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsReadyState = true;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task Uninstall()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsReadyState = false;
|
||||
|
||||
HeaderMessage = "Uninstalling Remotely...";
|
||||
|
||||
if (await _installer.Uninstall())
|
||||
{
|
||||
IsServiceInstalled = false;
|
||||
Progress = 0;
|
||||
HeaderMessage = "Uninstall completed.";
|
||||
StatusMessage = "Remotely has been uninstalled. You can now close this window.";
|
||||
}
|
||||
else
|
||||
{
|
||||
Progress = 0;
|
||||
HeaderMessage = "An error occurred during uninstall.";
|
||||
StatusMessage = "There was an error during uninstall. Check the logs for details.";
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Write(ex);
|
||||
}
|
||||
finally
|
||||
{
|
||||
IsReadyState = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
#nullable enable
|
||||
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Remotely.Agent.Installer.Win.ViewModels;
|
||||
|
||||
public class ViewModelBase : INotifyPropertyChanged
|
||||
{
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
public void FirePropertyChanged([CallerMemberName]string propertyName = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
@ -1,76 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||
<security>
|
||||
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<!-- UAC Manifest Options
|
||||
If you want to change the Windows User Account Control level replace the
|
||||
requestedExecutionLevel node with one of the following.
|
||||
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
|
||||
|
||||
Specifying requestedExecutionLevel element will disable file and registry virtualization.
|
||||
Remove this element if your application requires this virtualization for backwards
|
||||
compatibility.
|
||||
-->
|
||||
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- A list of the Windows versions that this application has been tested on
|
||||
and is designed to work with. Uncomment the appropriate elements
|
||||
and Windows will automatically select the most compatible environment. -->
|
||||
|
||||
<!-- Windows Vista -->
|
||||
<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />
|
||||
|
||||
<!-- Windows 7 -->
|
||||
<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />
|
||||
|
||||
<!-- Windows 8 -->
|
||||
<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />
|
||||
|
||||
<!-- Windows 8.1 -->
|
||||
<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />
|
||||
|
||||
<!-- Windows 10 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||
|
||||
</application>
|
||||
</compatibility>
|
||||
|
||||
<!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
|
||||
DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need
|
||||
to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should
|
||||
also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. -->
|
||||
<!--
|
||||
<application xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<windowsSettings>
|
||||
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
|
||||
</windowsSettings>
|
||||
</application>
|
||||
-->
|
||||
|
||||
<!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
|
||||
<!--
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
</assembly>
|
||||
14
Remotely.sln
14
Remotely.sln
@ -31,8 +31,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Linux", "Desktop.Li
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Desktop.Win", "Desktop.Win\Desktop.Win.csproj", "{6B726FC4-A907-4813-BF38-3342E02AA8D2}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Agent.Installer.Win", "Agent.Installer.Win\Agent.Installer.Win.csproj", "{A3D0368C-0850-4614-B5B5-41B9D5135AA9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Server.Tests", "Tests\Server.Tests\Server.Tests.csproj", "{48D9D0E6-5781-44A9-84C0-56F56C2A1193}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoadTester", "Tests\LoadTester\LoadTester.csproj", "{6C25240C-613D-4A86-A04E-784BA6726094}"
|
||||
@ -122,18 +120,6 @@ Global
|
||||
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x64.Build.0 = Release|x64
|
||||
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.ActiveCfg = Release|x86
|
||||
{6B726FC4-A907-4813-BF38-3342E02AA8D2}.Release|x86.Build.0 = Release|x86
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|x64.Build.0 = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|x64.ActiveCfg = Release|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|x64.Build.0 = Release|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A3D0368C-0850-4614-B5B5-41B9D5135AA9}.Release|x86.Build.0 = Release|Any CPU
|
||||
{48D9D0E6-5781-44A9-84C0-56F56C2A1193}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{48D9D0E6-5781-44A9-84C0-56F56C2A1193}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{48D9D0E6-5781-44A9-84C0-56F56C2A1193}.Debug|x64.ActiveCfg = Debug|x64
|
||||
|
||||
Loading…
Reference in New Issue
Block a user