Posh-SSH icon indicating copy to clipboard operation
Posh-SSH copied to clipboard

The process cannot access the file .poshssh\hosts.json because it is being used by another process

Open okarpov opened this issue 2 years ago • 6 comments

When you run a lot of PowerShell objects concurrently which all use Posh-SSH to access different servers

` runThread = new Thread(() => { if (_stop) return; List<Thread> openThrs = new List<Thread>();

            foreach (var psslog in PSSLogs)
            {
                if (_stop) break;
                if (!cbOneByOne.Checked)
                {

                    filterByLog = string.Empty;
                    Thread ot = new Thread(() =>
                    {
                    if (_stop) return;

                        PowerShell ps = PowerShell.Create();


                    try
                    {




                        PSCommand cmd = ps.Commands.AddScript(
                  		scriptToRun.Script, true);

                            cmd.AddParameter("IP", psslog.Node.IP)
                            .AddParameter("Pass", psslog.Node.Password)
                            .AddParameter("Zip", binFile);

                            if (cbWithDataFile.Checked) {
                                cmd.AddParameter("DataZip", Path.GetFullPath($".\\GenerateData\\Data\\{psslog.Node.IP}.zip"));
                            }

                            cmd.AddParameter("ErrorAction", "Stop")
                            .AddParameter("Verbose");

                            ps.Runspace.SessionStateProxy.SetVariable("ErrorActionPreference", "stop");

                            psslog.Ps = ps;

                            ps.Streams.Error.DataAdded += Error_DataAdded;
                            ps.Streams.Verbose.DataAdded += Verbose_DataAdded;
                            ps.Streams.Progress.DataAdded += Progress_DataAdded;
                            ps.Streams.Warning.DataAdded += Warning_DataAdded;
                            ps.Streams.Information.DataAdded += Information_DataAdded;

                            ps.Streams.Error.EnumeratorNeverBlocks = true;
                            ps.Streams.Verbose.EnumeratorNeverBlocks = true;
                            ps.Streams.Progress.EnumeratorNeverBlocks = true;
                            ps.Streams.Debug.EnumeratorNeverBlocks = true;
                            ps.Streams.Information.EnumeratorNeverBlocks = true;
                            ps.Streams.Warning.EnumeratorNeverBlocks = true;

                            ps.Invoke(null, psslog.psObjects);
                        }
                        catch (Exception ex)
                        {

                        }
                        finally
                        {
                            ps.Streams.Error.DataAdded -= Error_DataAdded;
                            ps.Streams.Verbose.DataAdded -= Verbose_DataAdded;
                            ps.Streams.Progress.DataAdded -= Progress_DataAdded;
                            ps.Streams.Warning.DataAdded -= Warning_DataAdded;
                            ps.Streams.Information.DataAdded -= Information_DataAdded;

                            ps.Dispose();
                           
                        }
                    });
                    ot.Start();
                    openThrs.Add(ot);

                    while (PSSLogs.Where(w => w.Ps != null && w.Ps.Streams.Progress.Count>0 && !w.Ps.Streams.Progress.Any(a=>a.PercentComplete>=100)).Count() >= delayMS)
                    {
                        Thread.Sleep(1000);
                    }
                }
                else
                {
                    if (_stop) break;

                    PowerShell ps = PowerShell.Create();

                    try
                    {
                        ps.Commands.AddScript(
            			scriptToRun.Script, false);

                        ps.AddParameter("IP", psslog.Node.IP);
                        ps.AddParameter("Pass", psslog.Node.Password);
                        ps.AddParameter("Zip", binFile);
                        if (cbWithDataFile.Checked)
                        {
                            ps.AddParameter("DataZip", Path.GetFullPath($".\\GenerateData\\Data\\{psslog.Node.IP}.zip"));
                        }

                        ps.AddParameter("ErrorAction", "Stop");
                        ps.AddParameter("Verbose");

                        ps.Runspace.SessionStateProxy.SetVariable("ErrorActionPreference", "stop");


                        psslog.Ps = ps;

                        ps.Streams.Error.DataAdded += Error_DataAdded;
                        ps.Streams.Verbose.DataAdded += Verbose_DataAdded;
                        ps.Streams.Progress.DataAdded += Progress_DataAdded;
                        ps.Streams.Warning.DataAdded += Warning_DataAdded;
                        ps.Streams.Information.DataAdded += Information_DataAdded;

                        ps.Streams.Error.EnumeratorNeverBlocks = true;
                        ps.Streams.Verbose.EnumeratorNeverBlocks = true;
                        ps.Streams.Progress.EnumeratorNeverBlocks = true;
                        ps.Streams.Debug.EnumeratorNeverBlocks = true;
                        ps.Streams.Information.EnumeratorNeverBlocks = true;
                        ps.Streams.Warning.EnumeratorNeverBlocks = true;


                        ps.Invoke(null, psslog.psObjects);

                    }
                    catch (Exception ex)
                    {

                    }
                    finally
                    {
                        ps.Streams.Error.DataAdded -= Error_DataAdded;
                        ps.Streams.Verbose.DataAdded -= Verbose_DataAdded;
                        ps.Streams.Progress.DataAdded -= Progress_DataAdded;
                        ps.Streams.Warning.DataAdded -= Warning_DataAdded;
                        ps.Streams.Information.DataAdded -= Information_DataAdded;

				ps.Dispose();
                    }
                }
                Thread.Sleep(scriptToRun.Name == "Install" ? 3000 : 250);
            }
        });
        runThread.Start();`

