Error: Subscript used with non-Array variable

  • Hey Leute,


    ich bin mal wieder auf eure Hilfe angewiesen!

    Ich habe vor längerer Zeit ein Skript geschrieben das alte Backups löschen
    sollte.

    Das klappt auch auf mehreren Server Problemlos, neuerdings bekomme ich
    allerdings auf einem Server die Fehlermeldung


    Error: Subscript used with non-Array variable

    [Blockierte Grafik: http://www.autoit.de/index.php?page=Attachment&attachmentID=16270&h=8c2a4ebd41f7b5474443172ff24435846b409ed0]


    Sowohl an dem Server als auch in dem Skript und der Ini habe ich nichts
    geändert.

    Die Dateien die vom Skript überprüft werden sollen liegen auch alle in den
    Ordnern in denen das Skript sie sucht.

    Ausgeführt wird das Skript als Administrator, daher sollte es auch genug Rechte
    haben (hat ja auch mehrere Wochen gelaufen).


    Hier der Quellcode:


    Spoiler anzeigen
    [autoit]

    #cs*****************************************
    ;Löschen_alter_Dateien.au3 by GorePriest
    ;Erstellt mit ISN AutoIt Studio v. 0.76 BETA#

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

    Löschen_alter_Backups - Version 0.1 Stand 26.01.2012
    - Das Script holt sich verschiedene Variablen aus einer Ini
    - Es Überprüft alle Dateien eines Bestimmten Types in einem Pfad auf Ihr alter
    - Wenn Eine Datei vom aktuellen Datum im Ordner liegt löscht es alle Dateien älter als X Tage
    - Eine Log Datei wird erstellt in der alle gelöschten Dateien stehen
    - Wenn keine Datei vom aktuellen Datum om Ordner liegt bricht das Script ab und schickt eine E-Mail Warnung

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

    Löschen_alter_Backups - Version 0.1.1 Stand 31.01.2012
    Neue Funktionen / Bugfixes
    - Überprüfung der aktuellsten Datei wurde verbessert
    - Falls keine Aktuelle Datei vorhanden ist werden jetzt alle Dateien die X Tage älter als die aktuellste Datei sind gelöscht
    - In Der Ini Datei kann jetzt angeben werden ob das Backup am Vorabend oder am selben Tag vor durchlauf des Script durchgeführt wird
    - Ein Debug modus wurde hinzugefügt

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

    Löschen_alter_Backups - Version 0.1.2 Stand 07.02.2012
    Neue Funktionen / Bugfixes
    - Es wird überprüft ob die .ini Datei am gewünschen Pfad existiert, Falls nicht wird sie erstellt und der User wird aufgefordert sie anzupassen.
    - Der Ort an dem die Logs abgelegt werden wir jetzt auch aus der ini ausgelesen auf die Art kann das Script einfacher an verschieden Server angepasst werden.
    #ce*****************************************

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

    #include <Array.au3>
    #include <Date.au3>
    #include <File.au3>
    #include <inet.au3>

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

    ;Überprüft ob die Ini Datei vorhanen ist, falls nicht wird eine Ini Datei mit Standard werden abgelegt und der User wird aufgefordert die Datei anzupassen.
    If FileExists(@ScriptDir & "\loeschen_alter_backups.ini") = 0 Then
    FileInstall("U:\Scripte\Projekte\Loeschen_alter_Dateien\loeschen_alter_backups.ini",@ScriptDir & "\loeschen_alter_backups.ini",0)
    MsgBox(0,"Bitte die Ini Datei Anpassen!", "Es wurde eine neue Ini Datei erstellt, bitte passen Sie die Werte nach Bedarf an!" & @CRLF & "Die Datei liegt unter " & @ScriptDir & @CRLF & "Sie heisst loeschen_alter_backups.ini" & @CRLF & "Führen Sie das Programm im Anschluss noch einmal aus.")
    Run(@ScriptDir & "\loeschen_alter_backups.ini")
    Exit
    EndIf
    ;Erstellen eines Zeitstempels
    const $Stamp = @YEAR & @MON & @MDAY

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

    ;Einlesen der Uhrzeit
    ;~ const $Time = @HOUR & @MIN & @SEC

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

    ;Ini Datei
    const $Iniverzeichnis = @ScriptDir
    const $IniName = "loeschen_alter_backups.ini"
    const $Ini = $Iniverzeichnis & "\" & $IniName

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

    ;Log Name
    const $LogName = "Log" & $Stamp & ".txt"

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

    ;Log Ordner
    const $LogOrdner =IniRead($Ini,"anzahl","LogOrdner","C:\Temp")

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

    ;Anzahl der druchläufe (wird aus einer Ini Datei ausgelesen)
    const $Anzahl =IniRead($Ini,"anzahl","anzahl","")

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

    ;Wenn DB = 1 werden MsgBoxen aktiv um den reibungslosen ablauf zu überprüfen (wird aus einer Ini Datei ausgelesen)
    const $DB =IniRead($Ini,"anzahl","DB","")

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

    ;Varialblen zum versenden einer E-Mail
    $Hostname = @ComputerName

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

    ; Adresse des Smtp Server der genutzt werden soll
    $SmtpServer = IniRead($Ini,"anzahl","SMTP_SVR","")

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

    ; Name das Absenders
    $FromName = $Hostname

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

    ; E-Mail Adresse die als Absender angezeigt wird
    $FromAddress = IniRead($Ini,"anzahl","S_Mail","")

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

    ; Text der E-Mail, wird in der Funktion zusammen gesetzt
    $Body= ""

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

    For $i = 1 To $Anzahl
    _Loeschen_alter_Backups()
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an wie oft das Programm durchlaufen wird",$i)

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

    Next

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

    Func _Loeschen_alter_Backups()

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

    ;Backup Ordner
    $ZielOrdner = IniRead($Ini,$i,"Pfad","")
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob der Zielodner richig ausgelesen wird",$ZielOrdner)

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

    ;Type der der Dateien
    $Type = IniRead($Ini,$i,"Type","")
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob der Datei Type richtig ausgelesen wird",$Type)

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

    ;Maximales alter der Dateien
    $LoeschDatum = IniRead($Ini,$i,"Alter","")
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob das Löschdatum richtig ausgelesen wird",$LoeschDatum)

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

    ;Name der zu überprüfenden Sicherung
    $Name = IniRead($Ini,$i,"Name","")
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob der Name richtig ausgelesen wird",$Name)

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

    ;E-Mail Adresse für Fehlermeldung
    $E_Mail = IniRead($Ini,$i,"E-Mail","technik@lis.eu")
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob die E-Mail Adresse richtig ausgelesen wird",$E_Mail)

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

    ;Wenn das Backup am Vortag läuft muss diese Variable in der Ini auf 1 gesetzt werden
    $Zeitraum_des_Backups = IniRead($Ini,$i,"Zeitraum_des_Backups",0)
    If $Zeitraum_des_Backups = "" Then $Zeitraum_des_Backups = 0
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an ob der Zeitraum der Backups richtig ausgelesen wird",$Zeitraum_des_Backups)

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

    ;Liest die Dateien in ein Array
    $fileList = _FileListToArray($ZielOrdner, $Type, 1)
    Dim $found[1]

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

    ;Das Array wird nach Namen Sortiert so das die Datei mit dem Neusten Zeitstempel an letzter Stellt steht
    _ArraySort($fileList,0)
    $test =_ArrayToString($fileList)
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an von welchem Datum die erste Datei im Ordner ist",$test)
    ;Die letzte Stelle des Arrays wird ermittelt
    $letzte_position = UBound($fileList)-1

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

    ;Das Datum der ersten und letzten Datei im Zielordner wird ermittelt
    $Datex = FileGetTime($ZielOrdner & "\" & $fileList[$letzte_position], 1, 0)
    $fDatex = StringFormat("%s/%s/%s %s:%s:%s", $Datex[0], $Datex[1], $Datex[2], $Datex[3], $Datex[4], $Datex[5])
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an von welchem Datum die letzte Datei im Ordner ist",$fDatex)
    $Date1 = FileGetTime($ZielOrdner & "\" & $fileList[1], 1, 0)
    $fDate1 = StringFormat("%s/%s/%s %s:%s:%s", $Date1[0], $Date1[1], $Date1[2], $Date1[3], $Date1[4], $Date1[5])
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an von welchem Datum die erste Datei im Ordner ist",$fDate1)
    ;Es wird überprüft welche Datei aktueller ist
    If $Fdatex > $fDate1 Then
    $fDate_N = $Fdatex
    Else
    $fDate_N = $fDate1
    If $DB = 1 Then MsgBox(1,"Dieses Fenster zeigt an von welchem Datum die neuste Datei ist",$fDate_N)
    EndIf
    ;Es wird überprüft ob die aktuellste Datei zu dem Backupzeitraum passt
    If _DateDiff('d', $fDate_N, _NowCalc()) > $Zeitraum_des_Backups Then ;Falls die Dateien älter sind als sie sein sollten werden alle Dateien die X Tage älter sind als die neuste gelöscht und es wird eine E-Mail Verschickt
    For $X = 1 To $fileList[0]
    ;Ermitteln des Erstellungsdatums der Dateien
    $Date = FileGetTime($ZielOrdner & "\" & $fileList[$X], 1, 0)
    ;Datum Formatieren um es mit der UDF "Date.au3" abgleichen zu können
    $fDate = StringFormat("%s/%s/%s %s:%s:%s", $Date[0], $Date[1], $Date[2], $Date[3], $Date[4], $Date[5])
    ;Berechnung des Alters, Löschen von Dateien älter als X Tage
    If _DateDiff('d', $fDate, $fDate_N) > $LoeschDatum Then
    FileDelete($ZielOrdner & "\" & $fileList[$X])
    _ArrayAdd($found, $ZielOrdner & $fileList[$X])
    If $DB = 1 Then MsgBox(1, "Files deleted:", $fileList[$X], 1)
    EndIf
    $found[0] = UBound($found)
    Next
    $ToAddress = $E_Mail ; Zieladresse der E-Mail
    $Subject = "Im Ordner " & $ZielOrdner &" ist keine aktuelle " & $Name & "!! Dringed Pruefen!!!"; subject from the email - can be anything you want it to be
    $rc = _INetSmtpMail($SmtpServer, $FromName, $FromAddress, $ToAddress, $Subject, $Body, @computername, -1)
    If $DB = 1 Then MsgBox(1,"Mail verschickt wurde verschickt an",$E_Mail)
    Return
    Else
    For $X = 1 To $fileList[0];Überprüfen der Dateien
    ;Ermitteln des Erstellungsdatums der Dateien
    $Date = FileGetTime($ZielOrdner & "\" & $fileList[$X], 1, 0)
    ;Datum Formatieren um es mit der UDF "Date.au3" abgleichen zu können
    $fDate = StringFormat("%s/%s/%s %s:%s:%s", $Date[0], $Date[1], $Date[2], $Date[3], $Date[4], $Date[5])
    ;Berechnung des Alters, Löschen von Dateien älter als X Tage
    If _DateDiff('d', $fDate, _NowCalc()) > $LoeschDatum Then
    FileDelete($ZielOrdner & "\" & $fileList[$X])
    _ArrayAdd($found, $ZielOrdner & $fileList[$X])
    If $DB = 1 Then MsgBox(1, "Files deleted:", $fileList[$X], 1)
    EndIf
    $found[0] = UBound($found)
    Next
    EndIf

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

    ;Schreiben einer aktuellen überschrift in eine Log Datei, Falls die Logdatei noch nicht existiert wird sie jetzt erstellt.
    FileWriteLine($LogOrdner & $LogName,"######Diese " & $Type & " Dateien wurden am " & @MDAY & "." & @MON & "." & @YEAR & " um " & @HOUR & ":" & @MIN & " Uhr gelöscht!######")

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

    ;Falls keine Dateien gelöscht worden sind schreibt das Script dies in die Log Datei
    If $found[0] = 1 Then FileWriteLine($LogOrdner & $LogName,"Es Sind Keine Dateien aus dem Ordner < " & $ZielOrdner & " gelöscht worden!")

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

    ;Alle von Script gelöschten Dateien werden in eine Log Datei geschrieben
    For $Y = 1 To $found[0] -1
    FileWriteLine($LogOrdner & $LogName,$found[$Y])
    Next

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

    EndFunc

    [/autoit]


    Die Ini Datei sieht wie folgt aus:


    Spoiler anzeigen


    [anzahl]
    anzahl=4
    LogOrdner=D:\Sicherung\Skript\Log\
    DB=0
    SMTP_SVR=123.456.789.101
    S_Mail=test@test.test
    [1]
    Pfad=D:\Sicherung\DBXXXX\
    Type=*.PMP
    Alter=2
    Name=Oracle DBXXXX
    E-Mail=test2@test.test
    Zeitraum_des_Backups=1
    [2]
    Pfad=D:\Sicherung\DBYYYY\
    Type=*.PMP
    Alter=2
    Name=Oracle DBYYYY
    E-Mail=test2@test.test
    Zeitraum_des_Backups=1
    [3]
    Pfad=D:\Sicherung\Skript\Log\
    Type=*.txt
    Alter=14
    Name=Log Files
    E-Mail=test2@test.test
    Zeitraum_des_Backups=1
    [4]
    Pfad=D:\oracle\backup\dbXXXX\archivelogs\
    Type=*.0001
    Alter=7
    Name=Archivlogs
    E-Mail=test2@test.test
    Zeitraum_des_Backups=1


    seltsamerweise werden ich Archivlogs (Ini Datei Punkt 4) gelöscht und die
    Logdatei wird auch erstellt.


    Hat jemand eine Idee woran das liegen kann?

    Das Betriebssystem des Servers ist Windows Server 2008 r2 Standard.
    Die Benutzerkontensteuerung ist aus.

    Vielen dank und grüße
    Priest

  • Du kannst folgendes tun, damit du die Zeile im Source Code findest:

    1)
    Kompiliere den Code mit folgendem Schalter:

    [autoit]


    #AutoIt3Wrapper_Run_Obfuscator=y
    #Obfuscator_Parameters=/so

    [/autoit]


    Es wird eine Datei DeinSkript_Obfuscated.au3 angelegt.


    2) entferne aus dieser Datei alle Zeilenumbrüche mit _


    3) Starte das neu kompilierte Skript auf dem Server.


    Wenn nun die Fehlermeldung mit der Zeilennummer erscheint, schaue in der DeinSkript_Obfuscated.au3 nach. Wenn die Zeile keinen Sinn macht, müsste sie "in der Nähe" sein.

    Gruß,
    UEZ

    Auch am Arsch geht ein Weg vorbei...

    ¯\_(ツ)_/¯

    2 Mal editiert, zuletzt von UEZ (29. August 2012 um 15:54)

  • Hab dein Script mal compiliert und ausgeführt, erhalte ebenfalls den Fehler.
    Bei mir liegt es daran, das er

    [autoit]

    $ZielOrdner = IniRead($Ini,$i,"Pfad","")

    [/autoit]


    auslesen will, im Standardfall "D:\Sicherung\DBXXXX\"
    Ich habe keine Festplatte D:, aber das gibt noch nicht die Fehlermeldung, sondern erst

    [autoit]

    $fileList = _FileListToArray($ZielOrdner, $Type, 1)

    [/autoit]


    Da Die Festplatte bzw. der Ordner nicht existiert, gibt _FileListToArray 0 zurück, kein Array.
    Hier fragst du aber den Inhalt eines Elements aus $filelist ab

    [autoit]

    $Datex = FileGetTime($ZielOrdner & "\" & $fileList[$letzte_position], 1, 0)

    [/autoit]


    Bei mir Fehler im kompilierten zustand 4554 :)

    Hoffe ich konnte helfen

  • Ich nehme an...der Fehler tritt mit einem der Includes aus...er hat ja nur <200 Zeilen


    Beim zusammenschmeißen des QUellcodes werden Includes vorangestellt ;)
    Wenn du nur 50 Zeilen Code hast, aber 20 Includes, kann ein Fehler bei dir im Script stecken, die compilierte Nachricht zeigt aber eine Fehlerzeile > 50 an ;)

  • Wie von TheLuBu bereits richtig erkannt gehst du fahrlässig mit Funktionen um die normalerweise zwar Arrays zurückgeben, im Fehlerfall allerdings nicht. Prüft man die Ergebnisse der Funktion nicht und verwendet die Ergebnis Variable blind weiter, als ob sie ein Array wäre kann es zum beschriebenen Programmabsturz kommen. Deswegen prüft man grundsätzlich auf die in der Funktion definierten Fehlerrückgabewerte, insbesondere wenn das Ergebnis weiterverwendet werden soll. Reagieren kann man hier dann auf diversen Arten. Da du vermutlich wissen willst warum und wann eine Teilfunktion einen Fehler zurückgibt solltest du die Makros @error und je nach Funktion auch @extended nutzen, welche Debug Möglichkeiten bestehen kannst du den betreffenden Hilfeeinträgen entnehmen. Wichtig sind jedenfalls entpsrechende if Bedingungen oder Schleifenabbrüche damit es im Fehlerfall nicht zum Absturz kommt. Außerdem Wichtig wäre es die Fehler auszugeben und möglichst viele releavante Informationen zu speichern. In deinem Fall solltest du neben den Fehlercodes auch den aktuellen Schleifendurchgang und evtl vorhergegangene Variabelninhalte in eine Logdatei schreiben, damit du nachvollziehen kannst warum es zum Fehler kam.

  • Vielen Dank für die Tipps und Hinweise ich werde Morgen / am Wochenende mal versuchen das Umzusetzen