[ADSI じゃないけど AD 系] DsGetDcName() - DC 様の 1 ゲトーレースの行方とは!?

皆様ごきげんよう、ういこです。

やっぱり調子が優れないです。何かの祟りでしょうか。それとも誰かから恨まれてるのでしょうか。思い当たる点が多すぎていちいち覚えてられないんですが、どうも集中力に欠けるので、今日はドメインコントローラを探す DsGetDcName() API を C# と VB.NET に激しく移植してみましたのでこれをもって今日の記事に代えさせてください…。

面白いので、可能な限り VB.NET と C# で同じ処理にしてみました。さっき、気分転換にだーっと作ったので、何か間違ってたりしたらこっそり教えてください。

もちろん今回もダウンロード可能な Visual Studio ソリューションつきです。Exe もついてるので、実行もすぐできます。でも、やる気のないソリューション名なのは勘弁な。 (※ 特攻野郎 A チーム風)

ダウンロードはここから

(ダウンロード ファイル : JPILMBLG(05Mar2009).zip)

 

ご注意ください

※ 以降のコード説明上のコードは、弊社にてその動作を保証するものではございません。

※ ご使用の際には、御社システムに合わせて修正して頂き、十分なテストを実施して頂き

※ ます様お願い致します。

ちなみに、今回使うDsGetDCName は、先日のぴろとくんのターミナル サービス API の記事で触れている関数の引数に必要となる NetBIOS 名を取得することができるです。おおコラボが成立した。よかったよかった。

そして Net 系 API は実は私たちのサポート担当ではなくて別のチームの担当エリアだったりします。製品サポート部隊は各テクノロジごとにエキスパート制をとっているからですね。

Visual Studio のバージョンについて

Visual Studio 2005 + Microsoft Update で最新の状態にしてます。もしかしたら、ソリューションを開く際に必要になるかもなので参考までに作成環境の VS のバージョン情報をはっておきます。ダウンロードできるサンプルでは、習性で、System.DirectoryServices 名前空間をつけてしまってますが取っ払っても動きます。

 

DsGetDcName 関数について

DsGetDcName() は、複数のドメイン コントローラ (DC) が存在する場合、最も早く応答を返すドメイン コントローラの情報を得ることができます。応答した DC はこの API が呼ばれた ”その時点” で一番早く応答を返したものです。1げとーですね。

つまり、これが意味するのは、DsGetDcName()  以降、 DC へ再度アクセスしたい状況が出てきたとしても、この DsGetDcName() で返された DC が常に一番早くアクセスできる DC とは限らないということです。要は常に一番速い応答を返す DC であることを意味するものではないということですね。さらに処理を記述していく場合設計によっては、この点を意識する必要があるかもしれませんね。

 

なお、第 4 引数の “DomainGuid” は、どうやってドメインのぐいどなんてとるのかわかんないよ!!って方いらっしゃるかと思いますが、C# で null もしくは VB.NET では Nothing を指定することもできます。

また、ネットワーク管理系 API 使用後は、必ず NetApiBufferFree() を呼び出し、領域を開放する必要があることに注意してください。

Windows におけるドメイン コントローラの検索方法については以下が参考になると思います。こちらも参考にぜひ、ごらんになってみてくださいね。

Windows でのドメインコントローラの検索方法

https://support.microsoft.com/kb/247811/ja

以下は MSDN の関数の説明です。フラグの使い方などはこちらから~。

DsGetDcName 関数

https://msdn.microsoft.com/en-us/library/ms675983(VS.85).aspx

NetApiBufferFree 関数

https://msdn.microsoft.com/ja-jp/library/cc401529.aspx

※ ちなみに、お友達関数に NetGetDcName() というのがいますが、こいつは Windows 2000 以降だと DC の情報を返すそうです。

◆コードサンプル

C# の場合

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using System.Runtime.InteropServices;

namespace WindowsApplication3

{

    public partial class Form1 : Form

    {

        private enum Flags : uint

        {

            DS_FLAGS_NONE = 0x0,

            DS_FORCE_REDISCOVERY = 0x1,

            DS_DIRECTORY_SERVICE_REQUIRED = 0x10,

            DS_DIRECTORY_SERVICE_PREFERRED = 0x20,

            DS_GC_SERVER_REQUIRED = 0x40,

            DS_PDC_REQUIRED = 0x80,

            DS_BACKGROUND_ONLY = 0x100,

            DS_IP_REQUIRED = 0x200,

  DS_KDC_REQUIRED = 0x400,

