Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]6998[/thread]

Beratung: Vergleichen von Textdateien

Leser: 1


<< |< 1 2 3 >| >> 21 Einträge, 3 Seiten
Gast Gast
 2005-05-17 18:23
#54990 #54990
Hi! (sorry schonmal für den langen Beitrag)
Ich bräuchte da mal in erster Linie einen Beratungdienst und wahrscheinlich auch Programmierhilfe.
Es geht um folgendes: Monatlich soll ein Abgleich zwischen den Usern einer ADS und der "Kopie" dieser User in einem ADAM(Active Directory Application Mode. Im Grunde ist ADS und ADAM dasselbe) stattfinden. Jedenfalls müssen nun die beiden ldf Files (mit ldifde exportierte User-Objekte) so abgeglichen werden, dass User aus der ADS, die nicht in dem ADAM zu finden sind, in eine neue Datei geschrieben werden sollen um sie dann in den ADAM zu importieren. Leider gibt es dabei einiges zu beachten:
Mal angenommen es gäbe 1 User in dem ADAM und 2 User in der ADS:

ADS ldf File:

dn: CN=Mach Falko 0150,OU=BEREICH1,DC=Wurstfabrik,DC=de
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sn: Mach
givenName: Falko
company: wurstfabrik
sAMAccountName: mach
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=wurstfabrik,DC=de
mail: falko.mach@wurstfabrik.de.example

dn: CN=Muetz Holger 0120,OU=BEREICH1,DC=Wurstfabrik,DC=de
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sn: Muetz
givenName: Holger
company: wurstfabrik
sAMAccountName: muetz
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=wurstfabrik,DC=de
mail: Holger.Muetz@wurstfabrik.DE.example


ADAM ldf File:

dn: CN=mach,OU=BEREICH1,DC=Wurstfabrik,DC=DE
changetype: add
company: wurstfabrik
mail: falko.mach@wurstfabrik.de.example
givenName: Falko
sn: mach
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: mach
name: mach
objectCategory:
CN=Person,CN=Schema,CN=Configuration,CN={5CA9017F-DBF8-4217-8DB2-B1043F357AE4}


Wenn nun der sAMAccountName eines User-Objektes(in dem Fall "muetz")aus der ADS im ADAM File nicht zu finden ist, soll folgendes passieren(der sAMAccountName spiegelt sich im ADAM hier wieder: dn: CN=mach,OU=BEREICH1,DC=wurstfabrik,DC=DE )
1. Nimm sAMAccountName und generiere in dem neuen Textdokument folgende Zeile: dn: CN="sAMAccountName",OU=BEREICH1,DC=wurstfabrik,DC=DE
2. Nimm die "sn: ", "givenName: ", "company: ", "mail " - Zeilen von diesem User-Objekt und setzte sie in dem neuen Textdokument unter die "dn: "-Zeile .
Das ganze müsste dann so aussehen:

dn: CN=muetz,OU=BEREICH1,DC=Wurstfabrik,DC=de
changetype: add
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
sn: Muetz
givenName: Holger
company: Wurstfabrik
sAMAccountName: muetz
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=wurstfabrik,DC=de
mail: Holger.Muetz@wurstfabrik.de.example

Wie würdet Ihr an diese Geschichte ran gehen ?! Oder vielleicht lieber alles in Tabellenform umwandeln und dann vergleichen und bearbeiten ?


edit pq: email-adressen nach RFC 2606 geändert\n\n

<!--EDIT|pq|1117440325-->
Strat
 2005-05-17 18:59
#54991 #54991
User since
2003-08-04
5246 Artikel
ModeratorIn
[Homepage] [default_avatar]
ich mache sowas haeufig folgendermaszen:

1. Auslesen aller Objekte aus ADS -> LDIF (da verwende ich lieber Net::LDAP + Net::LDAP::LDIF als ldifde)
2. Fuer jedes Objekt im LDIF (z.B. Net::LDAP::LDIF)
2.1. mache -wenn noetig - eine konvertierung, sodass es so gut wie identisch zu dem ADAM-Objekt ist
2.2. suche nach einem eindeutigen Kriterium via LDAP das Objekt in ADAM: hier z.B. (&(objectClass=user)(sAMAccountName=$xyz)) (Net::LDAP)
2.3. vergleiche das gefundene objekt mit dem aus der LDIF-Datei, und date eventuell unterschiedliche attribute des gefundenen objektes up. Falls ein RDN noetig sein sollte, sollte man dies allerdings in einem weiteren schritt vornehmen, weil die meisten directories gleichzeitige aenderungen in attributwerten und im RDN versemmeln, sie nacheinander aber problemlos ausfuehren (Net::LDAP::Entry). Man koennte eventuell noch mit Net::LDAP::Schema im Schema nachschauen, wodurch ein fehler beim update verursacht wurde (aber das kannst du dir von AD zu ADAM i.d.R. sparen, weil da die schemata ziemlich identisch sein duerften)
2.3.1. wenn das objekt in ADAM nicht gefunden wurde, hinzufuegen

fertig.\n\n

<!--EDIT|Strat|1116342339-->
perl -le "s::*erlco'unaty.'.dk':e,y;*kn:ai;penmic;;print"
http://www.fabiani.net/
pKai
 2005-05-17 19:52
#54992 #54992
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Ohne die von strat genannten Feinheiten, und nur eine Datei mit fehlenden nach "Spezifikation" erzeugend (Ich gebe auch keine objClass aus, da dies zwar im Beipiel impliziert, im Text aber nicht gefordert ist; Code für objClass-Ausgabe ist auskommentiert):
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
use strict;
use warnings;

use Carp qw(croak);

use Net::LDAP::LDIF;

my ($fads, $fadam, $fout) = @ARGV;
my $Ads = read2hash($fads, 'sAMAccountName'); # strukturiert einlesen, siehe unten
my $Adam = read2hash($fadam, 'cn'); # Da dn kein Attribute ist -> cn


# Wenn nun der sAMAccountName eines User-Objektes(in dem Fall "muetz")
# aus der ADS im ADAM File nicht zu finden ist,

my @missing = grep { !defined $Adam->{lc $_} } keys %{$Ads};

my $targetOU = 'OU=BEREICH1,DC=wurstfabrik,DC=DE';

my $out = Net::LDAP::LDIF->new ($fout, 'w', 'die');

foreach my $misskey (@missing) {
my $ads = $Ads->{$misskey}; # Net::LDAP::Entry-Objekt
my $neu = Net::LDAP::Entry->new();
$neu->dn ("CN=$misskey,$targetOU");
#$neu->add (objClass => [qw/top person organizationalPerson user/]);
foreach my $att (qw/sn givenName company mail/) { # Zu übernehmende Attribute
my $val = $ads->get_value($att);
$neu->add ($att, $val) if length $val;
}
$out->write_entry ($neu);
}
$out->done();

sub read2hash {
my $file = shift; # Eingabe: Dateiname
my $keyname = shift; # Schlüssel für Referenzierung: 'sAMAccountName' oder 'cn'
my %hash; # Ausgabe: (Ref auf) Hash
my $n = 0;
my $ldif = Net::LDAP::LDIF->new ($file, 'r', 'die');
while(not $ldif->eof ()) {
my $entry = $ldif->read_entry ();
$n++;
if ($ldif->error ()) {
print STDERR "Error msg: ", $ldif->error (), "\n";
print STDERR "Error lines:\n", $ldif->error_lines (), "\n";
die "\n";
} else {
my $key = $entry->get_value ($keyname);
croak "Schluessel ($keyname) nicht vorhanden in Satz $n" unless $key;
$hash{lc $key} = $entry; # Net::LDAP:Entry-Objekt unter dem

# (klein geschriebenen ) Schlüssel speichern
}
}
return wantarray ? %hash : \%hash;
}

Aufruf mit ADS-Datei als erstem Parameter,
ADAM-Datei als zweitem und
Ausgabedatei (wird überschrieben) als drittem.