System.Management.Automation.ActionPreferenceStopException: The running command stopped because the preference variable "ErrorActionPreference" or common parameter is set to Stop: The process cannot access the file 'C:\Users\user1\.poshssh\hosts.json' because it is being used by another process. at System.Management.Automation.Runspaces.PipelineBase.Invoke(IEnumerable input) at System.Management.Automation.PowerShell.Worker.ConstructPipelineAndDoWork(Runspace rs, Boolean performSyncInvoke) at System.Management.Automation.PowerShell.Worker.CreateRunspaceIfNeededAndDoWork(Runspace rsToUse, Boolean isSync) at System.Management.Automation.PowerShell.CoreInvokeHelper[TInput,TOutput](PSDataCollection1 input, PSDataCollection1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.CoreInvoke[TInput,TOutput](PSDataCollection1 input, PSDataCollection1 output, PSInvocationSettings settings) at System.Management.Automation.PowerShell.Invoke[T](IEnumerable input, IList`1 output) at Scripter.Form1.DownloadFile(PSSLog psslog) in E:\user1\Projects\Scripter\Form1.cs:line 906 at Scripter.Form1.<>c__DisplayClass26_1.<btnRun_Click>b__1() in E:\user1\Projects\Scripter\Form1.cs:line 480

okarpov avatar Oct 25 '22 22:10 okarpov

Need more context outside of pasting an error. The file seems locked is the only thing I can tell but no clue on what version of windows, what version of PS, version of module or how the command is being ran

darkoperator avatar Oct 25 '22 22:10 darkoperator

Seems it like a #457 problem.

Race condition still exists when writing concurrently because FileStream with Share.Read do not try to wait on fail.

I don't know if some work is needed or if a workaround is enough.

MVKozlov avatar Oct 26 '22 06:10 MVKozlov

@darkoperator simplified version of code added to the original post. ( I thought devs know how, when and why their module uses its own .poshssh\hosts.json file and thus it would be obviouse. )

okarpov avatar Oct 26 '22 06:10 okarpov

@okarpov, You, of course, also can look at issue above, the code of the module and draw conclusions :)

Hint: pre-populate hosts.json with keys before using it so it's never written to while your code is running. Or use one-time in memory key storage if you don't care about keys.

MVKozlov avatar Oct 26 '22 08:10 MVKozlov

As a dev it is the minimum I expect in a proper issue is to provide context with details on how to reproduce :)

darkoperator avatar Oct 26 '22 11:10 darkoperator

Not part of the current problem but something you might hit is this issue with the library https://github.com/sshnet/SSH.NET/pull/844 for a very long time there has been many issues in the library with threading that have not been resolved.

darkoperator avatar Oct 26 '22 13:10 darkoperator