D'après mon commentaire d'origine, il semble que la SUSER_SID
fonction ne saisit que le sid enregistré lors de la création de la connexion et ne fait pas de requête sur Active Directory (cela a du sens, car cela pourrait être coûteux - j'ai même essayé de redémarrer le service serveur).
Voici une application console C # qui accomplit la tâche, vous permettant d'auditer les connexions qui seront supprimées avant qu'elles ne soient réellement supprimées.
Cette application nécessite .NET 3.5 ou supérieur pour fonctionner, et en théorie, elle pourrait être placée dans un script PowerShell (je suis beaucoup plus à l'aise avec la programmation directe).
Pour supprimer toutes les connexions des comptes d'utilisateurs locaux / machine du serveur, vous devrez exécuter cette application sur la machine serveur et coder en dur la ContextType
variable (je l'ai comme ça pour tester sur mon ordinateur personnel non lié au domaine ). Sinon, vous pouvez l'exécuter à partir de n'importe quelle machine du même domaine que le serveur, qui a également accès au serveur.
Je vais poster ceci sur mon blog après avoir externalisé les paramètres et nettoyé un peu le code, donc quand je fais ça, je vais éditer ce post. Mais cela vous permettra de commencer maintenant.
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;
}
}
}
}
Vous pouvez exploiter xp_logininfo pour ce processus. Cette procédure stockée étendue peut être utilisée pour fournir des informations à partir des connexions Active Directory pour Windows dans SQL Server. La procédure renvoie une erreur si aucune connexion n'existe, nous pouvons donc placer un bloc TRY / CATCH autour pour fournir SQL pour les connexions qui ne sont plus valides lorsque les erreurs de procédure:
Avec la façon dont le script fonctionne, vous devrez définir la variable @domain sur le domaine que vous vérifiez. La requête du curseur ne filtrera que sur les connexions Windows (pas sur les groupes) dans ce domaine. Vous obtiendrez les résultats de la requête pour toutes les connexions valides, mais les instructions drop seront imprimées avec les messages. J'ai opté pour l'approche d'impression au lieu d'exécuter réellement le SQL afin que vous puissiez consulter et valider les résultats avant de supprimer les connexions.
Remarque, ce script ne créera que vos relevés de connexion de dépôt. Les utilisateurs devront toujours être supprimés des bases de données respectives. La logique appropriée peut être ajoutée à ce script si nécessaire. En outre, cela devra être exécuté dans votre environnement SQL 2005, car cette logique n'est pas prise en charge dans SQL 2000.
la source
Xp_logininfo
renvoie l'erreur 0x5, ce qui signifie que l'accès est refusé, pour un compte de domaine valide. Cela entraîne la suppression de chaque compte de domaine répertorié. Lasp_validatelogins
procédure stockée produira les mêmes résultats, que le compte de service SQL Server soit un compte local ou un compte de domaine.Vous pouvez faire un drop et recréer dans une transaction comme celle-ci:
Si l'erreur que vous obtenez est la suivante:
Windows NT user or group 'DOMAIN\testuser' not found. Check the name again.
votre identifiant Windows n'existe plus. Cependant, il existe de nombreuses raisons pour lesquelles la suppression elle-même échouera (par exemple, les autorisations accordées par la connexion). Vous devrez les suivre manuellement.la source
TRY ... CATCH
a été introduit dans SQL 2005. stackoverflow.com/questions/5552530/sql-server-2000-try-catch