Einzelnen Beitrag anzeigen

DavidKlimas

Registriert seit: 24. Sep 2006
Ort: Arlon, Belgien
71 Beiträge
 
#1

CreateProcess mit Powershell

  Alt 10. Mai 2016, 14:00
Hallo zusammen,

ich hab jetzt einige Tage lang gegrübelt und muss noch doch mal fragen.

Ich habe verschiedene "advertised Shortcuts" in meinem Startmenu und möchte gern die Zieldatei wissen. Das GetPath von iShellLink gibt da leider nur einen falschen Link vom Windows Installer zurück aber es gibt eine Powershell Funktion die das richtige Resultat ausgibt (Siehe Link):

Code:
$lnk = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Adobe\Adobe Acrobat X Pro.lnk"
$WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer
$ShortcutTarget = $WindowsInstaller.GetType().InvokeMember("ShortcutTarget","GetProperty",$null,$WindowsInstaller,$lnk)
$StringData1 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,1)
$StringData3 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,3)
$WindowsInstaller.GetType().InvokeMember("ComponentPath","GetProperty",$null,$WindowsInstaller,@($StringData1,$StringData3))
Nun zum lustigen teil, das funktionniert super manuelle vom Powershell aber ich bekomme es nicht hin mit Delphi.

1. Ich habe versucht die Funktionen als Argument zu benutzen:

Delphi-Quellcode:
var
ArgumentString: WideString;
ArgumentString := '$lnk = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Adobe\Adobe Acrobat X Pro.lnk"' + ';' +
                  '$WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer' + ';' +
                  '$ShortcutTarget = $WindowsInstaller.GetType().InvokeMember("ShortcutTarget","GetProperty",$null,$WindowsInstaller,$lnk)' + ';' +
                  '$StringData1 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,1)' + ';' +
                  '$StringData3 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,3)' + ';' +
                  '$WindowsInstaller.GetType().InvokeMember("ComponentPath","GetProperty",$null,$WindowsInstaller,@($StringData1,$StringData3))';
Manuelle klappt das mit dem Semikolon super im Powershell aber wenn ich folgendes probiere, scheint das argument nicht vorständig durchgegeben zu werden (zu lang!)

CreateProcess(nil, PChar('Powershell.exe ' + ArgumentString), @Security, @Security, true, CREATE_NEW_CONSOLE, nil, PChar('C:\'), start, ProcessInfo); Wie gesagt, das klappt nicht, weil zu lang.


2. Hab es mal mit WriteFile und Pipes versucht

Delphi-Quellcode:
var
ArgumentString: WideString;
Security: TSecurityAttributes;
PipeRead, PipeWrite: THandle;
NewPipeIn, NewPipeOut: THandle;
Start: TStartupInfo;
ProcessInfo: TProcessInformation;
BytesWritten, BytesRead: DWord;
ResultString: String;
WasOk: Boolean;
Buffer: array[0..255] of AnsiChar;

Procedure Test
Begin
   with Security do
   begin
     nLength := SizeOf(Security);
     bInheritHandle := True;
     lpSecurityDescriptor := nil;
   end;
   CreatePipe(PipeRead, NewPipeOut, @Security, 0);
   CreatePipe(NewPipeIn, PipeWrite, @Security, 0);
   with start do
   begin
       FillChar(start, SizeOf(start), 0);
       cb := SizeOf(start);
       dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
       wShowWindow := SW_SHOW; //SW_HIDE;
       hStdInput := NewPipeIn;
       hStdOutput := NewPipeOut;
       hStdError := NewPipeOut;
     end;
   ArgumentString := '-NoExit'
   if CreateProcess(nil, PChar('Powershell.exe ' + ArgumentString), @Security, @Security, true, CREATE_NEW_CONSOLE, nil, PChar('C:\'), start, ProcessInfo) then
   Begin
      ArgumentString := '$lnk = "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Adobe\Adobe Acrobat X Pro.lnk"' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
      ArgumentString := '$WindowsInstaller = New-Object -ComObject WindowsInstaller.Installer' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
      ArgumentString := '$ShortcutTarget = $WindowsInstaller.GetType().InvokeMember("ShortcutTarget","GetProperty",$null,$WindowsInstaller,$lnk)' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
      ArgumentString := '$StringData1 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,1)' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
      ArgumentString := '$StringData3 = $ShortcutTarget.GetType().InvokeMember("StringData","GetProperty",$null,$ShortcutTarget,3)' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
      ArgumentString := '$WindowsInstaller.GetType().InvokeMember("ComponentPath","GetProperty",$null,$WindowsInstaller,@($StringData1,$StringData3))' + #13#10
      WriteFile(PipeWrite, ArgumentString[1], length(ArgumentString), BytesWritten, nil);
     
      ResultString := '';
      repeat
         WasOK := ReadFile(PipeRead, Buffer, 255, BytesRead, nil);
         if BytesRead > 0 then
         begin
            Buffer[BytesRead] := #0;
            ResultString := ResultString + Buffer;
         end;
      until not WasOK or (BytesRead = 0);
      WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
      CloseHandle(ProcessInfo.hThread);
      CloseHandle(ProcessInfo.hProcess);
   end;
   CloseHandle(PipeRead);
   CloseHandle(PipeWrite);
   CloseHandle(NewPipeIn);
   CloseHandle(NewPipeOut);
end;
Soweit, so gut. Nun hab ich leider weder Input in den PowerShell, noch hab ich ein Resultat mit ReadFile.

Könnt Ihr mir bitte helfen das die Procedure Funktionniert ?

Geändert von DavidKlimas (10. Mai 2016 um 14:17 Uhr) Grund: Link wurde nicht korrekt angezeigt
  Mit Zitat antworten Zitat