Theo nhận xét ban đầu của tôi, có vẻ như SUSER_SID
chức năng chỉ lấy bất cứ thứ gì được ghi lại khi đăng nhập được tạo và không thực sự truy vấn Active Directory (có nghĩa là nó có thể tốn kém - tôi thậm chí đã thử khởi động lại dịch vụ máy chủ).
Dưới đây là một ứng dụng bảng điều khiển C # hoàn thành nhiệm vụ, cho phép bạn kiểm tra các thông tin đăng nhập sẽ bị hủy trước khi chúng thực sự bị hủy.
Ứng dụng này yêu cầu .NET 3.5 trở lên để chạy và về lý thuyết, nó có thể được đưa vào tập lệnh PowerShell (Tôi thoải mái hơn nhiều với lập trình trực tiếp).
Để xóa bất kỳ thông tin đăng nhập nào của tài khoản người dùng cục bộ / máy chủ khỏi máy chủ, bạn sẽ cần chạy ứng dụng này trên máy chủ và mã hóa ContextType
biến số (tôi có nó như thế để kiểm tra trên máy tính gia đình không tham gia miền của tôi ). Mặt khác, bạn có thể chạy nó từ bất kỳ máy nào trong cùng miền với máy chủ, cũng có quyền truy cập vào máy chủ.
Tôi sẽ đăng bài này lên blog của mình sau khi đưa ra các tham số và làm sạch mã một chút, vì vậy khi tôi làm điều đó, tôi sẽ chỉnh sửa bài đăng này. Nhưng điều này sẽ giúp bạn bắt đầu ngay bây giờ.
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;
}
}
}
}