Unterschied zwischen VBS Arrays und AutoIT Arrays

  • Hallo zusammen,

    mal wieder stehe ich vor einem Problem und brauche eure Unterstützung. Ich versuche gerade einige Funktionen aus dem SCCM SDK vom VBS ins AutoIT zu portieren. Bin dabei auf ein Problem gestoßen, welches ich mir erstmal nicht erklären kann und auch keine Lösung dafür finde. Dabei geht es um speichern von Objekten in einem Array und Übergabe des Arrays als Parameter an weitere Objekte. So, lange Rede kurzer Sinn, hier erstmal die beiden Funktionen

    1. Original VBS aus dem SDK

    2. Meine AutoIT Portierung

    [autoit]


    Func AddTaskSequenceGroup($oConnection, $oTaskSequence, $sName, $sDescription)

    Local $oGroup
    Local $aSteps[1]
    Local $aOperands[1]

    $oGroup = $oConnection.Get("SMS_TaskSequence_Group").SpawnInstance_()
    $oGroup.Name = $sName
    $oGroup.Description = $sDescription
    $oGroup.Enabled = True
    $oGroup.ContinueOnError = False

    $oCondition = $oConnection.Get("SMS_TaskSequence_Condition").SpawnInstance_()
    $oExpression = $oConnection.Get("SMS_TaskSequence_VariableConditionExpression").SpawnInstance_()
    $oExpression.Variable = "TESTVAR"
    $oExpression.Operator = "equals"
    $oExpression.Value = "1.0.0.0"

    ReDim $aOperands[UBound($oCondition.Operands)+1]
    $aOperands[UBound($oCondition.Operands)] = $oExpression
    $oCondition.Operands = $aOperands
    $oGroup.Condition = $oCondition

    ReDim $aSteps[UBound($oTaskSequence.Steps)+1]
    $aSteps[UBound($oTaskSequence.Steps)] = $oGroup
    $oTaskSequence.Steps = $aSteps
    EndFunc

    [/autoit]

    Als Ergebnis kommt beim Original eine Tasksequence mit einem Step, der Gruppe raus und diese hat eine Variable als Condition. So wie es sein soll. Bei meiner Variante kommt erstmal auch eine Tasksequence mit einem Step, der Gruppe raus, diese hat aber keine Condition. Ich habe stark die Vermutung das es an dieser Zuweisung liegt:

    Code
    operands=Array(oExpression)
    condition.Operands=operands


    Wenn ich mich nicht irre erzeut doch die erste Zeile ein eindimensionales Array mit einem Feld, welches den Index 0 hat. Diesem Feld wird gleichzeitig das Objekt oExpression zugewiesen. Rein theoretisch könnte man doch diese Zuweisung auch durch folgende ersetzen

    Code
    Dim operands(1)
    operands(0) = oExpression
    condition.Operands=operands


    Leider funktioniert dieses Beispiel nicht. Wenn ich die Zuweisung so modifiziere, bekomme ich beim Ausführen vom VBS folgende Fehlermeldung:
    Microsoft VBScript runtime error: Object doesn't support this property or method: 'operands'
    Dieser Code entspricht aber ziemlich genau dem AutoIT Code von oben (vereinfacht dargestellt):

    [autoit]


    Local $aOperands[1]
    $aOperands[0] = $oExpression
    $oCondition.Operands = $aOperands

    [/autoit]


    Was mich auch zu der Vermutung geführt hat, das es mit der Array Zuweisung zu tun hat. Die Frage ist ob man die VBS Zuweisung
    operands=Array(oExpression) irgendwie in AutoIT realisieren kann. Vielleich gibt es auch eine ganz andere Möglickeit. Evtl anstatt eines Arrays eine Collection oder eine ArrayList zu verwenden. Ich weiss aber nicht wie man sowas realisieren kann.

    Vielen Dank schon mal...
    Freue mich über eure Antworten

    Einmal editiert, zuletzt von edmann (10. März 2011 um 01:11)

  • Hallo BugFix,
    du bist doch ein Array Profi. Ist meine Annahme mit der Array Funktion richtig gewesen? Wird bei der Zuweisung

    Code
    operands=Array(oExpression)


    ein 1D Array erzeugt mit einem Feld, bei dem operands(0) das Objekt oExpression enthält oder kommt dabei was ganz anderes raus? Was mir nicht ganz einleuchtend ist, warum funktioniert die Zuweisung

    Code
    operands=Array(oExpression)


    aber nicht die

    Code
    operands(0)=oExpression


    obwohl das ja eigentlich gleich ist. Gibt es in AutoIT etwas vergleichbares zu der VBS Array Funktion?
    Die Idee mit den Collections ist mir auch schon gekommen, ich weiss aber nicht wie ich in AutoIT eine Collection erzeugen kann. Bis jetzt hatte ich mit Collections nur als Ergebnis irgend welcher Abfragen zu tun.

    • Offizieller Beitrag

    Mein Problem ist, dass ich keine Testmöglichkeit habe. Deine Funktion setzt ja als Parameter: (connection, taskSequence, name, description) voraus. Damit kann ich nicht dienen. Wozu dient sie eigentlich genau?
    Sieht mir nach Netzwerkadministration aus - nicht gerade mein Spezialgebiet.

    Edit:
    Hab mir nochmal den VBS-Code angeschaut.
    Also die Arrayerstellung passiert z.B. hier: operands=Array(oExpression)
    Die verwendete Syntax ist: Variable = Array( Argument_1, Argument_2, .., Argument_n)
    Es wird aber nur ein Argument übergeben, ein Objekt, das selbst ein Array darstellt.
    Und so geht es munter weiter:
    Das soeben erstellte Array wird als .Operands dem Objekt condition zugewiesen
    condition.Operands=operands
    Und dieses Objekt landet in der Eigenschaft .Condition des Objektes group
    group.Condition=condition

    Also ich sehe das so:
    - du hast eine Hand voll Bonbon (oExpression)
    - die steckst du in eine Tüte (operands)
    - dann hast du einen Schrank (condition) mit einem Fach in das du die operands steckst
    - und dieser Schrank landet in einem Raum (group) unter der Kategorie Möbel (Condition)

    Und ich weiß nicht, wie ich in AutoIt durch die Zimmertür in die Bonbontüte greifen soll. :D
    Ich vermute mal, dass sich das hier zu tief in Objekte vergräbt. Aber vielleicht kennt sich da jemand besser aus.

  • Die Funktion erzeugt eine Tasksequence in MS SCCM 2007. Mit nachstellen wird es schwierig, da hast du Recht. Da kann ich dir nur anbieten den Code hier zu posten, ich werde es dann in meine VM ausprobieren und das Ergebnis zurück posten. Ich denke das ist auch garnicht der springende Punkt, sondern warum gibt es einen Unterschied zwischen operands=Array(oExpression) und operands(0)=oExpression. Letzteres erzeugt sogar eine Fehlermeldung "Microsoft VBScript runtime error: Object doesn't support this property or method: 'operands'". Wobei mir diese Fehlermeldung auch ziemlich spanisch vorkommt. Normalerweise kommt sie nur dann wenn ich versuche eine Methode aufzurufen oder Propery zu setzen die es nicht gibt. Hier versuche ich aber in einem Arrayfeld ein Objekt abzuspeichern. Sehr seltsam. Ich habe im SDK ein C# Beispiel gefunden.

    Spoiler anzeigen


    public void AddRegistryCondition(
    WqlConnectionManager connection,
    IResultObject taskSequenceStep)
    {
    try
    {
    IResultObject condition;

    if (taskSequenceStep["Condition"].ObjectValue == null)
    {
    // Create a new condition.
    condition = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_Condition");
    }
    else
    { // Get the existing condition.
    condition = taskSequenceStep.GetSingleItem("Condition");
    }

    // Create and populate the expression.
    IResultObject registryExpression = connection.CreateEmbeddedObjectInstance("SMS_TaskSequence_RegistryConditionExpression");

    registryExpression["KeyPath"].StringValue = @"HKEY_LOCAL_MACHINE\MICROSOFT";
    registryExpression["Operator"].StringValue = "exists";
    registryExpression["Type"].StringValue = "REG_SZ";
    registryExpression["Data"].StringValue = null;

    // Get the operands and add the expression.
    List<IResultObject> operands = condition.GetArrayItems("Operands");
    operands.Add(registryExpression);

    // Add the expresssion to the list of operands.
    condition.SetArrayItems("Operands", operands);

    // Add the condition to the sequence.
    taskSequenceStep.SetSingleItem("Condition", condition);
    }
    catch (SmsException e)
    {
    Console.WriteLine("Failed to create Task Sequence: " + e.Message);
    throw;
    }
    }

    Hier wird es nicht mit einem Array sondern mit einem List Type gemacht

    Code
    List<IResultObject> operands = condition.GetArrayItems("Operands");
    operands.Add(registryExpression);
    condition.SetArrayItems("Operands", operands);


    Gibt es in AutoIT evtl eine Möglichkeit so etwas zu realisieren?

    • Offizieller Beitrag

    Gibt es in AutoIT evtl eine Möglichkeit so etwas zu realisieren?


    Also unabhängig ob Array oder Liste kannst du mit For-In (in VBS For-Each) die Werte durchgehen.
    operands = condition.GetArrayItems("Operands");
    erzeugt die Liste. An den Inhalt solltest du dann so kommen:

    [autoit]

    For $item In $operands
    ConsoleWrite($item & @CRLF)
    Next

    [/autoit]

    Auf diese Art und Weise kannst du natürlich dann die Werte in ein AutoIt-Array umschaufeln.
    Sind die Listenelemente aber selbst Objekte wird es wohl komplizierter, dann mußt du das mit IsObj() prüfen und ggf. wiederum mit For-In iterieren. Je nachdem, welche Properties das Objekt hat.

  • Problem gelöst. Hatte nichts mit dem Array zu tun, Das Array war OK. Die Übergabe an das Object hat nicht funktioniert

    [autoit]


    Local $aOperands[1]
    $aOperands[0] = $oExpression
    $oCondition.Operands = $aOperands
    $oGroup.Condition = $oCondition

    [/autoit]


    Problem war in der letzten Zuweisung. Diese habe ich wie folgt geändert

    [autoit]


    $oGroup.Properties_.Item("Condition") = $oCondition

    [/autoit]


    und schon hat es funktioniert.

    Abschließend noch eine Frage an Leute, die sich mit der WMI Programmierung auskennen.
    Warum funktionieren in den meißten Fällen die einfachen zuweisungen wie
    $oCondition.Operands = $aOperands
    und in anderen Fällen muss man es so zuweisen
    $oGroup.Properties_.Item("Condition") = $oCondition

    Weiss jemand womit das zusammen hängt? In VBS scheint es keine Rolle zu spielen. Dort funktioniert auch die einfache Zuweisung
    group.Condition=condition
    AutoIT scheint hier knirschiger zu sein.

    Vielen Dank für eure Unterstützung!!!