            DS_TIMESERV_REQUIRED = 0x800,

            DS_WRITABLE_REQUIRED = 0x1000,

            DS_GOOD_TIMESERV_PREFERRED = 0x2000,

            DS_AVOID_SELF = 0x4000,

            DS_ONLY_LDAP_NEEDED = 0x8000,

        DS_IS_FLAT_NAME = 0x10000,

            DS_IS_DNS_NAME = 0x20000,

            DS_RETURN_DNS_NAME = 0x40000000,

            DS_RETURN_FLAT_NAME = 0x80000000

        }

        public struct DOMAIN_CONTROLLER_INFO

        {

            [MarshalAs(UnmanagedType.LPWStr)]

            public string DomainControllerName;

            [MarshalAs(UnmanagedType.LPWStr)]

            public string DomainControllerAddress;

            [MarshalAs(UnmanagedType.I4)]

            public uint DomainControllerAddressType;

            [MarshalAs(UnmanagedType.Struct)]

            public System.Guid DomainGuid;

            [MarshalAs(UnmanagedType.LPWStr)]

            public string DomainName;

            [MarshalAs(UnmanagedType.LPWStr)]

            public string DnsForestName;

            [MarshalAs(UnmanagedType.I4)]

            public uint Flags;

            [MarshalAs(UnmanagedType.LPWStr)]

            public string DcSiteName;

            [MarshalAs(UnmanagedType.LPWStr)]

            public string ClientSiteName;

        };

        [DllImport("NetAPI32.dll", CharSet = CharSet.Unicode)]

        public static extern uint DsGetDcName(

        [MarshalAs(UnmanagedType.LPTStr)] string ComputerName,

        [MarshalAs(UnmanagedType.LPTStr)] string DomainName,

        [MarshalAs(UnmanagedType.Struct)]ref System.Guid DomainGuid,

        [MarshalAs(UnmanagedType.LPTStr)] string SiteName,

        uint Flags,

        out IntPtr pBuf);

        [DllImport("NetAPI32.dll", CharSet = CharSet.Unicode)]

        public static extern uint NetApiBufferFree(IntPtr buf);

        public Form1()

        {

            InitializeComponent();

        }

        private void button1_Click(object sender, EventArgs e)

        {

            IntPtr buf;

            DOMAIN_CONTROLLER_INFO dcInfo;

            System.Guid myGuid = new System.Guid();

            uint lRet;

            String szBuf;

           

            lRet = DsGetDcName(null, null, ref myGuid, null, Convert.ToUInt32(Flags.DS_RETURN_FLAT_NAME), out buf);

            dcInfo = (DOMAIN_CONTROLLER_INFO)Marshal.PtrToStructure(buf, typeof(DOMAIN_CONTROLLER_INFO));

            Console.WriteLine("DomainControllerName (NetBIOS 名) = " + dcInfo.DomainControllerName);

            Console.WriteLine("DomainControllerAddress = " + dcInfo.DomainControllerAddress);

            Console.WriteLine("DomainControllerAddressType = 0x" + dcInfo.DomainControllerAddressType.ToString("X"));

            Console.WriteLine("DomainName = " + dcInfo.DomainName);

            Console.WriteLine("DnsForestName = " + dcInfo.DnsForestName);

            Console.WriteLine("Flags = 0x" + dcInfo.Flags.ToString("X"));

            Console.WriteLine("DcSiteName = " + dcInfo.DcSiteName);

            Console.WriteLine("ClientSiteName = " + dcInfo.ClientSiteName);

            szBuf = "DomainControllerName (NetBIOS 名) = " + dcInfo.DomainControllerName + "\n" +

                    "DomainControllerAddress = " + dcInfo.DomainControllerAddress + "\n" +

                    "DomainControllerAddressType = 0x" + dcInfo.DomainControllerAddressType.ToString("X") + "\n" +

            "DomainName = " + dcInfo.DomainName + "\n" +

                    "DnsForestName = " + dcInfo.DnsForestName + "\n" +

                    "Flags = 0x" + dcInfo.Flags.ToString("X") + "\n" +

                    "DcSiteName = " + dcInfo.DcSiteName + "\n" +

                    "ClientSiteName = " + dcInfo.ClientSiteName;

            MessageBox.Show(szBuf);

            lRet = NetApiBufferFree(buf);

        }

    }

}

Visual Basic.NET の場合

Option Explicit On

Imports System

Imports System.Collections.Generic

Imports System.ComponentModel

