Problem bei DirGetSize und DirRemove über Domain Grenze hinaus

  • Hallöchen,

    sitze nun schon seit geraumer Zeit an einer GUI, die mir und meinen Kollegen die tägliche Arbeit in unseren Umgebungen erleichtern soll. Bin allerdings nun an einen Punkt gekommen, wo ich absolut nicht wirklich weiterkomme und hoffe hier vielleicht den entscheidenen Hinweis zu bekommen.

    Vorabinfo:

    Wir betreiben eine große Infrastruktur mit 4 unterschiedlichen Domains (2x Produktiv-, 2x Test-/Intigrationsumgebung, aktuell noch AD-W2003 / Citrix / NetApp usw.) und dazugehörenden Filesystemen. In jedem Benutzerkonto sind die relevanten Pfade (User Home, Profil, Exd.-Share und TS-Profil im UNC-Format hinterlegt. Sofern ein Benutzer das Unternehmen verlässt, werden diese Pfade entsprechend entfernt, um natürlich auch keine Altlasten oder Leichen zu pflegen (bei mehr als 8000 Miatrbeitern, Auszubildenden und Praktikanten kann man sich vorstellen was für eine Fluktuation hier entsteht ;) ). Dabei besitzt jetzt nun jedes Userkonto 4 UNC-Pfade in der Produktivumgebung (Domain1) , 4 UNC-Pfade in der Test-/Intigrationsumgebung(Domain2) die es zu entfernen gilt, wenn ich 1 Benutzerkonto lösche.

    Klar, es gibt diverse 3rd Party-Anwendungen und auch diverse MS-Boardmittel mit den das ggf. eleganter (und auch Kostenintensiver) zu lösen sei - in unserem Admintrupp sind wir uns aber einig, eine eigene - massgeschneiderte - Lösung mit AutoIT sei für uns idealer. Abgesehen davon ist ja auch gerne der Weg das Ziel. :D

    Alles gut und schön - AD-Abfragen, Gui, Prüfroutinen etc... alles weniger das Problem (mittlerweile hat uns ja echt das AutoIT-Fieber gepackt)... aber bei zwei Funktionen fährt das ganze Ding aktuell vor die Wand. -> DirGetSize als auch DirRemove.

    Problem:

    Mit DirGetSize (als Array-Ausgabe mit Files und Folders) eruieren wir vor dem Löschen von jedem Pfad dessen Volumen, Anzahl Dateien und Ordner um ein Log damit zu füttern (man kann ja nie wissen). In Folge käme dann ein entsprechender DirRemove. Dies funktioniert auch ohne weiteres - jedoch nur, wenn ich dieses auch in der gleichen Domain ausführe (als Domain-Admin) in der die File-Server stehen. Ziel ist es allerdings das ganze letztendlich ausschließlich auf der Produktivseite auszuführen und die entsprechende Testumgebung gleich mit abzufackeln. Zwar bestehen entsprechende Trusts zwischen den Domains, allerdings werden alle Benutzerkonten dieser beiden Domains seperat verwaltet und habe z.b auch unterschiedliche Kontennamen / Kennwörter. Auslesen der entsprechenden Pfade aus den AD-Konten war soweit auch kein Problem, jedoch werden beim Zugriff auf Fileebene entsprechende Credentials der jeweiligen Domain erwarten, die ich aktuell dem Befehl ja nicht mitgebe (oder kann). Diese sollen auch nicht auf irgendeine Weise ausgehebelt werden, das es grundsätzlich gilt beide Umgebungen strikt zu trennen (zumindest für den Otto-Normal-Benutzer).

    Z.B. AD-Abfragen (u.ä.) stellen weniger das Problem dar, da die hier genutzten UDF`s (riesigen Dank hier gleich mal an Water für die grandiose AD.au3!!) die Mitgabe von Domain / Benutzername / Kennwort erlauben. Allerdings habe ich bislang keine Möglichkeit gefunden DirGetSize, als auch DirRemove in anderen Kontext laufen zu lassen, als in der des ausführenden Benutzers.

    Die Frage ist nun, wie ich aus einer Domain hinaus DirGetSize (oder ggf. auch ganze andere Funktionen) auf Filesystemen eine anderen Domain zum laufen bekomme. Persönlich wäre es mir dabei am liebsten, dass ich dieses komplett in AutoIT umsetzten kann und nicht auf CMD / VBS oder Powershell angewiesen bin. Entsprechende Konten und Berechtigungen zur generellen Ausführung in allen Domains sind nicht das Thema. Wobei ich schon inbetracht gezogen habe, ein Dienstkonto dafür zu nutzen (ist aber eine andere Geschichte) - dieses jedoch ebenfalls daran scheitert, dass eine Möglichkeit her muss, um für eine andere Domain entsprechende Anmeldedaten mitgeben zu können.

    Prinzipiell in ganz einfacher Art und Weise...

    [autoit]


    Global $DirPfadProd = "\\Server1\Profile$\UserXYZ" ; Befindet sich innerhalb Domain 1
    Global $DirPfadTest = "\\Server2\Profile$\UserXYZ" ; Befindet sich innerhalb Domain 2

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

    ; folgender Passage läuft im Kontext des startenden User (Admin) in Domain 1
    Func _Folder1($DirPfadProd)
    Local $tmpSize = DirGetSize($DirPfadProd, 1)
    Local $DirSize = "" & Round($tmpsize[0] / 1024 / 1024)
    Local $DirFiles = $tmpsize[1]
    Local $DirFolder = $tmpsize[2]
    DirRemove($DirPfad, 1)
    if FileExists($DirPfad) Then
    MsgBox(0,"Meldung","Verzeichnis noch vorhanden")
    Else
    MsgBox(0,"Meldung",$DirSize&" MB, "&$DirFolder&" Ordner und "&$DirFiles&" Dateien wurden entfernt.")
    EndIf
    EndFunc

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

    ; theoretisch hier Abfrage von Benutzerdaten....?! - aber wie, damit nachfolgender Befehl diese nutzen kann?
    ; folgender Passage muss mit einer anderen Userkennung (Admin) in Domain 2 ausgeführt werden
    Func _Folder2($DirPfadTest)
    Local $tmpSize = DirGetSize($DirPfadTest, 1)
    $DirSize = "" & Round($tmpsize[0] / 1024 / 1024)
    $DirFiles = $tmpsize[1]
    $DirFolder = $tmpsize[2]
    DirRemove($DirPfadTest, 1)
    if FileExists($DirPfadTest) Then
    MsgBox(0,"Meldung","Verzeichnis noch vorhanden")
    Else
    MsgBox(0,"Meldung",$DirSize&" MB, "&$DirFolder&" Ordner und "&$DirFiles&" Dateien wurden entfernt.")
    EndIf

    [/autoit]



    Alle Pfade sind wie gesagt im UNC-Format hinterlegt (\\Server\Profile$\UserXYZ), jedoch kam bislang ein Mapping der Ressourcen (hier im Beispiel die Freigabe "Profile$") nicht in Frage. Das Unterverzeichnis "UserXYZ" könnte man verbinden, aber der Ordner "UserXYZ" soll ja ebenfalls gelöscht werden. Die $-Freigabe wäre im Notfall noch denkbar, jedoch müsste ich dann Berechtigungen (Konzept!) umbauen, was ich aber strikt vermeiden will. Dazu kommt, dass es sich nicht um Windows File-Server, sondern um NetAPP / EMC-Maschinen mit entsprechenden V-Filer / CIFS-Servern handelt und da schrauben wir prinzipiell nicht gerne an Berechtigungen rum :thumbdown: . Sonst muss einer von uns noch über die Planke.... "haaaarrrrrrrr"

    Gefunden habe ich in ähnlichem Bezug nur noch folgenden Ansatz (der mir jedoch noch nicht 100%ig klar ist). Eine solche Abfrage wäre völlig ausreichend... nur die Anwendung... ähm... ja... :whistling:

    Spoiler anzeigen
    [autoit]

    #include <APIDlgConstants.au3>
    #include <Crypt.au3>
    #include <MsgBoxConstants.au3>
    #include <WinAPI.au3>
    #include <WinAPIDlg.au3>

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

    Local $hBitmap = _WinAPI_LoadImage(0, @ScriptDir & '\Extras\Authentication.bmp', $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
    Local $aData[3] = ['', '', 0]

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

    While 1
    $aData = _WinAPI_ShellUserAuthenticationDlg('Authentication', 'To continue, type a login and password, and then click OK.', $aData[0], $aData[1], 'MyScript', BitOR($CREDUI_FLAGS_ALWAYS_SHOW_UI, $CREDUI_FLAGS_EXPECT_CONFIRMATION, $CREDUI_FLAGS_GENERIC_CREDENTIALS, $CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX), 0, $aData[2], $hBitmap)
    If @error Then Exit

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

    If (StringCompare($aData[0], 'AutoIt')) Or (StringCompare($aData[1], StringEncrypt(False, 'DC7E430A1C88', '123'))) Then
    If $aData[2] Then
    _WinAPI_ConfirmCredentials('MyScript', 0)
    EndIf
    MsgBox(BitOR($MB_ICONERROR, $MB_SYSTEMMODAL), 'Error', 'You have typed an incorrect login or password, it should be "AutoIt" and "123".')
    Else
    If $aData[2] Then
    _WinAPI_ConfirmCredentials('MyScript', 1)
    EndIf
    ExitLoop
    EndIf
    WEnd

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

    Func StringEncrypt($bEncrypt, $sData, $sPassword)
    _Crypt_Startup() ; Start the Crypt library.
    Local $sReturn = ''
    If $bEncrypt Then ; If the flag is set to True then encrypt, otherwise decrypt.
    $sReturn = _Crypt_EncryptData($sData, $sPassword, $CALG_RC4)
    Else
    $sReturn = BinaryToString(_Crypt_DecryptData($sData, $sPassword, $CALG_RC4))
    EndIf
    _Crypt_Shutdown() ; Shutdown the Crypt library.
    Return $sReturn
    EndFunc ;==>StringEncrypt

    [/autoit]

    Man möge verzeihen, dass meine Kollegen und ich noch AutoIT-Anfänger sind ;( ! Bin daher für jede Idee und Rat dankbar.

    Dank und Grüße

    Gibbs

    Einmal editiert, zuletzt von Agent_Gibbs (19. November 2014 um 22:21)

  • Ich habe leider keine Erfahrung mit multiplen Domänen, aber soweit ich dich verstanden habe kannst du durchaus aus Domäne1 auf ein Networkshare aus Domäne2 zugreifen, solange du die korrekten Logindaten für den jeweiligen Networkshare angibst. Also es wäre dir z.B. möglich von Hand Netzlaufwerke aus der fremden Domäne einzubinden. Habe ich das soweit richtig verstanden?

    Sollte das so zutreffend sein schlage ich dir vor einen dieser Wege anzusehen:

    1. Lagere die Scriptteile die in beliebigen/unterschiedlichen Benutzerkontexten laufen sollen in eine separate Scriptdatei aus. Aus deinem Hauptscript rufst du dieses "worker script" mit runas im jeweils richtigen Userkontext auf und übergibst als Parameter den UNC Pfad der geprüft/gelöscht werden soll.

    2. Verwende DriveMapAdd um die Netzlaufwerke im jeweils passenden Benutzerkontext zu verbinden. Anschließend deine Prüf-/Löschroutine auf die verbundenen Laufwerke loslassen und danach die Laufwerke wieder mit DriveMapDel trennen.

    Beide Varianten sollten funktionieren, du benötigst aber eben die jeweils passenden Accountdaten für alle Networkshares. Zur Vereinfachung würde ich wohl in allen Domänen einen gleichnamigen Benutzer mit gleichem Passwort dafür verwenden und im Script dann nur noch das Domänen Prefix variabel halten.

  • Vielen Dank erst Mal!. Deine Annahme ist völlig korrekt. Login-Daten für alle Domänen sind kein Problem, auch das Verbinden von Laufwerken aus all diesen Domänen ist kein Problem.

    Der erste Lösungsungansatz wäre dann wohl eher möglich, als der zweite - primär deshalb weil das zu prüfende / löschende Verzeichnis direkt unterhalb der Administrativen $-Freigabe steht. Und ich wüsste jetzt nicht, wie ein Verzeichnis löschen könnte, was als Netzlaufwerk im gleichen Moment verbunden ist. Dürfte meines Wissens nach grundsätzlich nicht funktionieren (Windowsseitig). Sicherlich könnte man auf der $Freigabe aufsetzen, so dass das zu löschende Verzeichnis als Unterverzeichnis erscheint - da ich abschließend nicht der einzige bin, der das Script nutzen wird/soll - scheitert dieses an den Berechtigung bei uns. An die $Freigabe direkt kommt nur ein sehr dedizierter Admin-Kreis.

    Werde aber mal deinen ersten Ansatz verfolgen und dieses mal testen. Werde das Ergebnis dann posten... :)

  • Moin,

    im Nachgang hier noch mal die jetzt von uns genutzte Lösung des o.g. Problems.

    Einmalige Abfrage der Credentials zu Programmstart... Benutzernamen und PW sind bei diesem ACC in allen Domains gleich, daher ja nur einmal nötig.

    Spoiler anzeigen
    [autoit]

    Func DOM_Authentification()
    Local $hBitmap = _WinAPI_LoadImage(0, @ScriptDir & '\Extras\Authentication.bmp', $IMAGE_BITMAP, 0, 0, $LR_LOADFROMFILE)
    Local $Data[3]
    Local $User[3]
    $Data[0] = "xxxxx.DOM\" & @UserName
    $Data = _WinAPI_ShellUserAuthenticationDlg('Authentifizierung', 'Es ist eine Authentifizierung gegenüber der Domain XXXXXX notwendig. Bitte geben Sie eine gültige Benutzerkennung an.', $Data[0], $Data[1], 'MyScript', BitOR($CREDUI_FLAGS_ALWAYS_SHOW_UI, $CREDUI_FLAGS_EXPECT_CONFIRMATION, $CREDUI_FLAGS_GENERIC_CREDENTIALS, $CREDUI_FLAGS_SHOW_SAVE_CHECK_BOX), 0, $Data[2], $hBitmap)
    $User = _WinAPI_ParseUserName($Data[0])
    If @error Then
    ; Errorhandling...
    EndIf
    ; $User[0] = Domainname
    ; $User[1] = Benutzername
    ; $Data[1] = Passwort
    EndFunc ;==>ITU_Authentificati

    [/autoit]

    Die beiden erstellten Arrays $User und $ Data werden für die entsprechenden Fileoperationen in anderen Domains genutzt.

    Bevor dann Fileoperationen reicht es aus (da war ich ja selbst überrascht) eine beliebige Freigabe vom entsprechenden Filer zu verbinden. Habe eine Standardfreigabe der NetAPP(V-Filer mit CIFS Share) genutzt, welche nur für TMP-Zwecke vorhanden sind. Dieses reicht aber aus, einen Trust aufzubauen und beliebige Fileoperation (so eben auch ein DirGetSize) auf gleichen Filer durchzuführen (Berechtigungen der eingegebenen Credentials mal vorausgesetzt).

    Spoiler anzeigen
    [autoit]

    Func get_pathAuth_pipe() ; Share xxxxx.DOM temporär verbinden und authentifizieren
    $resultAuthPfad = DriveMapAdd("*", $AuthPfad, 8, $Data[0], $Data[1])
    $resultAuthPfad2 = DriveMapAdd("*", $AuthPfad2, 8, $Data[0], $Data[1])
    EndFunc ;==>get_pathAuth_pipe

    [/autoit]

    ...ab hier kann ich dann alle Filebasierenden Aktivitäten durchführen und im Anschluß die Laufwerke wieder entfernen...

    Spoiler anzeigen
    [autoit]

    Func del_pathAuth_pipe() ; Share aus xxxxx.DOM wieder entfernen
    DriveMapDel($resultAuthPfad)
    DriveMapDel($resultAuthPfad2)
    EndFunc ;==>del_pathAuth_pipe

    [/autoit]

    Funktioniert erstaunlich fix und zuverlässig. Haben pro Domain immer 2 Filer, daher sind immer 2 Mapping erforderlich (1x pro Filer). Interessanterweise ist dabei noch aufgefallen, dass ich - sofern ich eine Verbindung zum Filer habe und diese wieder trenne - der Trust noch für knapp 5 min. bestehen bleibt. Ich kann ergo noch diese 5 min. lang weiter auf den Filer zugreifen, ohne erneut ein Mapping herzustellen. ?( Nach Ablauf dieser Zeit muss ich mich wieder Authentifizieren (via Mapping z.B.).

    Danke aber nochmal für die treffenden Antworten! :thumbup:

    - kann geclosed werden -