Home > Net >  How can I get output of PowerShell Command Line to my Project?
How can I get output of PowerShell Command Line to my Project?

Time:11-01

I am trying to make an application to test certain functionality that I intend to add later to my main program, but without the risk of breaking my main program.

I'm new to Pascal, and I still don't understand how many things work.

The objective of this program is, through a PowerShell command executed in the same application, to obtain several JSON, each one from a specific directory to go through them and check certain things.

These things can be the presence of specific file extensions in certain directories, or the presence of a large volume of information in them.

Create 3 objects in Delphi for this application. A button to start the program, a Timer and a JvCreateProcess.

The interval property of the timer is 10 (ms). The onTimer property is the Timer1Timer method.

Timer1Timer code:

procedure TUProbando.Timer1Timer(Sender: TObject);
var
  Comando: TStrings;
  ValorJSON: TStrings;
begin
  if ContadorDirectorios = Length(rutas) then
  begin
    Timer1.Enabled := false;
    exit;
  end;

  Timer1.Enabled := false;
  Lista.Clear;
  // Separador para mejorar la visibilidad de los elementos de los directorios
  // a la hora de listarlos
  memo_Salida_Command_gci.Lines.Add('******* '   rutas[ContadorDirectorios]  
    ' *******');
  Comando := TStringList.Create;

  try
    // Abro Powershell
    Comando.Add('C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe "');
    // Comando.Add(comandoPowerShell);

    // Agrego la línea de comando siguiente para volcar el contenido del
    // directorio especificado en un JSON
    Comando.Add('"gci '   rutas[ContadorDirectorios]  
      ' -Recurse | ConvertTo-Json"');

    // JvCreateProcess1.Tag:= ;
    // Agrego la linea de comando al proceso
    JvCreateProcess1.CommandLine := Comando.Text;

    // Ejecuto el proceso
    JvCreateProcess1.run;
    ValorJSON := JvCreateProcess1.ConsoleOutput;

  finally
    begin
      Comando.Free;
    end;
  end;
end;

The rutas[] array is a String array containing the directories to check.

rutas: array [0 .. 2] of String = ('C:\Users\operario43\Desktop',
    'C:\Users\operario43\Documents', 'C:\Users\operario43\Pictures');

Now, JvCreateProcess1 code:

procedure TUProbando.JvCreateProcess1Terminate(Sender: TObject;
  ExitCode: Cardinal);
begin
  // Calculo el tamaño del directorio actual

// I WANT GET JSON OF PREVIOUS POWER SHELL COMMAND HERE
  SizeDirectory := GetSizeFromJson('JSON HERE', Extensiones);
  // el codigo llega aqui, tengo q sacar el json de alguna parte

  if checkSizeDirectory(SizeDirectory, SizeControlDirectory) then
  begin
    ShowMessage('El directorio '   rutas[ContadorDirectorios]  
      ' tiene archivos importantes que no estan protejidos por Backup');
  end;

  // incremento en 1 la posicion en el array de directorios
  // para que la siguiente vez que se ejecute el proceso tome la siguiente
  // posición
  inc(ContadorDirectorios);
end;

Other methods that I use:

function GetSizeFromJson(JSON: String; vExtensiones: array of string): integer;
var

  // Contenedor - Array que contiene los elementos del JSON de cada directorio
  Contenedor: TJSONArray;
  // Jfichero- Objeto JSON que individualiza cada elementos del JSON
  Jfichero: TJSONObject;
  // JNombre -Nombre del elemento correspondiente del Jfichero
  JNombre: TJSONValue;
  // JSizeFile - Valor del elemento 'lenght' de cada elemento del JSON
  JSizeFile: TJSONNumber; //

  // elemento de bucle for
  I: integer;
  // Tamaño de un directorio en Bytes
  SizeDirectory: Int64;