Imports System.Data

Imports System.Drawing

Imports System.Text

Imports System.Windows.Forms

Imports System.Runtime.InteropServices

Public Class Form1

    Private Enum Flags As Integer

        DS_FLAGS_NONE = &H0

        DS_FORCE_REDISCOVERY = &H1

        DS_DIRECTORY_SERVICE_REQUIRED = &H10

        DS_DIRECTORY_SERVICE_PREFERRED = &H20

        DS_GC_SERVER_REQUIRED = &H40

        DS_PDC_REQUIRED = &H80

        DS_BACKGROUND_ONLY = &H100

        DS_IP_REQUIRED = &H200

        DS_KDC_REQUIRED = &H400

        DS_TIMESERV_REQUIRED = &H800

        DS_WRITABLE_REQUIRED = &H1000

        DS_GOOD_TIMESERV_PREFERRED = &H2000

        DS_AVOID_SELF = &H4000

        DS_ONLY_LDAP_NEEDED = &H8000

        DS_IS_FLAT_NAME = &H10000

        DS_IS_DNS_NAME = &H20000

        DS_RETURN_DNS_NAME = &H40000000

        DS_RETURN_FLAT_NAME = &H80000000

    End Enum

    Structure DOMAIN_CONTROLLER_INFO

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public DomainControllerName As String

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public DomainControllerAddress As String

        <MarshalAs(UnmanagedType.I4)> _

        Public DomainControllerAddressType As Integer

        <MarshalAs(UnmanagedType.Struct)> _

        Public DomainGuid As Guid

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public DomainName As String

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public DnsForestName As String

        <MarshalAs(UnmanagedType.I4)> _

        Public Flags As Integer

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public DcSiteName As String

        <MarshalAs(UnmanagedType.LPWStr)> _

        Public ClientSiteName As String

    End Structure

    Declare Auto Function DsGetDcName Lib "netapi32" (ByVal ComputerName As String, _

         ByVal DomainName As String, _

         ByRef DomainGuid As Guid, _

         ByVal SiteName As String, _

         ByVal Flags As Integer, _

         ByRef dcInfo As IntPtr) As Integer

    Declare Function NetApiBufferFree Lib "netapi32" (ByVal Buffer As IntPtr) As Integer

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim buf As IntPtr

        Dim dcInfo As DOMAIN_CONTROLLER_INFO

        Dim myGuid As System.Guid

        Dim lRet As Integer

        Dim szBuf As String

        lRet = DsGetDcName(Nothing, Nothing, myGuid, Nothing, Flags.DS_RETURN_FLAT_NAME, buf)

        dcInfo = CType(Marshal.PtrToStructure(buf, GetType(DOMAIN_CONTROLLER_INFO)), DOMAIN_CONTROLLER_INFO)

        Console.WriteLine("DomainControllerName (NetBIOS 名) = " & dcInfo.DomainControllerName)

        Console.WriteLine("DomainControllerAddress = " & dcInfo.DomainControllerAddress)

        Console.WriteLine("DomainControllerAddressType = 0x" & dcInfo.DomainControllerAddressType.ToString("X"))

        Console.WriteLine("DomainName = " & dcInfo.DomainName)

  Console.WriteLine("DnsForestName = " & dcInfo.DnsForestName)

        Console.WriteLine("Flags = 0x" & dcInfo.Flags.ToString("X"))

        Console.WriteLine("DcSiteName = " & dcInfo.DcSiteName)

        Console.WriteLine("ClientSiteName = " & dcInfo.ClientSiteName)

        szBuf = "DomainControllerName (NetBIOS 名) = " & dcInfo.DomainControllerName & vbLf _

                            & "DomainControllerAddress = " & dcInfo.DomainControllerAddress & vbLf _

                            & "DomainControllerAddressType = 0x" & dcInfo.DomainControllerAddressType.ToString("X") & vbLf _

                            & "DomainName = " & dcInfo.DomainName & vbLf _

                            & "DnsForestName = " & dcInfo.DnsForestName & vbLf _

                            & "Flags = 0x" & dcInfo.Flags.ToString("X") & vbLf _

                            & "DcSiteName = " & dcInfo.DcSiteName & vbLf _

                            & "ClientSiteName = " & dcInfo.ClientSiteName

  MessageBox.Show(szBuf)

        NetApiBufferFree(buf)

    End Sub

End Class

それでは皆様お体をご自愛くださいますよう。

~ ういこう ~

JPILMBLG(05Mar2009).zip