Recent

Author Topic: TAsyncProcess and Powershell  (Read 572 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: 14376
  • Sensorship 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.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

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