Es ist keine schlechte Idee, die Kennwörter von Dienst- und Taskausführungskonten zu ändern. Vielfach sind diese nämlich mit einem, naja, Startkennwort ausgestattet, das nicht den hohen Sicherheitsanforderungen für solche Konten entspricht. Doch fast niemand traut sich ran, denn es gibt so eine tolle Ausrede: Wer weiß, wo dieses Konto überall genutzt wird, und nachher läuft da gar nichts mehr!
Aber so schwierig ist es gar nicht, so etwas sicher herauszufinden. Wie so oft, hilft auch hier eine Skriptlösung. Betrachten wir dazu getrennt die Dienstkonten und die Konten, mit denen Geplante Tasks laufen.
Teil 1: Dienstkonten
Dienstkonten lassen sich gut mit WMI abfragen und dann in eine Datenbank schreiben. Alles, was man dazu benötigt, ist:
- Ein SQL Server (die Express Edition reicht hier vollkommen)
- Ein Konto, das auf die Server zugreifen darf, idealerweise mit Adminrechten
Auf dem SQL Server richtet man eine Datenbank beliebigen Namens ein, z.B. so:
CREATE DATABASE MeineAdminDB
Dann führt man folgendes Skript in einem Admintool für den SQL Server aus (SQL Server Management Studio, -Express oder einfach Ofarim):
USE MeineAdminDB
CREATE TABLE [dbo].[Win32Service] (
[idService] [int] IDENTITY (1, 1) NOT NULL ,
[Caption] [nvarchar] (255) COLLATE Latin1_General_CI_AS NULL ,
[Name] [nvarchar] (255) COLLATE Latin1_General_CI_AS NULL ,
[PathName] [ntext] COLLATE Latin1_General_CI_AS NULL ,
[StartMode] [varchar] (50) COLLATE Latin1_General_CI_AS NULL ,
[StartName] [nvarchar] (255) COLLATE Latin1_General_CI_AS NULL ,
[State] [varchar] (50) COLLATE Latin1_General_CI_AS NULL ,
[SystemName] [nvarchar] (50) COLLATE Latin1_General_CI_AS NULL ,
[RowDate] [smalldatetime] NULL ,
[UserName] [nvarchar] (50) COLLATE Latin1_General_CI_AS NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Damit hat die Datenbank die nötige Tabelle, um die Daten aufzunehmen. Nun führt man das folgende Skript auf allen Servern aus, deren Dienste inventarisiert werden sollen. Eine Hilfestellung dazu gebe ich unter dem Code. Im Code ändere man in den Zeilen 61 und 62 den Namen des SQL-Servers und der Datenbank.
-
""""""""""""""""""""""""""'
-
' ServiceInv.vbs
-
' Dienst-Mini-Inventarisierung über WMI
-
'
-
' Version: 0.1
-
' Datum: 22.12.2005
-
' Autor: Nils Kaczenski (Vorname at Nachname .de)
-
' Letzte Änderungen:
-
'
-
' Nils Kaczenski stellt dieses Skript ohne jede
-
' Gewährleistung zur Verfügung.
-
' Die Verwendung geschieht auf eigene Gefahr.
-
'
-
""""""""""""""""""""""""""'
-
-
Option Explicit
-
Dim colItems '
-
Dim dtmCompInDB '
-
Dim intGesamtzahl '
-
Dim intZeilenzahl '
-
Dim objArgs '
-
Dim objConn '
-
Dim objItem
-
Dim objRS '
-
Dim objWMIService
-
Dim objWSHNetwork '
-
Dim strBenutzer '
-
Dim strCaption '
-
Dim strComputer '
-
Dim strConn '
-
Dim strDatenbank '
-
Dim strDBServer '
-
Dim strLogmode '
-
Dim strName '
-
Dim strPathName '
-
Dim strSQL '
-
Dim strStartMode '
-
Dim strStartName '
-
Dim strState '
-
-
strLogmode = "error"
-
-
say Now & ": Starte Dienst-Inventarisierung …"
-
-
On Error Resume Next
-
-
' Computernamen herausfinden
-
Set objWSHNetwork = CreateObject("Wscript.Network")
-
strComputer = objWSHNetwork.ComputerName
-
strBenutzer = objWSHNetwork.UserDomain & "\" & objWSHNetwork.UserName
-
If checkit("Fehler beim Zugriff auf WSHNetwork!") Then WScript.Quit
-
-
' falls Computername per Argument übergeben, wird dieser genommen:
-
Set objArgs = WScript.Arguments
-
If objArgs.Count <> 0 Then
-
strComputer = objArgs(0)
-
End If
-
saydebug strComputer
-
-
' Datenbank-Daten
-
strDBServer = "SQL01"
-
strDatenbank = "MeineAdminDB"
-
-
' Objekte
-
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
-
If checkit("Fehler beim Zugriff auf WMI!") Then WScript.Quit
-
-
Set objConn = CreateObject("ADODB.Connection")
-
Set objRS = CreateObject("ADODB.Recordset")
-
If checkit("Fehler beim ADODB-Zugriff!") Then WScript.Quit
-
-
' Datenbank-Verbindung
-
strConn = "Provider=SQLOLEDB;Integrated Security=SSPI;" _
-
& "Initial Catalog=" & strDatenbank _
-
& ";Data Source=" & strDBServer
-
objConn.Open strConn
-
If checkit("Fehler beim Verbinden mit der Datenbank!") Then WScript.Quit
-
-
' prüfen, ob aktuelle Daten da sind
-
strSQL = "select max(RowDate) as datum from dbo.Win32Service where " _
-
& "SystemName='" & strComputer & "'"
-
objRS.Open strSQL, objConn
-
If checkit("Fehler beim Abfragen der Datenbank!") Then WScript.Quit
-
dtmCompInDB = objRS("Datum")
-
If DateDiff("d", dtmCompInDB, Now) < 7 Then
-
' Daten sind aktuell – Skript verlassen
-
say "Vorhandene Daten sind aktuell."
-
say "Beende Service-Inventarisierung."
-
WScript.Quit
-
End If
-
objRS.Close
-
-
' vorhandene Daten dieses Rechners löschen
-
strSQL = "delete from Win32Service where SystemName='" & strComputer & "'"
-
objConn.Execute strSQL, intZeilenzahl
-
If checkit("Fehler beim Löschen der Inventardaten!") Then WScript.Quit
-
say intZeilenzahl & " Zeilen aus der Datenbank gelöscht."
-
-
' WMI-Daten auslesen
-
Set colItems = objWMIService.ExecQuery("Select * from Win32_Service",,48)
-
If checkit("Fehler beim Auslesen der WMI-Daten!") Then WScript.Quit
-
-
' WMI-Daten durchlaufen
-
For Each objItem In colItems
-
strCaption = objItem.Caption
-
strName = objItem.Name
-
strPathName = objItem.PathName
-
strStartMode = objItem.StartMode
-
strStartName = objItem.StartName
-
strState = objItem.State
-
-
If checkit("Fehler beim Durchlaufen der WMI-Daten, Item " & intGesamtzahl & "!") Then WScript.Quit
-
-
' SQL-Kommando aufbauen
-
strSQL = "insert dbo.Win32Service (" _
-
& " SystemName, Caption, [Name], PathName, StartMode," _
-
& " StartName, State, RowDate, Username " _
-
& ") values ( '" _
-
& strComputer & "', '" & strCaption & "', '" & strName _
-
& "', '" & strPathName & "', '" & strStartMode _
-
& "', '" & strStartName & "', '" & strState & "', '" _
-
& Now & "', '" & strBenutzer & "') "
-
-
saydebug strSQL
-
-
' Daten in die Datenbank schreiben
-
objConn.Execute strSQL, intZeilenzahl
-
If checkit("Fehler beim Schreiben in die Datenbank!") Then WScript.Quit
-
intGesamtzahl = intGesamtzahl + intZeilenzahl
-
Next
-
-
objConn.Close
-
On Error Goto 0
-
say intGesamtzahl & " Zeilen in die Datenbank geschrieben."
-
say "Service-Inventarisierung ist fertig."
-
-
-
Function checkit(strNachricht)
-
checkit = False
-
If Err.number <>0 Then
-
strNachricht = strNachricht & " [" & Err.description & " (" & Err.number & ")]"
-
sayerror strNachricht
-
Err.clear
-
checkit=True
-
End If
-
End Function
-
-
-
' Universelle Ausgabefunktion
-
Sub say(s)
-
saynb s & VbCrLf
-
End Sub
-
-
' Ausgabe ohne Zeilenumbruch
-
Sub saynb(s)
-
WScript.echo s
-
End Sub
-
-
' Ausgabe als Fehlermeldung
-
Sub sayerror(s)
-
say "Fehler (" & Date & ", " & Time & "): " & s
-
End Sub
-
-
' Ausgabe als Warnung
-
Sub sayalert(s)
-
say "Warnung (" & Date & ", " & Time & "): " & s
-
End Sub
-
-
-
' Debug-Ausgabe
-
Sub saydebug(s)
-
If strLogmode = "debug" Then
-
say s
-
End If
-
End Sub
Dieses Skript speichert man als "ServiceInv.vbs" und ruft es folgendermaßen – mit ausreichenden Rechten ausgestattet – auf, um den Server "MeinServer" zu inventarisieren:
cscript C:\Pfad\ServiceInv.vbs MeinServer
Dies lässt sich für alle Server gut über ein Batch erledigen (das man mit Excel erzeugen kann), das z.B. so aussieht:
cscript C:\Pfad\ServiceInv.VBS SERVER001
cscript C:\Pfad\ServiceInv.VBS SERVER002
cscript C:\Pfad\ServiceInv.VBS SERVER003
Sollte das Skript einen Server nicht per WMI erreichen, kann das mehrere Gründe haben: Der Server läuft gar nicht, eine Firewall hindert die WMI-Ansprache oder es gibt gar kein WMI auf der Maschine. Die meisten Windows-Server sollten aber klaglos ihre Daten ausgeben.
Hernach stehen die Daten zu den Dienstkonten in der Datenbank. Folgende SQL-Abfrage im SQL-Client (siehe oben) gibt eine schnelle Übersicht, welches Dienstkonto wo verwendet wird. Dabei blendet es die lokalen Standardkonten gleich aus, weil diese ja nicht von der Kennwortänderung betroffen sind:
-
SELECT StartName
-
, Caption
-
, SystemName
-
, StartMode
-
FROM Win32Service
-
WHERE StartName NOT IN (
-
'LocalSystem'
-
, 'NT AUTHORITY\LocalService'
-
, 'NT AUTHORITY\NetworkService')
-
ORDER BY StartName, SystemName, Caption
Teil 2: Konten für Geplante Tasks
Mit den Geplanten Tasks ist es leider nicht so einfach, denn diese lassen sich nicht per WMI abfragen – jedenfalls wenn sie mit dem Taskplaner eingerichtet wurden. WMI kann nur die "alten" AT-Tasks verarbeiten (die aber zu Recht niemand mehr will).
Hier hilft das Kommandozeilentool schtasks.exe, das auf Rechnern ab XP und Windows Server 2003 vorhanden ist. Gemeinsam mit psexec (von Sysinternals) wird eine brauchbare Lösung daraus. Man baue sich also (z.B. wieder mit Excel, siehe oben) ein Batch folgender Art:
"C:\Daten\psexec.exe" \\SERVER001 schtasks /query /V /FO csv|find /i "Domain"
"C:\Daten\psexec.exe" \\SERVER002 schtasks /query /V /FO csv|find /i "Domain"
"C:\Daten\psexec.exe" \\SERVER003 schtasks /query /V /FO csv|find /i "Domain"
Dabei steht "Domain" für den Namen der eigenen Domäne, den man hier ersetzt. Die Ausgabe dieses Batches leitet man in eine Datei um. Die Kommandos verbinden sich mit jedem Remoteserver und geben über das Piping mit find nur die Tasks zurück, in denen der Name der Domäne auftaucht – üblicherweise dann, wenn ein Domänenkonto für den Task angegeben ist. In der erzeugten Ausgabedatei findet man also nun genau die Tasks, die man nach der Kennwortänderung bearbeiten muss.
Verwandte Beiträge:
- Systeme mit Windows Server 2003 R2 identifizieren
Es ist nicht ganz leicht, im Rahmen einer Dokumentation im Netzwerk die Server zu identifizieren, die mit Windows Server 2003... - Ein AD-Attribut zu einem Logon-Namen herausfinden
Das folgende Skript gibt den Wert eines beliebigen Attributs aus dem Active Directory für einen User zurück, dessen Logon-Name (SAM-Name,... - BGInfo um eigene Datenfelder erweitern
BGInfo von Sysinternals ist für viele Windows-Admins ein unverzichtbares Werkzeug. Es blendet Konfigurationsinformationen über den lokalen Rechner in das Hintergrundbild... - Standardkennwort bei Benutzern prüfen
Manchmal werden Benutzer durch eine Migration, beim Neuanlegen oder auch beim Zurücksetzen des Kennwortes mit einem Standardkennwort versehen. Ab und... - AD-Informationen schnell auslesen
Neben eineAm klassischen ADSI-Skript gibt es eine relativ einfache Möglichkeit, Informationen aus dem Active Directory auszulesen. Hierzu lässt sich das...


25. Dezember 2008, 10:00 Uhr
http://faq-o-matic.net/?p=1014