begin
  SizeDirectory := 0;
  result := -1;
  try
    Contenedor := TJSONObject.ParseJSONValue(JSON) as TJSONArray;
    // Controlamos el caso de que Contenedor sea null
    if Contenedor = nil then
    begin
      ShowMessage('Error al parsear el json'   JSON);
      exit;
    end;

    // Este for recorre el 'array' del JSON contabilizando cada elemento
    for I := 0 to Contenedor.Count - 1 do
    begin

      Jfichero := Contenedor.Items[I] as TJSONObject;
      if Jfichero <> nil then
      begin
        // Extraigo el nombre del elemento
        JNombre := Jfichero.GetValue('Name');

        // Si las extensiones de los archivos del directorio estan en
        // nuestro tracker de extensiones
        if MatchStr(ExtractFileExt(JNombre.Value), vExtensiones) then
        begin
          // Saco el valor del tamaño del elemento en Bytes
          JSizeFile := Jfichero.GetValue('Length') as TJSONNumber;

          if JSizeFile <> nil then
          begin

            // Incremento el contador de tamaño del directorio en una cantidad
            // igual al tamaño del elemento
            inc(SizeDirectory, JSizeFile.AsInt);
          end; // if JSizeFile <> nil
        end; // if MatchStr(ExtractFileExt(JNombre.Value), vExtensiones)
      end; // if Jfichero <> nil
    end; // for I := 0 to Contenedor.Count - 1

    // Devuelvo el valor de tamaño del directorio
    result := SizeDirectory;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;

// metodo para saber si el directorio en cuestion supera el tamaño de directorio
function checkSizeDirectory(vSizeDirectory, vSizeControlDirectory
  : Int64): Boolean;
var
  Contenedor: TJSONArray;
begin
  result := false;

  vSizeDirectory := GetSizeFromJson(Contenedor.ToString, Extensiones);

  if vSizeDirectory > vSizeControlDirectory then
  begin
    ShowMessage('El directorio '   rutas[ContadorDirectorios]  
      ' tiene archivos importantes que no estan protejidos por Backup');
  end;

end;

My question is, how do I get JSON for JvCreateProcess1Terminate method?.

I've made a lot of changes trying to get it to work, and made small pieces of code to make it more manageable.

CodePudding user response:

Just a note may be It helps someone.
You can save the output of any windows terminal command or application into a file. Just add " > FileName" after the ExeName or commandm then the output will saved to "FileName". I can use this from Delphi too. Suppose I want the output of a program called MyApp.exe to be saved to a file then I can use the following command:

Myprog := 'd:\MyApp.exe > FullOutputFileName';
r := ShellExecute(0, 'open', PChar(Myprog), nil, nil, SW_HIDE);
if r <> o then
  //Check for error
else
  //load the file FullOutputFileName and get results

When using some terminal internal commands like 'dir, ver, vol, ...' I create a batch file (FileName.bat) that contains the command or commands I want to execute then I use shellexecute to execute this file.

Notes:

  1. You can also use " >> FileName" to append the output to the end of the file.
  2. This method is slow so it is not advised to use it in loops.
  3. mORMot has a good and easy to use JSON implementation.

CodePudding user response:

Here comes a little piece of a Code-Snippet which you can use, to execute an DOS Application with the JVCreateProcess Component:

procedure TForm2.JvImgBtn6Click(Sender: TObject);
var
  path : String;
begin
  try
    path := ExtractFilePath(Application.ExeName);

    with JvCreateProcess1 do
    begin
      ApplicationName  := 'C:\windows\system32\cmd.exe';
      CurrentDirectory :=   path;
      CommandLine      := '/c '  
      path   'build.bat '   path;
      ShowMessage(ApplicationName   #13#10   CommandLine);
      Run;
    end;
  finally
  end;
end;

In this Code, I use the cmd.exe Parameter /C - this close the DOS Terminal Process Window after the execution of "build.bat" is finished.
If you would like to hold open the DOS-Terminal Window, use the /k Parameter.

The path variable before, and after the 'build.bat' stand for:
C:\path\to\build.bat C:\path\as\parameter

So, the build.bat can have the demonstrated content:

@echo off
set DEVPATH=%1
dir            
  • Related