public RemotePathMappings(
     RunspaceDetails runspaceDetails,
     RemoteFileManagerService remoteFileManager)
 {
     this.runspaceDetails   = runspaceDetails;
     this.remoteFileManager = remoteFileManager;
 }
        private void RegisterPSEditFunction(RunspaceDetails runspaceDetails)
        {
            if (runspaceDetails.Location == RunspaceLocation.Remote &&
                runspaceDetails.Context == RunspaceContext.Original)
            {
                try
                {
                    runspaceDetails.Runspace.Events.ReceivedEvents.PSEventReceived += HandlePSEventReceivedAsync;

                    PSCommand createCommand = new PSCommand();
                    createCommand
                    .AddScript(CreatePSEditFunctionScript)
                    .AddParameter("PSEditModule", PSEditModule);

                    if (runspaceDetails.Context == RunspaceContext.DebuggedRunspace)
                    {
                        this.powerShellContext.ExecuteCommandAsync(createCommand).Wait();
                    }
                    else
                    {
                        using (var powerShell = System.Management.Automation.PowerShell.Create())
                        {
                            powerShell.Runspace = runspaceDetails.Runspace;
                            powerShell.Commands = createCommand;
                            powerShell.Invoke();
                        }
                    }
                }
                catch (RemoteException e)
                {
                    this.logger.LogException("Could not create psedit function.", e);
                }
            }
        }
        private void RemovePSEditFunction(RunspaceDetails runspaceDetails)
        {
            if (runspaceDetails.Location == RunspaceLocation.Remote &&
                runspaceDetails.Context == RunspaceContext.Original)
            {
                try
                {
                    if (runspaceDetails.Runspace.Events != null)
                    {
                        runspaceDetails.Runspace.Events.ReceivedEvents.PSEventReceived -= HandlePSEventReceivedAsync;
                    }

                    if (runspaceDetails.Runspace.RunspaceStateInfo.State == RunspaceState.Opened)
                    {
                        using (var powerShell = System.Management.Automation.PowerShell.Create())
                        {
                            powerShell.Runspace = runspaceDetails.Runspace;
                            powerShell.Commands.AddScript(RemovePSEditFunctionScript);
                            powerShell.Invoke();
                        }
                    }
                }
                catch (Exception e) when(e is RemoteException || e is PSInvalidOperationException)
                {
                    this.logger.LogException("Could not remove psedit function.", e);
                }
            }
        }
        /// <summary>
        /// For a remote or local cache path, get the corresponding local or
        /// remote file path.
        /// </summary>
        /// <param name="filePath">
        /// The remote or local file path.
        /// </param>
        /// <param name="runspaceDetails">
        /// The runspace from which the remote file was fetched.
        /// </param>
        /// <returns>The mapped file path.</returns>
        public string GetMappedPath(
            string filePath,
            RunspaceDetails runspaceDetails)
        {
            RemotePathMappings remotePathMappings = this.GetPathMappings(runspaceDetails);

            return(remotePathMappings.GetMappedPath(filePath));
        }
        private RemotePathMappings GetPathMappings(RunspaceDetails runspaceDetails)
        {
            RemotePathMappings remotePathMappings = null;
            string             computerName       = runspaceDetails.SessionDetails.ComputerName;

            if (!this.filesPerComputer.TryGetValue(computerName, out remotePathMappings))
            {
                remotePathMappings = new RemotePathMappings(runspaceDetails, this);
                this.filesPerComputer.Add(computerName, remotePathMappings);
            }

            return(remotePathMappings);
        }
        /// <summary>
        /// Opens a remote file, fetching its contents if necessary.
        /// </summary>
        /// <param name="remoteFilePath">
        /// The remote file path to be opened.
        /// </param>
        /// <param name="runspaceDetails">
        /// The runspace from which where the remote file will be fetched.
        /// </param>
        /// <returns>
        /// The local file path where the remote file's contents have been stored.
        /// </returns>
        public async Task <string> FetchRemoteFileAsync(
            string remoteFilePath,
            RunspaceDetails runspaceDetails)
        {
            string localFilePath = null;

            if (!string.IsNullOrEmpty(remoteFilePath))
            {
                try
                {
                    RemotePathMappings pathMappings = this.GetPathMappings(runspaceDetails);
                    localFilePath = this.GetMappedPath(remoteFilePath, runspaceDetails);

                    if (!pathMappings.IsRemotePathOpened(remoteFilePath))
                    {
                        // Does the local file already exist?
                        if (!File.Exists(localFilePath))
                        {
                            // Load the file contents from the remote machine and create the buffer
                            PSCommand command = new PSCommand();
                            command.AddCommand("Microsoft.PowerShell.Management\\Get-Content");
                            command.AddParameter("Path", remoteFilePath);
                            command.AddParameter("Raw");
                            command.AddParameter("Encoding", "Byte");

                            byte[] fileContent =
                                (await this.powerShellContext.ExecuteCommandAsync <byte[]>(command, false, false).ConfigureAwait(false))
                                .FirstOrDefault();

                            if (fileContent != null)
                            {
                                this.StoreRemoteFile(localFilePath, fileContent, pathMappings);
                            }
                            else
                            {
                                this.logger.LogWarning(
                                    $"Could not load contents of remote file '{remoteFilePath}'");
                            }
                        }
                    }
                }
                catch (IOException e)
                {
                    this.logger.LogError(
                        $"Caught {e.GetType().Name} while attempting to get remote file at path '{remoteFilePath}'\r\n\r\n{e.ToString()}");
                }
            }

            return(localFilePath);
        }
        private string StoreRemoteFile(
            string remoteFilePath,
            byte[] fileContent,
            RunspaceDetails runspaceDetails)
        {
            RemotePathMappings pathMappings  = this.GetPathMappings(runspaceDetails);
            string             localFilePath = pathMappings.GetMappedPath(remoteFilePath);

            this.StoreRemoteFile(
                localFilePath,
                fileContent,
                pathMappings);

            return(localFilePath);
        }
        /// <summary>
        /// Creates a new instance of the DebuggerStoppedEventArgs class.
        /// </summary>
        /// <param name="originalEvent">The original DebuggerStopEventArgs instance from which this instance is based.</param>
        /// <param name="runspaceDetails">The RunspaceDetails of the runspace which raised this event.</param>
        /// <param name="localScriptPath">The local path of the remote script being debugged.</param>
        public DebuggerStoppedEventArgs(
            DebuggerStopEventArgs originalEvent,
            RunspaceDetails runspaceDetails,
            string localScriptPath)
        {
            Validate.IsNotNull(nameof(originalEvent), originalEvent);
            Validate.IsNotNull(nameof(runspaceDetails), runspaceDetails);

            if (!string.IsNullOrEmpty(localScriptPath))
            {
                this.ScriptPath       = localScriptPath;
                this.RemoteScriptPath = originalEvent.InvocationInfo.ScriptName;
            }
            else
            {
                this.ScriptPath = originalEvent.InvocationInfo.ScriptName;
            }

            this.OriginalEvent   = originalEvent;
            this.RunspaceDetails = runspaceDetails;
        }
        /// <summary>
        /// Creates a temporary file with the given name and contents
        /// corresponding to the specified runspace.
        /// </summary>
        /// <param name="fileName">
        /// The name of the file to be created under the session path.
        /// </param>
        /// <param name="fileContents">
        /// The contents of the file to be created.
        /// </param>
        /// <param name="runspaceDetails">
        /// The runspace for which the temporary file relates.
        /// </param>
        /// <returns>The full temporary path of the file if successful, null otherwise.</returns>
        public string CreateTemporaryFile(string fileName, string fileContents, RunspaceDetails runspaceDetails)
        {
            string temporaryFilePath = Path.Combine(this.processTempPath, fileName);

            try
            {
                File.WriteAllText(temporaryFilePath, fileContents);

                RemotePathMappings pathMappings = this.GetPathMappings(runspaceDetails);
                pathMappings.AddOpenedLocalPath(temporaryFilePath);
            }
            catch (IOException e)
            {
                this.logger.LogError(
                    $"Caught {e.GetType().Name} while attempting to write temporary file at path '{temporaryFilePath}'\r\n\r\n{e.ToString()}");

                temporaryFilePath = null;
            }

            return(temporaryFilePath);
        }
        public static DscBreakpointCapability CheckForCapability(
            RunspaceDetails runspaceDetails,
            PowerShellContext powerShellContext,
            ILogger logger)
        {
            DscBreakpointCapability capability = null;

            // DSC support is enabled only for Windows PowerShell.
            if ((runspaceDetails.PowerShellVersion.Version.Major < 6) &&
                (runspaceDetails.Context != RunspaceContext.DebuggedRunspace))
            {
                using (PowerShell powerShell = PowerShell.Create())
                {
                    powerShell.Runspace = runspaceDetails.Runspace;

                    // Attempt to import the updated DSC module
                    powerShell.AddCommand("Import-Module");
                    powerShell.AddArgument(@"C:\Program Files\DesiredStateConfiguration\1.0.0.0\Modules\PSDesiredStateConfiguration\PSDesiredStateConfiguration.psd1");
                    powerShell.AddParameter("PassThru");
                    powerShell.AddParameter("ErrorAction", "Ignore");

                    PSObject moduleInfo = null;

                    try
                    {
                        moduleInfo = powerShell.Invoke().FirstOrDefault();
                    }
                    catch (CmdletInvocationException e)
                    {
                        logger.WriteException("Could not load the DSC module!", e);
                    }

                    if (moduleInfo != null)
                    {
                        logger.Write(LogLevel.Verbose, "Side-by-side DSC module found, gathering DSC resource paths...");

                        // The module was loaded, add the breakpoint capability
                        capability = new DscBreakpointCapability();
                        runspaceDetails.AddCapability(capability);

                        powerShell.Commands.Clear();
                        powerShell.AddScript("Write-Host \"Gathering DSC resource paths, this may take a while...\"");
                        powerShell.Invoke();

                        // Get the list of DSC resource paths
                        powerShell.Commands.Clear();
                        powerShell.AddCommand("Get-DscResource");
                        powerShell.AddCommand("Select-Object");
                        powerShell.AddParameter("ExpandProperty", "ParentPath");

                        Collection <PSObject> resourcePaths = null;

                        try
                        {
                            resourcePaths = powerShell.Invoke();
                        }
                        catch (CmdletInvocationException e)
                        {
                            logger.WriteException("Get-DscResource failed!", e);
                        }

                        if (resourcePaths != null)
                        {
                            capability.dscResourceRootPaths =
                                resourcePaths
                                .Select(o => (string)o.BaseObject)
                                .ToArray();

                            logger.Write(LogLevel.Verbose, $"DSC resources found: {resourcePaths.Count}");
                        }
                        else
                        {
                            logger.Write(LogLevel.Verbose, $"No DSC resources found.");
                        }
                    }
                    else
                    {
                        logger.Write(LogLevel.Verbose, $"Side-by-side DSC module was not found.");
                    }
                }
            }

            return(capability);
        }
 /// <summary>
 /// Creates a new instance of the DebuggerStoppedEventArgs class.
 /// </summary>
 /// <param name="originalEvent">The original DebuggerStopEventArgs instance from which this instance is based.</param>
 /// <param name="runspaceDetails">The RunspaceDetails of the runspace which raised this event.</param>
 public DebuggerStoppedEventArgs(
     DebuggerStopEventArgs originalEvent,
     RunspaceDetails runspaceDetails)
     : this(originalEvent, runspaceDetails, null)
 {
 }