Según mi comentario original, parece que la SUSER_SID
función solo toma cualquier sid que se registró cuando se creó el inicio de sesión, y en realidad no consulta Active Directory (tiene sentido, ya que podría ser costoso, incluso intenté reiniciar el servicio del servidor).
Aquí hay una aplicación de consola C # que realiza la tarea, permitiéndole auditar los inicios de sesión que se eliminarán antes de que realmente se eliminen.
Esta aplicación requiere .NET 3.5 o superior para ejecutarse, y en teoría se podría incluir en un script de PowerShell (estoy mucho más cómodo con la programación directa).
Para eliminar todos los inicios de sesión de las cuentas de usuario locales / de la máquina del servidor, deberá ejecutar esta aplicación en la máquina del servidor y codificar la ContextType
variable (lo tengo así para probar en mi computadora hogareña no unida al dominio) ) De lo contrario, puede ejecutarlo desde cualquier máquina en el mismo dominio que el servidor, que también tiene acceso al servidor.
Voy a publicar esto en mi blog después de externalizar los parámetros y limpiar un poco el código, así que cuando lo haga, editaré esta publicación. Pero esto te ayudará a comenzar ahora.
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;
}
}
}
}
Puede aprovechar xp_logininfo para este proceso. Este procedimiento almacenado extendido se puede usar para proporcionar información de Active Directory para inicios de sesión de Windows en SQL Server. El procedimiento devuelve un error si no existe un inicio de sesión, por lo que podemos poner un bloque TRY / CATCH a su alrededor para proporcionar SQL para inicios de sesión que ya no son válidos cuando el procedimiento falla:
Con la forma en que funciona el script, deberá establecer la variable @dominio en el dominio que esté comprobando. La consulta del cursor solo se filtrará en los inicios de sesión de Windows (no en los grupos) dentro de ese dominio. Obtendrá resultados de consultas para todos los inicios de sesión válidos, pero las declaraciones de caída se imprimirán con los mensajes. Seguí el enfoque de impresión en lugar de ejecutar realmente el SQL para que pueda revisar y validar los resultados antes de soltar los inicios de sesión.
Tenga en cuenta que este script solo creará sus declaraciones de inicio de sesión. Los usuarios aún deberán ser eliminados de las respectivas bases de datos. La lógica apropiada se puede agregar a este script según sea necesario. Además, esto deberá ejecutarse en su entorno SQL 2005, ya que esta lógica no es compatible con SQL 2000.
fuente
Xp_logininfo
devolverá el error 0x5, que significa acceso denegado, para una cuenta de dominio válida. Esto da como resultado que todas las cuentas de dominio enumeradas se eliminen. Elsp_validatelogins
procedimiento almacenado producirá los mismos resultados tanto si la cuenta de servicio de SQL Server es una cuenta local como una cuenta de dominio.Puede hacer una caída y recrear en una transacción como esta:
Si el error que obtiene es este:
Windows NT user or group 'DOMAIN\testuser' not found. Check the name again.
entonces su inicio de sesión de Windows ya no existe. Sin embargo, hay varias razones por las que la caída fallará (por ejemplo, permisos otorgados por el inicio de sesión). Deberá hacer un seguimiento de ellos manualmente.fuente
TRY ... CATCH
se introdujo en SQL 2005. stackoverflow.com/questions/5552530/sql-server-2000-try-catch