Recent

Author Topic: TAsyncProcess and Powershell  (Read 1339 times)

HomeBoy38

  • Jr. Member
  • **
  • Posts: 59
TAsyncProcess and Powershell
« on: February 22, 2024, 12:04:07 pm »
Hello,

I have an issue with my code and I cannot figure out what is the issue, certainly something I do not do correctly...

I have a (visual component) TAsyncProcess called PZ with [poNoConsole, poStderrToOutPut, poUsePipes].
The TAsyncProcess has 'OnReadData' event.

Code: Pascal  [Select][+][-]
  1. var
  2.  s : String;
  3.  SLO: TStringList;
  4.  
  5. begin
  6. PZ.Executable := 'C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe';
  7. PZ.Tag := 1; // Process is running
  8. SLO.Clear;
  9. s := 'Enter-PSSession ' + CompName + LineEnding; // CompName is the computer name and LineEnding is CRLF
  10. PZ.Input.Write(s[1], Length(s));
  11. while PZ.Tag <> 0 do
  12.   Application.HandleMessage;
  13. ...
  14.  s := 'Invoke-Command {Get-WmiObject Powershell Command}' + LineEnding;
  15.  PZ.Tag := 1;
  16.  PZ.Input.Write(s[1], Length(s));
  17.  while PZ.Tag <> 0 do
  18.   Application.HandleMessage;
  19. ...
  20.  

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.PZReadData(Sender: TObject);
  2. var
  3.  J: Integer;
  4.  SLOtmp: TStringList;
  5. begin
  6.  J := 0;
  7.  SLOtmp := TStringList.Create;
  8.  SLOtmp.LoadFromStream(PZ.Output);
  9.  
  10.  if J < SLOtmp.Count then
  11.  begin
  12.   for J := J to SLOtmp.Count - 1 do
  13.    SLO.Add(SLOtmp.Strings[J]);
  14.  end;
  15.  
  16.  if SLOtmp.Count > 0 then
  17.  begin
  18.   if ((Copy(SLOtmp.Strings[SLOtmp.Count - 1], 1, 3) = 'PS ') and (Copy(SLOtmp.Strings[SLOtmp.Count - 1], Length(SLOtmp.Strings[SLOtmp.Count - 1]) - 1, 1) = '>')) or
  19.      ((Copy(SLOtmp.Strings[SLOtmp.Count - 1], 1, Length(FSettings.ECompName.Text) + 7) = '[' + FSettings.ECompName.Text + ']: PS ') and (Copy(SLOtmp.Strings[SLOtmp.Count - 1], Length(SLOtmp.Strings[SLOtmp.Count - 1]) - 1, 1) = '>')) then
  20.    PZ.Tag := 0;
  21.  end;
  22.  
  23.  if Assigned(SLOtmp) then SLOtmp.Free;
  24. end;
  25.  

The goal is to enter the remote powershell of another computer and get the result of each command I should run.
I previously used remote WMI commands (wmic.exe) but it is getting obsolete, I then used remote PowerShell commands (Get-CimInstance -computername) which are running correctly.
The PZReadData is something I found (maybe on this forum), I only added the prompt detection to exit.

The issue :
The issue is, according to me, related to my PZReadData procedure. The procedure works 99% of the time, but when it fails, I may be falling in my while loop. What I can say, is that the PowerShell commands are sometimes returning an unexpected result (missing result, broken format result and something I am not able to catch that fails my procedure).

I tried to log everything, I tried to put some timeouts, to workaround the issue, but each time it fails, I loop and the workaround is not working, so clearly, I am not handling the process correctly.

One workaround I found is the LazPwshJP64.dll in the topic,58276.0.html but I would like to understand what I am doing wrong and what I should do right, avoid using this additionnal DLL, avoid a blackbox dll I use blindly without understanding it.

Thanks

Thaddy

  • Hero Member
  • *****
  • Posts: 16200
  • Censorship about opinions does not belong here.
Re: TAsyncProcess and Powershell
« Reply #1 on: February 22, 2024, 04:47:50 pm »
This is again an example that the stream source needs to be flushed before you can read that stream.
If I smell bad code it usually is bad code and that includes my own code.

HomeBoy38

  • Jr. Member
  • **
  • Posts: 59
Re: TAsyncProcess and Powershell
« Reply #2 on: February 22, 2024, 06:21:01 pm »
ok, I got the idea but can you tell me what/where/how I should do it?
I have found threads saying it is not necessary, some say to "closeoutput" (but I am afraid I will hang on the next command), ... so I am a bit lost

Note:
I am currently testing this:
Code: Pascal  [Select][+][-]
  1. PZ.Tag := 1;
  2. PZ.Input.Write(s[1], Length(s));
  3. FileFlush(PZ.Output.Handle);        // Flush test
  4. while PZ.Tag <> 0 do
  5.  Application.HandleMessage;
  6.  
Nope, after a few hours, loop of the death, either the flush try is not what was suggested, either the truth is out there
« Last Edit: February 23, 2024, 09:00:46 am by HomeBoy38 »

 

TinyPortal © 2005-2018