Page 1 sur 1

[..] Fonction récursive

Posté : ven. 04 mars 2011 09:15
par lokidor
Bonjour,

Je viens à vous car j'ai mis au point un script qui est sensé être récursif mais qui veux pas ><

Sur le principe : j'ai un utilisateur qui appartient a différents groupes. Ces groupes contenant eux même d'autres groupes et ainsi de suite.

Mon idée, c'est : je prends le user, je tire la liste de ces groupe, je prends le premier groupe j'écris dans un fichier qui il est et qui est son parent, je regarde ces groupes, je prends le premier, j'écris etc... et ainsi de suite jusqu'à un groupe qui n'en contient pas d'autres. Et à ce moment là, on remonte un étage au dessus et on refait la même chose avec le second groupe. De cette manière on remonte petit à petit en faisant tous les groupes.

Mon soucis, c'est qu'arrivé au fond de la première branche, ben pas moyen de remonter :(
Je pense que ça vient du fait qu'il ne peut récupérer le nom du groupe au dessus.

J'ai fait de la récursivité en cours, mais j'ai toujours eu du mal ><

Je pense bien qu'il me manque un moyen de de revenir en arrière quand je suis au bout, mais je ne parvient pas à m'en sortir :/

Merci aux âmes charitables qui sauront me sortir de ce bourbier :)

le code :

Code : Tout sélectionner

Global $MOF_grp
Global $MOF_CSV = "***/***/***/RecursiveMemberOf_résultat.txt"
Global $MOF_handler_CSV

;petite fonction prise de _ADfunction.au3 et modifié pour faire bien les choses
;fonction qui va chercher la liste des memberOf d'un user AD et le retourne dans un tableau $memberof
Func ADGetUserGroups(ByRef $memberof, $user = @UserName)

    Local $objItem

    $strHostServer = $objRootDSE.Get("dnsHostName") ; Retrieve the name of the connected DC

    $objItem = ObjGet("LDAP://" & $strHostServer & "/" & $user) ; Retrieve the COM Object for the logged on user

    $memberof = $objItem.GetEx("memberof")

;~     MsgBox(64,"debug","memberof : "&$memberof)
;~     _ArrayDisplay($memberof)

    $count = UBound($memberof)

    _ArrayInsert($memberof, 0, $count)

EndFunc   ;==>_ADGetUserGroups

Func RecursiveListGroup($MOF_userDN)
    ADGetUserGroups($MOF_grp,$MOF_userDN)
;~     _ArrayDisplay($MOF_grp)

    If IsArray($MOF_grp) Then
        For $MOF_cpt=1 To $MOF_grp[0]

;~             MsgBox(64,"Fini", $MOF_grp[0])
;~             _ArrayDisplay($MOF_grp)

            ;on écrit le résultat dans le CSV
            FileWrite($MOF_handler_CSV,"Père : "&_ADDNToSamAccountName($MOF_userDN)&" ----> Fils : "&_ADDNToSamAccountName($MOF_grp[$MOF_cpt])&@CRLF)
            FileWrite($MOF_handler_CSV,"--------------------------------"&@CRLF)

            ;on rappelle la fonction pour aller plus bas
            RecursiveListGroup($MOF_grp[$MOF_cpt])
        Next
    Else

        ;on écrit dans le CSV qu'il n'y a pas de fils pour ce groupe
        FileWrite($MOF_handler_CSV,"Pas de descendance pour : "&_ADDNToSamAccountName($MOF_userDN)&"!"&@CRLF)
        FileWrite($MOF_handler_CSV,"--------------------------------"&@CRLF)

    EndIf

EndFunc

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg

        Case $MOF_GO

            ;ouverture du fichier
            $MOF_handler_CSV=FileOpen($MOF_CSV,1)

            ;on lit l'entrée de l'utilisateur (à savoir quel user AD on doit aller regarder)
            $MOF_user = GUICtrlRead($MOF_user_input)

            ;on écrit l'en tête du fichier
            FileWrite($MOF_handler_CSV,"--------"&_NowDate() &" "& _NowTime() &" -------- Fiche des groupes de  : "&$MOF_user&" --------"&@CRLF)

            ;on met le nom donné sous la bonne forme pour AD
            $MOF_user_DN  = _ADSamAccountNameToFQDN($MOF_user)

            ;appel de la fonction récursive
            RecursiveListGroup($MOF_user_DN)

            ;fermeture du fichier
            FileClose($MOF_handler_CSV)

            ;Fin du programme
            MsgBox(64,"Fini", "Traitement terminé")

    EndSwitch
