web-dev-qa-db-ja.com

C#でSIDからアカウント名に変換するにはどうすればよいですか

ディレクトリをスキャンして情報を収集するC#アプリケーションがあります。各ファイルのアカウント名を表示したいと思います。 FileInfoオブジェクトのSIDを取得して、ローカルシステムでこれを行うことができます。

string GetNameFromSID( SecurityIdentifier sid )
{
    NTAccount ntAccount = (NTAccount)sid.Translate( typeof( NTAccount ) );
    return ntAccount.ToString();
}

ただし、おそらくTranslate()関数はローカルユーザーアカウントでのみ機能するため、これはネットワーク上のファイルに対しては機能しません。 SIDでLDAPルックアップを実行できると思ったので、次のことを試しました。

string GetNameFromSID( SecurityIdentifier sid )
{
    string str = "LDAP://<SID=" + sid.Value + ">";
    DirectoryEntry dirEntry = new DirectoryEntry( str );
    return dirEntry.Name;
}

これは、「dirEntry.Name」へのアクセスが数秒間ハングし、ネットワークをオフにしてクエリを実行しているように見えますが、System.Runtime.InteropServices.COMExceptionをスローするように動作するようです。

任意のファイルまたはSIDのアカウント名を取得する方法を知っている人はいますか?ネットワークやLDAPなどについてはあまり知りません。おそらく使用するはずのDirectorySearcherというクラスがありますが、ドメイン名が必要です。それを取得する方法もわかりません。スキャンしているディレクトリへのパスだけです。

前もって感謝します。

51
Sam Hopkins

SecurityReferenceオブジェクトのTranslateメソッドは、非ローカルSIDで機能しますが、ドメインアカウントに対してのみ機能します。別のマシンのローカルアカウントまたは非ドメインセットアップでは、ルックアップの実行が必要な特定のマシン名を指定するLookupAccountSid関数をPInvokeする必要があります。

18
Stephen Martin

良い答えはこちらをご覧ください:

SIDで表示ユーザー名を解決する最良の方法?

その要点は次のとおりです。

string sid="S-1-5-21-789336058-507921405-854245398-9938";
string account = new System.Security.Principal.SecurityIdentifier(sid).Translate(typeof(System.Security.Principal.NTAccount)).ToString();

このアプローチは、Active Directory上の非ローカルSIDに対して有効です。

39
Chris

System.DirectoryServices.AccountManagement.UserPrincipalクラス( msdn link )には、SIDをユーザーオブジェクトに変換する静的関数FindByIdentityがあります。ローカルマシンまたはLDAP/Active Directoryサーバーの両方に対して機能する必要があります。 Active Directoryに対してのみ使用しました。

IISで使用した例を次に示します。

// Set the search context to a specific domain in Active Directory
var searchContext = new PrincipalContext(ContextType.Domain, "YOURDOMAIN", "OU=SomeOU,DC=YourCompany,DC=com");
// get the currently logged in user from IIS
MembershipUser aspUser = Membership.GetUser();
// get the SID of the user (stored in the SecurityIdentifier class)
var sid = aspUser.ProviderUserKey as System.Security.Principal.SecurityIdentifier;
// get the ActiveDirectory user object using the SID (sid.Value returns the SID in string form)
var adUser = UserPrincipal.FindByIdentity(searchContext, IdentityType.Sid, sid.Value);
// do stuff to user, look up group membership, etc.
6
Bakanekobrain

C#で、ユーザーSIDを取得し、次の方法で文字列変数に割り当てます。

string strUser = System.Security.Principal.WindowsIdentity.GetCurrent().User.ToString();

UserNameに解決する機能は文字列をサポートしているため、文字列を使用する必要があります。つまり、var varUserを使用すると、名前空間エラーが発生します。

string strUserName = new System.Security.Principal.SecurityIdentifier(strUser).Translate(typeof(System.Security.Principal.NTAccount)).ToString();
3
J Weezy

すばらしいです。ここからいくつかのLookupAccountSid()コードを作成しました。