Ausgabedatei sieht dann nach Aufruf mit obigen ADS- und ADAM-Daten wie folgt aus:
Code: (dl )
1
2
3
4
5
dn: CN=muetz,OU=BEREICH1,DC=wurstfabrik,DC=DE
sn: Muetz
givenname: Holger
company: wurstfabrik
mail: [EMAIL=Holger.Muetz@wurstfabrik.DE]Holger.Muetz@wurstfabrik.DE[/EMAIL]
I sense a soul in search of answers.
StefanJ
 2005-05-18 13:43
#54993 #54993
User since
2005-05-03
35 Artikel
BenutzerIn
[default_avatar]
Hi!
Danke für die Antworten.
@ Strat: So einfach ist das nicht, denk ich, weil ich ja den sAMAccountName mit dem "CN-Name" des DN vergleichen muss, da ja das ADAM ldf File keinen sAMAAccountName besitzt ! (oder hab ich dich falsch verstanden ???)

@pKai: Vielen Dank für den Code, nur krieg ich es leider nicht zum laufen. Nachdem ich die 2 Module perl-ldap-0.33.tar.gz und Convert-ASN1-0.18.tar.gz nachinstalliert habe, kriege ich keine Fehlermeldungen mehr beim starten der Test.pl. Allerdings passiert auch sonst nix! Der scheint rein gar nix zu machen. Ich muss den Prozess in der cmd mit STRG+C beenden...
So hab ich das ganze gestartet: c:\prisma\Test>Test.pl ADS.ldf ADAM.ldf Ausgabe.ldf
pKai
 2005-05-18 15:07
#54994 #54994
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Der Aufruf sieht OK aus.
Sind die Eingabedateien größer (sehr groß)?
Wenn ja, geht es statt dessen mit den Eingabedaten wie in deinem Post (2 und 1 Datensatz)?
I sense a soul in search of answers.
StefanJ
 2005-05-18 15:13
#54995 #54995
User since
2005-05-03
35 Artikel
BenutzerIn
[default_avatar]
Ich habe es mit diesen 2 Dateien probiert, die ich oben im Post angeführt habe, also müsste es eigentlich gehen, hab jetzt schon 3 mal nachgeguckt ob auch wirklich die richtigen Zeilen im richtigen Dokument stehen. Was mich allerdings insgesamt wundert ist, (was zweifeslos daran liegen könnte, dass ich deinen Code nur ansatzweise verstehe) dass wenn ich keine Parameter übergebe, oder falsche, passiert einfach gar nix ?!?Müsste nicht dann irgendeine Fehlermeldung in der cmd Box erscheinen, wie z.B. die Fehlermeldung, die erscheint wenn die benötigten Module nicht isntalliert sind ?!
Stefan
pKai
 2005-05-18 15:50
#54996 #54996
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Offenbar funktioniert die Fehlerbehandlung in Net::LDAP::LDIF anders, als ich das verstanden habe aus der Beschreibung.

Ersetze mal die die Zeile 40 (die mit ...LDIF->new) durch folgende:
Code: (dl )
my $ldif = Net::LDAP::LDIF->new ($file, 'r') || croak "Cannot open $file";
I sense a soul in search of answers.
StefanJ
 2005-05-18 16:02
#54997 #54997
User since
2005-05-03
35 Artikel
BenutzerIn
[default_avatar]
Hhmm,ne leider auch nicht. Passiert immer noch nichts! *Help*
pKai
 2005-05-18 17:08
#54998 #54998
User since
2005-02-18
357 Artikel
BenutzerIn
[default_avatar]
Geb mal Ctrl-Z (Z nicht C) ein, wenn das Skript "hängt", evtl. mehrfach.
Tut sich dann was?
I sense a soul in search of answers.
StefanJ
 2005-05-18 17:27
#54999 #54999
User since
2005-05-03
35 Artikel
BenutzerIn
[default_avatar]
also bei Crtl+Z und danach Enter drücken passiert folgendes:

c:\prisma\Test>Test.pl ADS.ldf ADAM.ldf Ausgabe.ldf
^Z
Can't call method "get_value" on an undefined value at c:\prisma\Test\Test.pl li
ne 49.
<< |< 1 2 3 >| >> 21 Einträge, 3 Seiten



View all threads created 2005-05-17 18:23.