_WinAPI_GetProcessCommandLine​() funktioniert scheinbar nicht mehr?

  • Hat vor einiger Zeit funktioniert, aber heute liefert _WinAPI_GetProcessCommandLine() nur noch bei ganz wenigen Prozessen den Inhalt der Commandline obwohl laut ProcExplorer fast überall Werte stehen.


    Problem: wir starten die Browser immer mit eigenen Profilen und müssen gelegentlich genau und nur die Fenster schließen, die mit diesen Profilen gestartet wurden - die anderen Chromes dürfen weiterlaufen. In der ProcessCommandLine steht dieses Profil laut ProcExplorer - wenn genutzt und wenn gefunden könnte ich den Prozess beenden.


    Gibt es eine neue Funktion oder einen Workaround?


    Test mit dem Script aus der Hilfe: das Ergebnis von _WinAPI_GetProcessCommandLine() über die kompletten Prozesse - Ergebnis: seitenweise leer, nur bei ganz wenigen Prozessen wird die CommandLine angezeigt. Bei einigen auch nur ein Teil der Commandline. Bei den leeren Zeilen kommt Error = 20 oder 40.


    • Offizieller Beitrag
    Zitat

    This function uses undocumented API functions and may stop working properly in future versions of Windows.

    Using this function for some processes may require full access rights. Use _WinAPI_AdjustTokenPrivileges()
    function to enable $SE_DEBUG_NAME privilege before calling this function.

    Undokumentierte Funktionen die möglicherweise in neueren Windowsversionen nicht mehr richtig funktionieren.

    Ich denke, das sagt Alles.


    Ansonsten ist der Verweis auf die Privilegien sicher zu beachten.

  • Die Privilegien werden im Beispiel-Script doch gesetzt, oder sehe ich das falsch?


    Leider sind die Fehler 20 und 40 nicht dokumentiert - das sind die angezeigten Fehler bei leeren Zeilen. Die abgeschnittene Zeile hat Error = 0.


    Mit dem "undocumented" gebe ich Dir natürlich Recht. Aber da die Funktion ja teilweise noch funktioniert, könnte sich "Yashied" die Sache vielleicht noch mal anschauen?

  • Leider sind die Fehler 20 und 40 nicht dokumentiert

    Um zu erfahren wieso eine _WinAPI-Funktion einen Fehler meldet, musst du _WinAPI_GetLastError() und _WinAPI_GetErrorMessage() verwenden... ich habe das hier mal eingebaut.

  • Hast Du das bei Dir mal laufen lassen? Bekommst Du auch so viele Fehler?

    Ja, und ja. Da scheint sich in der Tat etwas geändert zu haben... evtl. funktioniert es, wenn das Script als System-Process gestartet wird.


    Kompiliert und als Exe gestartet mit "Als Administrator ausführen" bringt übrigens auch wieder andere Ergebnisse...

  • Habe schon bei VBS nachgeschaut, soll damit einfach möglich sein und das könnte man ja dann von AutoIt aus aufrufen. Aber ich verstehe trotzdem nicht, wie es funktioniert.

    • Offizieller Beitrag

    Versuchs mal mit WMI:

    Code
    WMIC path win32_process get Caption,Processid,Commandline

    Kannst du auch in AutoIt mit WMI Objekt ausführen. Habe nur gerade keinen PC zur Hand.


    Ausgabe in Datei geht auch:

    Code
    WMIC /OUTPUT:C:\Process.txt path win32_process get Caption,Processid,Commandline
  • WMIC path win32_process get Processid,Commandline |find "22788" > c:\temp\proxess4.txt

    Der WMIC-Befehl funktioniert in CMD . Im Ergebnis kommen dabei allerdings 5 Zeilen raus, einmal die gesuchte Commandline und die PID, danach aber noch eine Leerzeile, eine Zeile in der das FIND und die PID stehen und weitere 2.



    Und mein kurzes Script funktioniert auch nicht - habe noch nie den Output eines Run()-Befehls weiterverarbeitet:

    Optimal wäre natürlich die Rückgabe nur der zu $iPIDSearch gehörenden Commandline oder umgedreht, falls mehrfach vorkommend, Ausgabe aller PIDs, in deren Commandline $sSearch vorkommt in einem Array (noch komfortabler).

    Vielen Dank für die Unterstützung - und das am Feiertag!

  • Das sieht schon etwas anders aus...

  • Nö, falscher Fehler. Mit $sOutput = StdoutRead($iPID) hat es nicht funktioniert und dann kam ein Test, den ich nicht vollständig zurückgenommen habe: im Run noch >c:\temp\process.txt eingefügt um zu sehen, ob das Run() überhaupt was produziert - die Datei war leer. Also ist das Run() schon nicht ok. Den Output würde ich ja vielleicht in die Variable bekommen, aber wenn nichts da ist?

    Daher: an den ""; liegt es nicht, sondern an meinem Unwissen insgesamt ;)

  • Das sieht schon etwas anders aus...

    Das funktioniert tatsächlich, aber dauert und das Admin-Fenster ist nicht so gut bei den einfachen Usern. Wenn ich mich auf Chrome beschränke, geht es schneller aber das Admin-Problem bleibt.


    Code
            For $i = 1 To UBound($aList) -1
                If $aList[$i][0] = "chrome.exe" Then
                    $aList[$i][2] = _Proc($aList[$i][0])
                    If StringInStr($aList[$i][2],"Profile") Then ConsoleWrite('PID: ' & $aList[$i][1] & @TAB & $aList[$i][2] & @CRLF)
                EndIf
            Next

    Hast Du eine Idee, was bei meinem Run() falsch ist?

  • Dank Deinem Tipp mit wmic habe ich eine eine Lösung gefunden, die das nicht mehr vollständig funktionierende _WinApi_GetProcessCommandline() umgeht. Funktioniert nach ersten Tests auch ohne Admin-Rechte und kann sicher für alle möglichen Zwecke umgestaltet werden.


    Ausgabe:


    Um die aus unerfindlichen Gründen entstehenden leeren Einträge am Ende des Arrays zu entfernen, habe ich _ArrayClear() geschrieben. Da gibt es aber sicher eine bessere direkte Funktion in AutoIt? Wäre nett, wenn Du mein Script ein wenig optimieren könntest.

    • Offizieller Beitrag

    Die schnellste Lösung ist meist PowerShell, so auch hier. Und die Ausgabe ist komplett.

    Wichtig: Unbedingt Format-Table mit Out-String Cmdlet kombinieren, sonst wird die Zeile abgeschnitten.

  • Die schnellste Lösung ist meist PowerShell, so auch hier. Und die Ausgabe ist komplett.

    Danke an beide! Jetzt habe ich endlich ein Beispiel, wie ich PowerShell in AutoIt nutzen kann, aber mit meinem Script hole ich mir schon die gesuchten PIDs in ein Array mit dem ich die betreffenden Prozesse beenden kann. Ich suche tatsächlich nicht chrome an sich, sondern die chromes, die ein bestimmtes Profil nutzen ($sSearch = "chrome_wd_profil"). Und wmic ist auch schnell (von wmic hatte ich noch nie etwas gehört) ;)

    Aber jetzt brauche ich noch einen Tipp, ob es eine AutoIt-Funktion gibt, die die letzten Elemente oder alle Elemente, die leer sind, aus einer Tabelle löscht oder ob man es nur in der Art wie mein _ArrayClear() machen kann.

    • Offizieller Beitrag
    Zitat

    Aber jetzt brauche ich noch einen Tipp, ob es eine AutoIt-Funktion gibt, die die letzten Elemente oder alle Elemente, die leer sind, aus einer Tabelle löscht oder ob man es nur in der Art wie mein _ArrayClear() machen kann.

    Wenn es die letzten Elemente sind und die Anzahl der nicht-leeren Elemente bekannt ist, kannst du mit ReDim das Array verkleinern.

  • Alles in einem Rutsch...

    AutoIt
    ;~ Example: 'WMIC path win32_process WHERE ' & "Name='notepad.exe' AND CommandLine like '%%' " & 'CALL terminate' ; ohne Parameter
    ;~ Example: 'WMIC path win32_process WHERE ' & "Name='notepad.exe' AND CommandLine like '%AMD.txt%' " & 'CALL terminate' ; mit Parameter
    
    Local $sName = 'chrome.exe', $sCommandLine = '%chrome_wd_profil%'
    Local $sCMD = StringFormat('WMIC path win32_process WHERE "Name=%s AND CommandLine LIKE %s" CALL terminate', "'" & $sName & "'", "'" & $sCommandLine & "'")
    ConsoleWrite("@@_Debug_line" & @TAB & @TAB & @ScriptLineNumber & "   var: $sCMD --> " & $sCMD & @LF)
    
    Run($sCMD, '', @SW_HIDE) ; --> WMIC path win32_process WHERE "Name='chrome.exe' AND CommandLine LIKE '%chrome_wd_profil%'" CALL terminate


    Hast Du eine Idee, was bei meinem Run() falsch ist?

    Der Suchstring für Find muss in Quote stehen!

    $iPID = Run(@ComSpec & ' /c ' & 'WMIC path win32_process get Processid,Commandline |find "' & $iPIDSearch & '"')

  • Der Suchstring für Find muss in Quote stehen!

    $iPID = Run(@ComSpec & ' /c ' & 'WMIC path win32_process get Processid,Commandline |find "' & $iPIDSearch & '"')

    Den Suchstring hatte ich im Script in #14 weiter oben schon korrigiert, läuft ja einwandfrei jetzt. Aber was macht das "call terminate" bei Dir?

    Und wmic path und wmic process sind gleich?

  • Den Suchstring hatte ich im Script in #14 weiter oben schon korrigiert, läuft ja einwandfrei jetzt.

    Quatsch, das ist so, als ob du Äpfel mit Birnen vergleichst... in Post #9 verwendest du in dem Run() den Befehl Find, in Post #14 machst du es ganz anders - ohne Find.

    Aber was macht das "call terminate" bei Dir?

    Dasselbe wie bei dir: Hiermit werden alle Prozesse, die dem Suchmuster entsprechen, terminiert (gekillt).

    Und wmic path und wmic process sind gleich?

    Hä?

    Code
    C:\Users\ghost>wmic path /?
    
    Wechselt zu vollständigen WMI-Objektpfaden.
    SYNTAX:
    
    PATH (<Pfadausdruck> | (<Klassenpfadausdruck> [WHERE <WHERE-Klausel>]))
    [<Verbklausel>]