Kompiliertes Script soll "sich selbst" löschen können.

  • Hi Leute,

    ich hätte gerne für mein Script eine Deinstallationsroutine. Ich habe einen "Programm entfernen" Button. Wenn der gedrückt wird, dann werden die ini, Tempfiles und schließlich das Programm selbst gelöscht.
    Auf der Suche nach einer "Script-löscht-sich-selbst-Anleitung" bin ich schnell fündig geworden.

    Da gibts ja die _SelfDelete udf, die schon in Scite ist.

    [autoit]

    Func _SelfDelete()
    Local $cmdfile
    FileDelete(@TempDir & "scratch.cmd")
    $cmdfile = ':loop' & @CRLF _
    & 'del "' & @ScriptFullPath & '"' & @CRLF _
    & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
    & 'del ' & @TempDir & 'scratch.cmd'
    FileWrite(@TempDir & "scratch.cmd", $cmdfile)
    Run(@TempDir & "scratch.cmd", @TempDir, @SW_HIDE)
    EndFunc

    [/autoit]


    Ich rufe die Funktion einfach in meiner Aufräumaktion auf. Das funktionierte wunderbar, bis ich das Script kompiliert habe. Als ich testweise versuchte das Programm zu entfernen, wurde nur die scratch.cmd erstellt, aber nicht ausgeführt bzw. löscht nicht erfolgreich ?(
    Nach ein paar Tests habe ich festgestellt, dass es nicht funktioniert, wenn die scratch.cmd vom laufenden Programm erstellt wird. Wohl aber klappt das löschen, wenn ich eine bestehende scratch.cmd nicht lösche, sondern ausführe.
    So prüfe ich jetzt immer bei Programmstart, ob die Datei besteht, wenn nicht wird sie erstellt..

    Das geht erst einmal, ist aber natürlich nicht so dolle. Wie geht ihr denn beim Programm entfernen vor? Woran könnte es liegen, dass es mit der Function nicht klappt?

    Ich habe schon eine Pause in die erste Zeile der cmd geschrieben, damit das Programm beim Löschversuch beendet ist.

    Grüße autoiter

    • Offizieller Beitrag

    Möglicherweise gibt es Probleme, weil in der Funktion die Backslashes nach dem Pfad fehlen. Probiere es mal so:

    Spoiler anzeigen
    [autoit]


    _SelfDelete()

    [/autoit] [autoit][/autoit] [autoit]

    Func _SelfDelete()
    Local $cmdfile
    FileDelete(@TempDir & "\scratch.cmd")
    $cmdfile = ':loop' & @CRLF _
    & 'del "' & @ScriptFullPath & '"' & @CRLF _
    & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
    & 'del ' & @TempDir & '\scratch.cmd'
    FileWrite(@TempDir & "\scratch.cmd", $cmdfile)
    Run(@TempDir & "\scratch.cmd", @TempDir, @SW_HIDE)
    EndFunc

    [/autoit]
  • Ach sorry, das habe ich beim Schreiben vergessen.

    Nein, das war das erste, was ich korrigiert habe. Lustigerweise ging es im Script sogar ohne die Backslashs.

    Dann habe ich noch den Del Parameter /F ausprobiert und einen timeout in die batch schreiben lassen.

    Das lief dann so: Programm führt batch aus, beendet sich, nach zehn Sekunden startete der erste Durchgang löschen. Hat aber alles nicht funktioniert.


    Funktioniert das denn bei anderen mit kompilierten exe Dateien?

    Grüße autoiter

  • Das Programm beendet sich nach einigen Augenblicken. Danach Passiert nichts weiter.

    Wenn ich dann manuell die scratch.cmd starte (anklicke), wird das Programm auch gelöscht. Es funktioniert wie gesagt auch, wenn die scratch.cmd nicht in der gleichen Sitzung geschrieben werden musste, sondern schon im Ordner ist und nur vom Programm ausgeführt werden muss..

    Also scheint das Programm die .cmd nicht sofort nach dem Schreiben, starten zu können. An dieser Stelle liegt das Problem. Ich habe aber keine Ahnung, was es zu ändern gilt :whistling:

    Also bei dir gehts Oscar?!? Könnte es an meinem System liegen? Ich nutze Win 8.1 x64.
    Das Script aus deinem vorletztem Eintrag funktioniert bei mir nur bei einem nicht kompiliertem Script. Genau das als Script kompiliert geht nicht.
    Wenn ich Zeile 5 lösche, dann klappt es bei der zweiten Ausführung:

    [autoit]

    FileDelete(@TempDir & "\scratch.cmd")

    [/autoit]

    Entspricht genau der Beobachtung mit meinem Programm.

    Grüße autoiter

  • Verdammt. eben habe ich das mal in virtuellen Maschinen mit Win 7 (x86 und x64) gestestet. Bei beiden Systemen klappt meine suicide.exe, in der nur der Code steht, wie du ihn auch hast, Oscar. Dort klappt das!
    Wahrscheinlich geht es da auch ohne den eingefügten Backslash.

    Könnte mir jemand mit Win 8.1 x64 den Gefallen tun das Script mal zu einer exe kompilieren, um zu sehen, ob diese bei Ausführung gelöscht wird? Das wäre sehr nett.

    [autoit]

    _SelfDelete()

    [/autoit][autoit][/autoit][autoit]

    Func _SelfDelete()
    Local $cmdfile
    FileDelete(@TempDir & "\scratch.cmd")
    $cmdfile = ':loop' & @CRLF _
    & 'del "' & @ScriptFullPath & '"' & @CRLF _
    & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
    & 'del ' & @TempDir & '\scratch.cmd'
    FileWrite(@TempDir & "\scratch.cmd", $cmdfile)
    Run(@TempDir & "\scratch.cmd", @TempDir, @SW_HIDE)
    EndFunc

    [/autoit]

    Grüße autoiter

  • Geht bei mir auch problemlos unter 8.1 Pro x64. Schalt mal deinen Virenscanner testweise ab und teste nochmal. Außerdem wäre zum Debuggen wohl ein Aufruf der Batch mit sichtbarem Fenster, also @SW_SHOW angebracht.

  • Jap, es ist mein Bitdefender Antivirus, der das Verhalten blockiert hat! Ich hatte ihn schon auf Spielmodus (mehr bietet er nicht an). Dabei blockiert er wohl alles, meldet es nur nicht mehr. (Macht eigentlich Sinn, ich hatte aber keine Ahnung). Nach dem Abschalten des Spielemodus hat er mir gemeldet, dass ein verdäschtiges Verhalten unterbunden wurde.

    Ich werde mal testen wie es ausschaut, wenn ich die cmd vom Programm erstellen und ein weiteres Script starte, das wiederum die scratch.cmd ausführt.

    Danke schonmal :thumbup:

    Grüße autoiter

  • Hier noch meine Rückmeldung.
    Mein Virenscanner ist recht hartnäckig. Es klappt bei mir nicht einmal, wenn ich die cmd per fileinstall mit dem Programm mitliefere. Daher erstelle ich jetzt nach dem Schreiben nur noch eine Verknüpfung auf dem Desktop um Verwirrungen zu vermeiden. Die muss der User selbst ausführen und Virenscanner bleiben sicher still.

    Spoiler anzeigen

    Func _SelfDelete()
    Local $cmdfile
    FileDelete(@TempDir & "\scratch.cmd")
    $cmdfile = ':loop' & @CRLF _
    & 'del "' & @ScriptFullPath & '"' & @CRLF _
    & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
    & 'del ' & @TempDir & '\scratch.ico' & @CRLF _
    & 'del ' & @DesktopDir & '\scratch.cmd.lnk' & @CRLF _
    & 'del ' & @TempDir & '\scratch.cmd'
    FileWrite(@TempDir & "\scratch.cmd", $cmdfile)
    FileCreateShortcut(@TempDir & "\scratch.cmd", @DesktopDir & "\scratch.cmd.lnk", @TempDir, "", "ScratchTest", @TempDir & "\scratch.ico")
    MsgBox(0, "ScratchTest", "Auf dem Desktop befindet sich nun ein Uninstaller. Führe diesen bitte aus.", 3)
    EndFunc

    Danke nochmal. :)

    Grüße autoiter

  • Man könnte den Aufruf der scratch.cmd evtl. auch über die Aufgabenplannung "programmieren". Einfach Datei wie gehabt erstellen, Task zum Aufruf erstellen, Programm beenden. Dadurch dürfte der Virenscanner nicht mehr so ohne weiteres einen Bezug zwischen der Erstellung der Batch und der Ausführung durch dein Programm erkennen. Am Ende der batch sollte dann evtl. noch code eingefügt werden um den Task wieder aus der Aufgabenplannung zu entfernen.

    Aber selbst wenn das mit Bitdefender so klappen sollte ist das natürlich keine Garantie, dass es immer so klappt. Jeder Virenscanner arbeitet anders, wenn es um die Verhaltensanalyse geht, da kann schon ein Update reichen um eine vorher funktionierende Methode ebenfalls zu blockieren.

    Einmal editiert, zuletzt von misterspeed (28. April 2014 um 10:13)

  • Aber selbst wenn das mit Bitdefender so klappen sollte ist das natürlich keine Garantie, dass es immer so klappt. Jeder Virenscanner arbeitet anders, wenn es um die Verhaltensanalyse geht, da kann schon ein Update reichen um eine vorher funktionierende Methode ebenfalls zu blockieren.

    Ja, das bleibt ein Problem. Hätte ich nicht den bitdefender, hätte ich dieses Problem nicht einmal bemerkt. Bei AVG und Antivir klappt es (momentan).

    Außerdem habe ich mich im Forum umgeschaut, wegen dem Taskmanager und da stand in einem Thread, dass der Weg, der dort beschrieben wird nur ab win7 vielleicht ab vista ginge. Ich denke mir, bei so vielen Problemen lohnt sich die Arbeit einfach nicht..

    Auf meine Weise ist es nicht elegant, aber ich habe wenigstens die Gewissheit, dass es funktioniert.

    Grüße autoiter

  • Auch unter XP konnte man Tasks erstellen/planen. Siehe hier: http://en.wikipedia.org/wiki/At_%28Windows%29

    Laut wikipedia ist der Nachfolger von "at" die "schtasks.exe", allerdings gibt es die angeblich nicht unter XP Home und Starter. AT sollte aber auf allen Windows Plattformen funktionieren. Besonders aufwendig ist das auch nicht, du brauchst nur 2 Zeilen, die eine im Autoitscript um den Task anzulegen, die andere in der Batch um ihn wieder zu löschen.

  • Du könntest prüfen, ob die Exe noch läuft und sie dann beenden:

    [autoit]


    _SelfDelete(@AutoItPID)

    [/autoit][autoit][/autoit][autoit]

    MsgBox(0, "Test", "Test")

    [/autoit][autoit][/autoit][autoit]

    Func _SelfDelete($iPID)
    Local $cmdfile
    FileDelete(@TempDir & "\scratch.cmd")
    $cmdfile = ':loop' & @CRLF _
    & 'ping localhost >NUL' & @CRLF _
    & 'taskkill /pid "' & $iPID & '"' & @CRLF _
    & 'del "' & @ScriptFullPath & '"' & @CRLF _
    & 'if exist "' & @ScriptFullPath & '" goto loop' & @CRLF _
    & 'del ' & @TempDir & '\scratch.cmd'
    FileWrite(@TempDir & "\scratch.cmd", $cmdfile)
    Run(@TempDir & "\scratch.cmd", @TempDir, @SW_HIDE)
    EndFunc

    [/autoit]

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

  • Danke für eure Ratschläge :thumbup:

    UEZ
    Genau das hatte ich schon probiert. Allerdings wird die batch gar nicht gestartet, wenn der bitdefender läuft. In der Richtung brauche ich also nicht weiter forschen. :(

    Spoiler anzeigen

    :blub
    tasklist | findstr /i programm.exe > 0
    if %errorlevel%==0 goto :blub
    ...

    @gmmg
    Klar, das könnte ich tun. Ich würde mir für mich aber gar nicht die Mühe machen, sondern wollte das Programm weitergeben. Ist zwar ein absolut randständiges Ding, und wahrscheinlich auch nicht die Mühe wert, aber interessant ist es doch.

    Ich habe mir auch gedacht, ich könnte immer prüfen, ob die scratch.cmd schon da ist, wenn nicht, sollte sie ins Temp schreiben. Dann wäre das direkte deinstallieren immer möglich, wenn die Datei nicht gerade erstellt wurde. Wenn sie gerade erstellt wurde, dann würde ich nur einen Link zur scratch.cmd erstellen, mit der das Programm gelöscht werden könnte..

    Aber das ist natürlich keinesfalls perfekt. Deshalb muss ich erst einmal dem Vorschlag von misterspeed nachgehen. Weil ich an anderen Sachen weitergemacht habe, konnte ich nicht nach den AT tasks schauen. Das schaue ich mir aber noch an.

    Grüße autoiter

  • Die Lösung mir dem AT allein scheidet aus.. Wenn ich bei meinem Win8.1 eingebe:

    Code
    at 18:18 call "C:\Users\User\AppData\Local\Temp\scratch.cmd", dann erhalte ich die Meldung:
    
    
    Der AT-Befehl ist veraltet. Verwenden Sie stattdessen "schtasks.exe".
    Die Anforderung wird nicht unterstützt.


    Also könnte ich aber beides schreiben einen für AT und einen schtasks.exe. Allerdings lohnt sich das nur, wenn man auch einen Task für die aktuelle Minute machen kann. AT unterstützt nur h:min. Und bis zu 59 Sekunden auf das löschen zu warten, ist schlechter als eine Uninstaller Verknüpfung.
    Ich probiere das noch aus. Aber nicht sofort. Ich muss erst einmal eine XP Maschine erstellen..

    Aber wahrscheinlich ist das alles Quatsch. Es ist wohl ein guter Kompromiss, das System abzufragen und entweder einen Task mit schtasks.exe zu erstellen oder eine Verknüpfung zu erstellen, wenn XP im Einsatz ist. Gibt es eh nicht mehr lange ;)

    Grüße autoiter