http://www.pinvoke.net/default.aspx/advapi32.LookupAccountSid

ホスト名を自分で入力する必要がありましたが、それはうまくいきました。 UNCパスの場合、最初のコンポーネントのみを取得できます。マップされたドライブの場合、このコードを使用してパスをUNCに変換します。

http://www.wiredprairie.us/blog/index.php/archives/22

それはうまくいくようですので、UNCパスの最初のコンポーネントがホスト名ではないという状況を誰かが考え出さない限り、それが私がやる方法です...

ご協力ありがとうございます。

1
Sam Hopkins

おっと、Active Directory環境にいない可能性があるため、LDAP呼び出しが機能していない可能性があります。この場合、各マシンが独自のIDストアを担当します。また、コードを実行しているマシンはリモートマシンでのみ意味のあるSIDを解決する方法を知らないため、最初のコードサンプルはネットワーク上で機能しません。

マシンがActive Directoryの一部であるかどうかを本当に確認する必要があります。これは、ログオンプロセス中にわかります。または、「マイコンピュータ」を右クリックして確認し、「プロパティ」、「コンピュータ名」タブを選択して、コンピュータがドメインの一部であるかどうかを確認します。

1
barneytron

ユーザーの言語設定に関係なく機能する次のようなコードを使用して、「全員」などの特別なアカウントのアカウント名を取得することもできます。

   SecurityIdentifier everyoneSid = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
   string everyone = everyoneSid.Translate(typeof(System.Security.Principal.NTAccount)).ToString();
1
jm.

現在のドメインを取得します。

System.DirectoryServices.ActiveDirectory.Domain.GetCurrentDomain();

Ldapおよびドメイン名からディレクトリエントリを取得します。

DirectoryEntry de = new DirectoryEntry(string.Format("LDAP://{0}", domain));

ActiveDirectoryMembershipProvider ActiveDirectoryMembershipUserからsidを取得します。

ActiveDirectoryMembershipUser user = (ActiveDirectoryMembershipUser)Membership.GetUser();
var sid = (SecurityIdentifier)user.ProviderUserKey;

SecurityIdentifierからユーザー名を取得します。

(NTAccount)sid.Translate(typeof(NTAccount));

ドメインディレクトリエントリとユーザー名を使用して、アクティブディレクトリでディレクトリ検索を実行します。

DirectorySearcher search = new DirectorySearcher(entry);
        search.Filter = string.Format("(SAMAccountName={0})", username);
        search.PropertiesToLoad.Add("Name");
        search.PropertiesToLoad.Add("displayName");
        search.PropertiesToLoad.Add("company");
        search.PropertiesToLoad.Add("homePhone");
        search.PropertiesToLoad.Add("mail");
        search.PropertiesToLoad.Add("givenName");
        search.PropertiesToLoad.Add("lastLogon");
        search.PropertiesToLoad.Add("userPrincipalName");
        search.PropertiesToLoad.Add("st");
        search.PropertiesToLoad.Add("sn");
        search.PropertiesToLoad.Add("telephoneNumber");
        search.PropertiesToLoad.Add("postalCode");
        SearchResult result = search.FindOne();
        if (result != null)
        {
            foreach (string key in result.Properties.PropertyNames)
            {
                // Each property contains a collection of its own
                // that may contain multiple values
                foreach (Object propValue in result.Properties[key])
                {
                    outputString += key + " = " + propValue + ".<br/>";
                }
            }
        }

Active Directoryのデータに応じて、出力にさまざまな応答が返されます。

必要なすべてのユーザープロパティを備えたサイトを次に示します。

0
tombmedia

これはスタンパーです。あなたはActive Directory環境にいますか?チェックしてるだけ:)

とにかく、sid.Valueでバインドする代わりに、

string str = "LDAP://<SID=" + sid.Value + ">";

SIDのバイト配列を オクテット文字列 に変換して、代わりにバインドしてみます。

良い例があります here 78ページ。正直に言うと、私は以前にSIDとのバインドを試みたことがありません。しかし、ユーザーのGUID

幸運を祈ります。

0
barneytron