Archive for Oktober, 2010

Nutzer anlegen im Active Directory

Ich habe vor einigen Tagen mich mit dem Active Directory beschäftigen müssen. Für mich als Solaris-User ist das eine ganz andere Welt. Deswegen habe ich mich sehr schwer getan, ohne Martin wär dieser Artikel nicht möglich gewesen. Er stand mir mit Rat und Tat eine Stunde telefonisch zur Verfügung. Danke noch einmal!

Nun zu meinen Problem: Ich wollte Nutzer aus einer spool-Datei automatisch in das Active Directory eintragen. Weiterhin mussten die Benutzer in die Organizational Unit peter_lustig_user verschoben werden. Das anlegen der Nutzer habe ich noch alleine hinbekommen. Dazu habe ich aus zahlreichen Skripten Codezeilen kopiert. Aber das Verschieben habe ich nicht hinbekommen. Martin hat mich auf die Active Directory Tools von Microsoft hingeweisen. Diese fangen alle mit ds an. Mit dsquery * habe ich mich durch die Struktur des Active Directory gewühlt. Das grafische Frontend ist zwar schön, aber da habe ich nicht mitbekommen, aber da weiß ich nicht wie der Distinguished Name aussieht…
Zum Schluss bin ich zu folgen Skript gekommen:

Set args = WScript.Arguments
profile_pfad = "\\odin\homes\%username%\profile"
gruppe_neu = "benutzer"
if args.count <> 1 then
	MsgBox "Es muss genau eine spool-Datei angegeben werden"
	Wscript.quit
End If
Randomize
protokoll = "C:\Dokumente und Einstellungen\Administrator\Desktop\skripte\protokoll.txt"
Set fs = CreateObject("Scripting.FileSystemObject")
' Das WScript.Network-Objekt liefert den Namen des Computers
Set net = CreateObject("WScript.Network")
' Protokolldatei öffnen
Set output = fs.CreateTextFile(protokoll, True)
'Holt den Namen des Computers aus dem net Objekt
name = net.ComputerName
Set computer = GetObject("WinNT://" & name)
' Datei öffnen
dateiname = args(0)
If Not fs.FileExists(dateiname) Then
	MsgBox "Die Datei (" & dateiname & ") existiert am angegebenen Ort nicht!"
	WScript.Quit