WEnd
Edit : simplification du code

Re: [..] Fonction récursive

Posté : ven. 04 mars 2011 19:05
par Tlem
Je ne doute pas que vos explications sont extrêmement claires pour vous. Malheureusement, après 3 lectures j'avoue avoir un peut de mal à entrevoir la portée globale de votre question. Cela est sans doute le fait que nous soyons Vendredi soir et que je suis quelque peu fatigué.
Mis à par ses quelques considérations et afin de facilité la compréhension de la problématique, quelques images ou dessins pour neuneu m'aiderai grandement à comprendre votre histoire d'utilisateur et de groupe et ce que vous souhaitez obtenir.

Pour résumer, qu'avez-vous comme données et que voulez-vous obtenir en résultat.

Re: [..] Fonction récursive

Posté : ven. 04 mars 2011 21:35
par sylvanie
Bonsoir,
Ce qui n'est pas facile est de faire tourner le script, car il est très "environement" dépendant.
Cependant, je pense qu'il y a déjà au moins un soucis sur $MOF_grp :
Cette variable est globale, or par récursivité, elle se fait écraser par les appels à ADGetUserGroups. Comme elle est déclarée comme globale, alors en sortie de la premère brache exploirée, on ne tombe plus sur le tableau initial.

Pour la faire plus clair, déclarez là en "local" dans la fonction RecursiveListGroup, ainsi le contenu de la variable ne sera pas écrasée par l'appel à ADGetUserGroups dans les autres itérations.

Tenez nous au courant ;)

Re: [..] Fonction récursive

Posté : mer. 13 avr. 2011 10:18
par sksbir
Bonjour

Je dirais pour ma part qu'il y a un problème d'architecture.
Alors on a
;fonction qui va chercher la liste des memberOf d'un user AD et le retourne dans un tableau $memberof
Func ADGetUserGroups(ByRef $memberof, $user = @UserName)
et
Func RecursiveListGroup($MOF_userDN)

Ce qui ne va pas, c'est qu'on trouve un appel à ADGetUserGroups dans la fonction RecursiveListGroup.

Dans le principe, pour chaque utilisateur, on cherche donc la liste des groupes directs ( fonction ADGetUserGroups ) , et pour chaque groupe direct rencontré , on devrait appeler la fonction RecursiveListGroup pour trouver la liste des groupes indirects.

Donc, ADGetUserGroups appelle RecursiveListGroup , et RecursiveListGroup s'appelle lui même , mais en aucun cas RecursiveListGroup ne doit appeler ADGetUserGroups .

Et puis pour ce qui est de stocker tout ça dans un tableau, je te conseille de déclarer ton tableau en global, d'utiliser tableau[0] comme compteur d'éléments déja remplis, et de ne pas passer tableau[] en paramètre de tes fonctions.


Et puis dans le principe de la récursivité, il ne faut pas se casser la tête sur la façon de "remonter". En fait, "remonter", c'est juste que le script "fils" se termine et permet à son "père" de continuer son traitement...

Re: [..] Fonction récursive

Posté : mer. 13 avr. 2011 11:39
par lokidor
Merci à tous pour vos réponses :)

En effet, déclarer mon tableau en global était une erreur, parmi tant d'autres :p

J'ai repris tout ça au calme chez moi durant ma période de cours avec une de mes profs de prog.

Je me rends compte en vous écrivant que j'ai oublié le fichier en question chez moi -_-

