Meinem ursprünglichen Kommentar zufolge scheint die SUSER_SID
Funktion nur die Seite zu erfassen, die beim Erstellen der Anmeldung aufgezeichnet wurde, und Active Directory nicht abzufragen (sinnvoll, da dies teuer sein kann - ich habe sogar versucht, den Serverdienst neu zu starten).
Hier ist eine C # -Konsolenanwendung, die die Aufgabe ausführt und es Ihnen ermöglicht, die Anmeldungen zu überwachen, die gelöscht werden, bevor sie tatsächlich gelöscht werden.
Für diese App ist .NET 3.5 oder höher erforderlich, und theoretisch kann sie in ein PowerShell-Skript eingefügt werden (ich bin mit der direkten Programmierung viel besser vertraut).
Um alle Anmeldungen lokaler / Computer-Benutzerkonten vom Server zu entfernen, müssen Sie diese Anwendung auf dem Server ausführen und die ContextType
Variable fest codieren (ich habe sie so zum Testen auf meinem Heimcomputer, der keiner Domäne angehört ). Andernfalls können Sie es von jedem Computer in derselben Domäne wie der Server ausführen, der auch Zugriff auf den Server hat.
Ich werde dies in meinem Blog veröffentlichen, nachdem ich die Parameter externalisiert und den Code ein wenig bereinigt habe. Wenn ich das mache, werde ich diesen Beitrag bearbeiten. Aber damit können Sie jetzt loslegen.
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.DirectoryServices.AccountManagement;
using System.Security.Principal;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string connectionString = @"Data Source=.\SQL2008R2DEV;Initial Catalog=master;Integrated Security=SSPI;";
ContextType domainContext = Environment.UserDomainName == Environment.MachineName ? ContextType.Machine : ContextType.Domain;
IList<string> deletedPrincipals;
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
deletedPrincipals = _GetDeletedPrincipalsFromServer(conn, domainContext);
}
if (deletedPrincipals.Count > 0)
{
Console.WriteLine("Logins that will be dropped:");
foreach (string loginName in deletedPrincipals)
Console.WriteLine(loginName);
Console.WriteLine();
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
else
Console.WriteLine("No logins with deleted principals.");
if (deletedPrincipals.Count > 0)
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
_DropDeletedPrincipalLoginsFromServer(conn, deletedPrincipals);
}
Console.WriteLine("Logins dropped successfully.");
}
Console.WriteLine();
Console.WriteLine("Press Enter to continue.");
Console.ReadLine();
}
private static void _DropDeletedPrincipalLoginsFromServer(IDbConnection conn, IList<string> loginNames)
{
if (loginNames.Count == 0)
return;
StringBuilder sb = new StringBuilder();
foreach (string loginName in loginNames)
sb.AppendFormat("DROP LOGIN {0};", loginName); // This was escaped on the way out of SQL Server
IDbTransaction transaction = conn.BeginTransaction();
IDbCommand cmd = conn.CreateCommand();
cmd.Transaction = transaction;
cmd.CommandText = sb.ToString();
try
{
cmd.ExecuteNonQuery();
transaction.Commit();
}
catch
{
try
{
transaction.Rollback();
}
catch { }
throw;
}
}
private static IList<string> _GetDeletedPrincipalsFromServer(IDbConnection conn, ContextType domainContext)
{
List<string> results = new List<string>();
IDbCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT sid, QUOTENAME(loginname) AS LoginName FROM sys.syslogins WHERE isntname = 1;";
IDataReader dr = null;
try
{
dr = cmd.ExecuteReader(CommandBehavior.SingleResult);
while (dr.Read())
{
if (!_PrincipalExistsBySid((byte[])dr["sid"], domainContext))
results.Add((string)dr["LoginName"]);
}
}
finally
{
if ((dr != null) && !dr.IsClosed)
dr.Close();
}
return results;
}
private static bool _PrincipalExistsBySid(byte[] principalSid, ContextType domainContext)
{
SecurityIdentifier sid = new SecurityIdentifier(principalSid, 0);
if (sid.IsWellKnown) return true;
using (PrincipalContext pc = new PrincipalContext(domainContext))
{
return AuthenticablePrincipal.FindByIdentity(pc, IdentityType.Sid, sid.Value) != null;
}
}
}
}
Sie können xp_logininfo für diesen Prozess nutzen. Diese erweiterte gespeicherte Prozedur kann verwendet werden, um Informationen aus Active Directory für Windows-Anmeldungen in SQL Server bereitzustellen. Die Prozedur gibt einen Fehler zurück, wenn keine Anmeldung vorhanden ist. Daher können wir einen TRY / CATCH-Block um sie setzen, um SQL für Anmeldungen bereitzustellen, die bei Prozedurfehlern nicht mehr gültig sind:
Bei der Funktionsweise des Skripts müssen Sie die Variable @domain auf die Domäne festlegen, die Sie überprüfen. Die Cursorabfrage filtert nur nach Windows-Anmeldungen (nicht nach Gruppen) innerhalb dieser Domäne. Sie erhalten Abfrageergebnisse für alle gültigen Anmeldungen, aber Drop-Anweisungen werden mit den Nachrichten gedruckt. Ich habe mich für den Druckansatz entschieden, anstatt SQL tatsächlich auszuführen, damit Sie die Ergebnisse überprüfen und validieren können, bevor Sie die Anmeldungen tatsächlich löschen.
Beachten Sie, dass dieses Skript nur Ihre Drop-Login-Anweisungen erstellt. Benutzer müssen weiterhin aus den jeweiligen Datenbanken entfernt werden. Die entsprechende Logik kann bei Bedarf zu diesem Skript hinzugefügt werden. Dies muss auch in Ihrer SQL 2005-Umgebung ausgeführt werden, da diese Logik in SQL 2000 nicht unterstützt wird.
quelle
Xp_logininfo
wird für ein gültiges Domänenkonto der Fehler 0x5 zurückgegeben, was bedeutet, dass der Zugriff verweigert wurde. Dies führt dazu, dass jedes Domänenkonto gelöscht wird. Diesp_validatelogins
gespeicherte Prozedur führt zu denselben Ergebnissen, unabhängig davon, ob es sich bei dem SQL Server-Dienstkonto um ein lokales Konto oder ein Domänenkonto handelt.Sie können eine Transaktion wie folgt löschen und neu erstellen:
Wenn der folgende Fehler auftritt:
Windows NT user or group 'DOMAIN\testuser' not found. Check the name again.
Ihr Windows-Login existiert nicht mehr. Es gibt jedoch eine Reihe von Gründen, warum das Löschen selbst fehlschlägt (z. B. durch die Anmeldung erteilte Berechtigungen). Sie müssen diese manuell nachverfolgen.quelle
TRY ... CATCH
wurde in SQL 2005 eingeführt. stackoverflow.com/questions/5552530/sql-server-2000-try-catch