End If
Set infos = fs.OpenTextFile(dateiname)
' Datei zeilenweise bis zum Ende (atEndOfStream) lesen:
Do Until infos.AtEndOfStream
	' eine Zeile einlesen
	zeile = infos.ReadLine
	' Informationen durch Semikola splitten
	details = Split(zeile, ";")
	username = Trim(details(0))
	' Konto anlegen
	Set kontoneu = computer.Create("User", Trim(details(0)))
	kontoneu.FullName = Trim(details(1))
	kontoneu.Profile = profile_pfad
	' Passwort auslesen, wenn es das default-Passwort ist, dann generiere ein Passwort
	passwort =  Trim(details(2))
	if passwort = "du34!$7_.4-@" then
		passwort = Trim(genPasswort)
		kontoneu.PasswordExpired = CLng(1)
	end if
	kontoneu.SetPassword passwort
	' Ablaufdatum setzten
	if trim(details(3)) <> "never" then
		kontoneu.AccountExpirationDate = Trim(details(3))
	end if
	' Normales Benutzerkonto
	kontoneu.UserFlags = 512
	if not fs.FolderExists("\\odin\homes\" & username) then
		set folder = fs.CreateFolder("\\odin\homes\" & username)
		set folder_files = fs.createfolder("\\odin\homes\" & username & "\files")
		set folder_profile = fs.createfolder("\\odin\homes\" & username & "\profile")
		set IShellDispatch2 = CreateObject("Shell.Application")
		Call IShellDispatch2.ShellExecute("C:\skripte\subinacl", "/file \\odin\homes\" & username & " /setowner=" & username, , , 0)
		Call IShellDispatch2.ShellExecute("c:\skripte\subinacl", "/subdirectories \\odin\homes\" & username & " /setowner=" & username, , , 0)
		Call IShellDispatch2.ShellExecute("C:\skripte\cacls", "\\odin\homes\" & username & " /T /G Administratoren:F " & username & ":F System:F < echo j", , , 0)
	end if
	err.clear
	On Error Resume Next
	kontoneu.SetInfo
	if Err.number = 0 then
		WriteLog "Benutzername:  " & username & "   Passwort: " & passwort
		AddToGroup gruppe_neu, kontoneu.ADsPath
		' User in die ou peter_lustig_user verschieben
		set dsMove = CreateObject("Shell.Application")
		dsMoveArg = " " & Chr(34) & "CN=" & username & ",CN=Users,DC=w2k8-pool,DC=windows,DC=0rpheus,DC=net" & Chr(34) & _
	                       " -newparent " & Chr(34) & "OU=peter_lustig_user,DC=w2k8-pool,DC=windows,DC=0rpheus,DC=net" & Chr(34)
		Call dsMove.ShellExecute("dsmove", dsMoveArg, , ,0)
	else
		if Err.number = -2147022672 then
			WriteLog "Fehler beim Anlegen von " & username & ": Nutzer existiert bereits"
		else
			WriteLog "Fehler beim Anlegen von " & username & ": " & Err.Number
		end if
	end if
	Err.Clear
Loop
' Dateien schließen
infos.Close
output.Close
' Protokoll anzeigen:
'SYS: Microsoft (r) Script Runtime
Set wshshell = CreateObject("WScript.Shell")
wshshell.Run """" & protokoll & """"
Sub AddToGroup(gruppenname, kontoname)
	On Error Resume Next
	Set gruppe = GetObject("WinNT://" & ComputerName & "/" & gruppenname & ",group")
	gruppe.Add kontoname
	gruppe.SetInfo
	If Err.number = 0 Then
		'WriteLog "Konto ist Mitglied in Gruppe " & gruppenname
	Else
		'WriteLog "Konto konnte nicht zum Mitglied in Gruppe " & gruppenname & " gemacht werden."
	End If
	Err.Clear
End Sub
 
Sub WriteLog(text)
	' eine Zeile ins Protokoll schreiben und Leerzeile einfügen
	output.WriteLine text & vbCrLf & vbCrLf
End Sub
 
function genPasswort()
	password = ""
	for i=1 to 12
		if Int(100*Rnd mod 2 ) = 1 then
			password = password & chr(Int(61*Rnd+33))
		else
			password = password & chr(Int(29*Rnd+97))
		end if
	next
	genPasswort = password
end function

Der AD-Guru oder Windows-Hardcore User wird sicher sagen, wie dumm ist das denn, das geht in einen 3-Zeiler. Aber ich kann kein Windows und will es eigentlich auch nicht lernen :P Wenn ich Zeit hätte wüsste ich wie man mit den ds*-Tools das ganze schöner machen könnte. Ich habe das komplette Skript hier rein gestellt, da man sicher die ein oder andere Zeile klauen kann *g*. Der Passwortgenerator ist schlecht, es war aber die schnellste Lösung.

Platz sparen mit zfs

Mir sind heute meine Festplatten fast voll gelaufen. Also habe ich quick&dirty die Kompression und die Deduplikation von zfs für die betreffenden Dateisysteme aktiviert. Da zfs (noch) kein rewrite der Daten hat, habe ich angefangen die Daten zu kopieren und anschließend die alte Version gelöscht. Für import und Export von Pool hatte ich einfach zu wenig Platz, deswegen die umständliche Aktion mit dem kopieren. Und dann kam der Schreck: du -hs zeigte auf einmal eine kleinere Größe an. Nach einiger Nachforschung habe ich mitbekommen, dass disk usage wörtlich zu nehmen ist. du zeigt wirklich die Größe an, welche auf dem Device verbraucht wird. Das GNU-du kann hier Abhilfe schaffen, mit /usr/gnu/bin/du --apparent-size -hs bekommt man die Aufsummierte Größe der Dateien. In diesem Zusammenhang ist der Blogeintrag von Ben Rockwood lesenswert.

Zum Schluss sei noch gesagt, dass sich die Aktion für meine Daten gelohnt hat. Ich habe zfs compression=on .... gesetzt, also keine gzip-Kompression benutzt.