Je ramène ça demain. Je pense en tout cas que je ne suis plus très loin de la solution, vous me direz ce que vous en pensez ;) (promis je ferais un gros effort pour la compréhension, bien que l'on ne soit plus vendredi :P )

Encore merci à tous et à demain

Re: [..] Fonction récursive

Posté : mer. 13 avr. 2011 15:33
par sksbir
Créer le tableau globalement n'est pas une erreur en soi : c'est pas parce qu'un script est récursif qu'il ne doit pas alimenter un seul et même tableau pour tout l'empilement d'invocation.

Maintenant, si tu réinitialise le tableau au niveau global à chaque invocation, là, ça va plus marcher...

Re: [..] Fonction récursive

Posté : jeu. 14 avr. 2011 09:42
par lokidor
Voili voilou, j'ai modifié la fonction récursive, je vous reposte pas ce qui vas autour, ça ne devrait pas avoir changé (en dehors du tableau de résultat qui n'est plus en global)

Code : Tout sélectionner

Func RecursiveListGroup($MOF_userDN)
    ;on récupère la liste des groupes dans $MOF_userDN
    ADGetUserGroups($MOF_grp,$MOF_userDN)

    If IsArray($MOF_grp) Then
            For $MOF_cpt=1 To $MOF_grp[0]

                ;on écrit le résultat dans le CSV
                FileWrite($MOF_handler_CSV,"Père : "&_ADDNToSamAccountName($MOF_userDN)&" ----> Fils : "&_ADDNToSamAccountName($MOF_grp[$MOF_cpt])&@CRLF)
                FileWrite($MOF_handler_CSV,"--------------------------------"&@CRLF)

                ;on rappelle la fonction pour aller plus bas
                RecursiveListGroup($MOF_grp[$MOF_cpt])
            Next
    Else
        ;on écrit dans le CSV qu'il n'y a pas de fils pour ce groupe
        FileWrite($MOF_handler_CSV,"Pas de descendance pour : "&_ADDNToSamAccountName($MOF_userDN)&"!"&@CRLF)
        FileWrite($MOF_handler_CSV,"--------------------------------"&@CRLF)
    EndIf

EndFunc

 

Je penses que mon problème se situe à ce niveau là :

Code : Tout sélectionner

If IsArray($MOF_grp) Then
 
