/// <summary> /// Writes a value to the Windows registryKey. /// </summary> /// <typeparam name="T">The type of value that is written (<see cref="RegistryReadValueCommand{T}"/>).</typeparam> /// <param name="command">The command to execute.</param> /// <param name="logger">The logger to use.</param> /// <returns>A response indicating success and the written value, or failure with error details.</returns> public IServiceCommandResponse ExecuteWrite <T>(RegistryWriteValueCommand <T> command, ILogger logger) { Param.VerifyNotNull(command, nameof(command)); Param.VerifyNotNull(logger, nameof(logger)); IServiceCommandResponse response; try { var registryHive = (RegistryHive)Enum.Parse(typeof(RegistryHive), command.BaseKey.ToString()); using (IWin32RegistryKey baseKey = _registry.OpenBaseKey(registryHive, RegistryView.Registry64)) using (IWin32RegistryKey subKey = baseKey.CreateSubKey(command.Key, writable: true)) { subKey.SetValue(command.ValueName, command.Value, TypeToRegistryValueKind(typeof(T))); response = ServiceCommandResponse.Create(command.CommandName, command.Value); } } catch (Exception e) { response = ServiceCommandResponse.CreateError( command.CommandName, ServiceErrorInfo.RegistryWriteError( RegistryPath.HiveToWin32Name(RegistryPath.BaseKeyToHive(command.BaseKey)), command.Key, command.ValueName, e)); logger.LogError(response.ErrorMessage); } return(response); }
//// =========================================================================================================== //// Methods //// =========================================================================================================== /// <summary> /// Reads a value from the Windows registryKey. /// </summary> /// <typeparam name="T">The type of value that is read (<see cref="RegistryReadValueCommand{T}"/>).</typeparam> /// <param name="command">The command to execute.</param> /// <param name="logger">The logger to use.</param> /// <returns>A response indicating success and the read value, or failure with error details.</returns> public IServiceCommandResponse ExecuteRead <T>(RegistryReadValueCommand <T> command, ILogger logger) { Param.VerifyNotNull(command, nameof(command)); Param.VerifyNotNull(logger, nameof(logger)); ServiceCommandResponse response; try { var registryHive = (RegistryHive)Enum.Parse(typeof(RegistryHive), command.BaseKey.ToString()); using (IWin32RegistryKey baseKey = _registry.OpenBaseKey(registryHive, RegistryView.Registry64)) using (IWin32RegistryKey subKey = baseKey.OpenSubKey(command.Key, writable: false)) { object value = subKey?.GetValue(command.ValueName, command.DefaultValue) ?? command.DefaultValue; response = ServiceCommandResponse.Create(command.CommandName, value); } } catch (Exception e) { response = ServiceCommandResponse.CreateError( command.CommandName, ServiceErrorInfo.RegistryReadError( RegistryPath.HiveToWin32Name(RegistryPath.BaseKeyToHive(command.BaseKey)), command.Key, command.ValueName, e)); logger.LogError(response.ErrorMessage); } return(response); }
//// =========================================================================================================== //// Methods //// =========================================================================================================== public async Task <IServiceCommandResponse> SendCommandAsync(IServiceCommand command) { var valueSet = new ValueSet(); command.SerializeToValueSet(valueSet); AppServiceResponse bridgeResponse = await _connection.SendMessageAsync(valueSet); AppServiceResponseStatus status = bridgeResponse.Status; IServiceCommandResponse response; if (status == AppServiceResponseStatus.Success) { if (!ServiceCommandResponse.TryDeserializeFromValueSet( bridgeResponse.Message, out response, out IServiceCommandResponse errorResponse)) { response = errorResponse; } } else { response = ServiceCommandResponse.CreateError(command.CommandName, ServiceErrorInfo.InternalError($"AppServiceConnection failed with status '{status}'")); } return(response); }
public void CreateError_from_exception_should_store_the_properties() { var response = ServiceCommandResponse.CreateError( ServiceCommandName.RegistryReadIntValue, new InvalidOperationException()); response.CommandName.Should().Be(ServiceCommandName.RegistryReadIntValue); response.Result.Should().BeNull(); response.ErrorCode.Should().Be(ServiceCommandErrorCode.InternalError); response.ErrorMessage.Should().NotBeNull(); }
public void CreateError_should_store_the_properties() { var response = ServiceCommandResponse.CreateError( ServiceCommandName.RegistryReadIntValue, ServiceErrorInfo.InternalError("message")); response.CommandName.Should().Be(ServiceCommandName.RegistryReadIntValue); response.Result.Should().BeNull(); response.ErrorCode.Should().Be(ServiceCommandErrorCode.InternalError); response.ErrorMessage.Should().NotBeNull(); }
//// =========================================================================================================== //// Methods //// =========================================================================================================== public async Task <IServiceCommandResponse> SendCommandAsync(IServiceCommand command, ILogger logger) { // The path to the elevated app is a zero-byte executable EXE that facilitates the packaged app launch for // classic invokers – such as CMD or Process.Start. string localAppDataPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); string elevatedAppPath = Path.Combine( localAppDataPath, "microsoft", "windowsapps", "ElevatedDesktopServicesApp.exe"); string args = BuildArgs(command); var processStartInfo = new ProcessStartInfo { Arguments = args, FileName = elevatedAppPath, Verb = "runas", UseShellExecute = true }; int exitCode = 0; try { var elevatedProcess = Process.Start(processStartInfo); elevatedProcess?.WaitForExit(5000); exitCode = elevatedProcess?.ExitCode ?? 3; } catch (Exception e) { if (e.HResult == E_FAIL) { // the user cancelled the elevated process // by clicking "No" on the Windows elevation dialog exitCode = 1; } logger.LogError($"Error starting elevated process: {e}"); } ServiceCommandResponse response = exitCode == 0 ? ServiceCommandResponse.Create(command.CommandName, 0) : ServiceCommandResponse.CreateError( command.CommandName, new InvalidOperationException($"Error starting elevated process: {exitCode}")); return(await Task.FromResult(response)); }
public IServiceCommandResponse Execute(IServiceCommand command) { IServiceCommandResponse response; _logger.LogDebug("Executing command: ", command.ToDebugString()); switch (command) { case ShutdownServerCommand _: response = ServiceCommandResponse.Create(ServiceCommandName.ShutdownServer, true); break; case EchoCommand echoCommand: response = ServiceCommandResponse.Create(ServiceCommandName.Echo, echoCommand.EchoMessage); break; case RegistryReadIntValueCommand registryCommand: response = _registryExecutor.ExecuteRead(registryCommand, _logger); break; case RegistryReadStringValueCommand registryCommand: response = _registryExecutor.ExecuteRead(registryCommand, _logger); break; case RegistryWriteIntValueCommand registryCommand: response = _registryExecutor.ExecuteWrite(registryCommand, _logger); break; default: _logger.LogWarning("Unsupported command: ", command.CommandName); response = ServiceCommandResponse.CreateError( command.CommandName, ServiceErrorInfo.InternalError( $"Command '{command.CommandName}' is not supported for execution in the elevated bridge application.")); break; } return(response); }