Car lorsque je n'ai qu'un enregistrement dans le tableau, il passe le test de IsArray, mais desuite après il me sort une erreur et se stop :
test_MemberOfRecursif.au3 (61) : ==> Subscript used with non-Array variable.:
FileWrite($MOF_handler_CSV,"Père : "&_ADDNToSamAccountName($MOF_userDN)&" ----> Fils : "&_ADDNToSamAccountName($MOF_grp[$MOF_cpt])&@CRLF)
FileWrite($MOF_handler_CSV,"Père : "&_ADDNToSamAccountName($MOF_userDN)&" ----> Fils : "&_ADDNToSamAccountName($MOF_grp^ ERROR
Merci pour votre aide :)

Edit : J'ai oublié de faire un "dessin" pour une meilleur compréhension du problème :P

Donc en fait, je prends un User ActiveDirectory et j'extraie ces groupes.
Ensuite, pour chaque groupe extrait, je regarde s'il n'y a pas d'autres groupes a l'intérieur de ces groupes précédemment extraits.
Je souhaite répéter ce schéma jusqu'à ce que j'arrive tout au fond de l'arborescence.

J'espère avoir été clair. Si ce n'est pas le cas, n'hésitez pas à me le dire :)

Re: [..] Fonction récursive

Posté : jeu. 14 avr. 2011 11:02
par sksbir
je vois que tu ne tiens pas compte de mes remarques... dommage, d'autant plus que dans ta dernière réponse tu décris correctement le processus quand tu le décris en clair, mais tu ne l'applique pas à ton propre script.

Re: [..] Fonction récursive

Posté : jeu. 14 avr. 2011 11:42
par lokidor
sksbir a écrit : Ce qui ne va pas, c'est qu'on trouve un appel à ADGetUserGroups dans la fonction RecursiveListGroup.

Donc, ADGetUserGroups appelle RecursiveListGroup , et RecursiveListGroup s'appelle lui même , mais en aucun cas RecursiveListGroup ne doit appeler ADGetUserGroups .
Là, je ne vois pas pourquoi. Dans me tête, ce serait plutôt l'inverse, RecursivListGroup a besoin de savoir quels sont les groupes, il faut donc bien qu'il appelle ADGetUserGroups non? En tout cas je n'ai pas bien compris ton conseil là dessus ^^'
sksbir a écrit : Et puis pour ce qui est de stocker tout ça dans un tableau, je te conseille de déclarer ton tableau en global, d'utiliser tableau[0] comme compteur d'éléments déja remplis, et de ne pas passer tableau[] en paramètre de tes fonctions.
Je veux bien, mais je ne vois pas comment gérer l'index du tableau :( il faudrait le passer en paramètre?

Et surtout on risque de se retrouver avec un array d'une taille un peu exagérée je pense car la quantité de groupes est assez importante(30 à 40 groupes au premier niveau).
sksbir a écrit :je vois que tu ne tiens pas compte de mes remarques... dommage
J'ajouterais juste que je n'ai pas pas tenu compte de tes conseil, le code que j'ai posté aujourd'hui a été écrit il y a quelques semaines, et je n'était pas revenu dessus avant de poster ce matin. N'y vois aucune marque d'irrespect :oops:
sksbir a écrit :d'autant plus que dans ta dernière réponse tu décris correctement le processus quand tu le décris en clair, mais tu ne l'applique pas à ton propre script.

haa... :roll:
Il me semblait pourtant avoir suivi la même logique.




Merci encore

Re: [..] Fonction récursive

Posté : jeu. 14 avr. 2011 12:30
par sksbir
lokidor a écrit :
sksbir a écrit : Ce qui ne va pas, c'est qu'on trouve un appel à ADGetUserGroups dans la fonction RecursiveListGroup.
Donc, ADGetUserGroups appelle RecursiveListGroup , et RecursiveListGroup s'appelle lui même , mais en aucun cas RecursiveListGroup ne doit appeler ADGetUserGroups .
Là, je ne vois pas pourquoi. Dans me tête, ce serait plutôt l'inverse, RecursivListGroup a besoin de savoir quels sont les groupes, il faut donc bien qu'il appelle ADGetUserGroups non? En tout cas je n'ai pas bien compris ton conseil là dessus ^^'
Ben non. Tu l'appelles avec un seul argument obligatoire : le nom du groupe dont tu veux scanner la liste des groupes secondaires ( enfin, le chemin AD complet du nom du groupe, c'est plus facile).
Donc, la logique du script est celle-ci:
- pour chaque groupe de l'utilisateur, j'appelle RecursivListGroup (nomgroupe)
- Dans RecursivListGroup, je fais la liste des groupes du groupe passé en argument. Pour chaque groupe trouvé, j'appelle RecursivListGroup.

Tu vois donc bien que RecursivListGroup n'a besoin que d'un truc en entrée : le nom du groupe à explorer. Il n'a pas non plus besoin de faire appel ADGetUserGroups. Pourquoi faire?? il a tout ce qu'il faut...
sksbir a écrit : Et puis pour ce qui est de stocker tout ça dans un tableau, je te conseille de déclarer ton tableau en global, d'utiliser tableau[0] comme compteur d'éléments déja remplis, et de ne pas passer tableau[] en paramètre de tes fonctions.
Je veux bien, mais je ne vois pas comment gérer l'index du tableau :( il faudrait le passer en paramètre?
Et surtout on risque de se retrouver avec un array d'une taille un peu exagérée je pense car la quantité de groupes est assez importante(30 à 40 groupes au premier niveau).
J'ai mis un tableau de 500, et je n'ai jamais explosé. L'index du tableau, c'est la case 0. tableau[0]=3 : tu as déjà renseigné 3 groupes ( dans tableau[1], tableau[2], et tableau[3] ).

ps : si j'avais considéré ça comme de l'irrespect, je n'aurais tout simplement plus rien posté ici ;)
pps : je te laisse réfléchir encore un peu, et après je te donne la solution qui est opérationnelle chez moi.

Re: [..] Fonction récursive

Posté : ven. 15 avr. 2011 10:44
par lokidor
yep merci beaucoup en tout cas.

Pour le moment je suis passé sur un autre outils a développer, mais je reviens sur celui ci dans le courant de la semaine prochaine.

Je ne perds pas espoir :D