LoginSignup
6
7

More than 5 years have passed since last update.

コンピューターSIDを取得する方法

Last updated at Posted at 2017-02-26

コンピューターSIDは見つけにくい

SIDを取得する際に whoami /user を実行するとユーザーSIDを取得することが出来る。

いろんなサイトだと、ここから末尾のRIDを除いた値がコンピューターSIDだと記載してるけど、ドメインユーザーでログインしてるとその方法は使えない。
その場合でもローカルユーザーのSIDを表示させれば同じ事は出来るんだけど、出来ればちゃんとした方法で取得したい。

というわけで

最近C++を使ってみる機会があったし、関数の使い方をちゃんと把握するのに都合がよかったので C++ → C# (→ PowerShell)で作ってみました。
特にC++は初心者なので、書き方とか解放とか微妙かもしれません。エラー処理もしてません。
(wstringに変換しているのはコピーが楽そうだからです。)

取得方法含め、ご利用は自己責任でお願いします、というよくある但し書きをつけておきます。

参考

参考にしたページは以下です。(参考というより、必要な部分だけ削り出したような感じですが。)
PInvoke.NETの方はほとんど書き終わった後で必要なコードほぼ全部書いてるじゃん、と気づいてしまいました。

コンピューターSIDの取得(C++版)

main.cpp
#include <iostream>
#include <windows.h>
#include <sddl.h>

std::wstring GetComputerSid() {

    // コンピューター名を取得する
    wchar_t szComputerName[MAX_COMPUTERNAME_LENGTH + 2];
    DWORD dwComputerNameSize = sizeof(szComputerName);
    GetComputerNameW(szComputerName, &dwComputerNameSize);

    // SID取得
    PSID pSid;
    DWORD dwSidLen = 0;
    wchar_t szDomain[256];
    DWORD dwDomainLen = sizeof(szDomain);
    SID_NAME_USE snu;

    // SIDに必要なメモリ領域を確認して確保する
    LookupAccountNameW(NULL, szComputerName, NULL, &dwSidLen, szDomain, &dwDomainLen, &snu);
    pSid = (PSID)HeapAlloc(GetProcessHeap(), 0, dwSidLen);

    // SIDを取得する
    LookupAccountNameW(NULL, szComputerName, pSid, &dwSidLen, szDomain, &dwDomainLen, &snu);

    // SIDを文字列に変換する
    wchar_t *szSid;
    ConvertSidToStringSidW(pSid, &szSid);

    // std::wstringに変換
    std::wstring sidString;
    sidString = std::wstring(szSid);

    // メモリの解放
    HeapFree(GetProcessHeap(), 0, pSid);
    LocalFree(szSid);

    return sidString;
}

int main()
{
    std::wstring computerSid = GetComputerSid();
    std::wcout << computerSid.c_str();

    return 0;
}

コンピューターSIDの取得(C#版)

中身はC++をそのまま移植しただけです。

Program.cs
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

namespace GetComputerSID {
    class Program {
        static void Main(string[] args) {
            Console.WriteLine(GetComputerSid());
            Console.ReadLine();
        }

        public static string GetComputerSid() {
            // コンピューター名を取得する
            string computerName = Environment.MachineName;

            // SID取得
            byte[] sid;
            uint sidLen = 0;
            StringBuilder domainName = new StringBuilder(256);
            uint domainNameLen = (uint)domainName.Capacity;
            SID_NAME_USE snu;

            // SIDに必要なメモリ領域を確認して確保する
            if (!LookupAccountName(null, computerName, null, ref sidLen, domainName, ref domainNameLen, out snu)) {
                int lastError = Marshal.GetLastWin32Error();
                if (lastError != ERROR_NOT_ENOUGH_MEMORY) {
                    // ここもコンストラクターは空でいい気もするけど気分的にこのまま
                    throw new Win32Exception(lastError);
                }
            }

            // SIDを取得する
            sid = new byte[sidLen];
            domainName.EnsureCapacity((int)domainNameLen);
            if (!LookupAccountName(null, computerName, sid, ref sidLen, domainName, ref domainNameLen, out snu)) {
                throw new Win32Exception();
            }

            // SIDを文字列に変換する
            IntPtr pSidString;
            if (!ConvertSidToStringSid(sid, out pSidString)) {
                throw new Win32Exception();
            }

            // stringに変換
            string sidString = Marshal.PtrToStringUni(pSidString);

            // メモリの解放
            if (LocalFree(pSidString) != IntPtr.Zero) {
                throw new Win32Exception();
            }

            return sidString;
        }

        private const int ERROR_NOT_ENOUGH_MEMORY = 122;

        public enum SID_NAME_USE {
            SidTypeUser = 1,
            SidTypeGroup,
            SidTypeDomain,
            SidTypeAlias,
            SidTypeWellKnownGroup,
            SidTypeDeletedAccount,
            SidTypeInvalid,
            SidTypeUnknown,
            SidTypeComputer,
            SidTypeLabel
        }

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "LookupAccountNameW", SetLastError = true)]
        private static extern bool LookupAccountName(
            string lpSystemName,
            string lpAccountName,
            [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
            ref uint cbSid,
            StringBuilder ReferencedDomainName,
            ref uint cbReferencedDomainName, 
            out SID_NAME_USE peUse);

        [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "ConvertSidToStringSidW", SetLastError = true)]
        private static extern bool ConvertSidToStringSid([MarshalAs(UnmanagedType.LPArray)]byte[] sid, out IntPtr stringSid);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern IntPtr LocalFree(IntPtr hMem);
    }

}

コンピューターSIDの取得(PowerShell版)

PowerShellと見せかけてC#そのままです。


$GetComputerSidDef =@'
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Text;

public class GetComputerSidClass {
    public static string GetComputerSid() {
        // コンピューター名を取得する
        string computerName = Environment.MachineName;

        // SID取得
        byte[] sid;
        uint sidLen = 0;
        System.Text.StringBuilder domainName = new System.Text.StringBuilder(256);
        uint domainNameLen = (uint)domainName.Capacity;
        SID_NAME_USE snu;

        // SIDに必要なメモリ領域を確認して確保する
        if (!LookupAccountName(null, computerName, null, ref sidLen, domainName, ref domainNameLen, out snu)) {
            int lastError = Marshal.GetLastWin32Error();
            if (lastError != ERROR_NOT_ENOUGH_MEMORY) {
                // ここもコンストラクターは空でいい気もするけど気分的にこのまま
                throw new System.ComponentModel.Win32Exception(lastError);
            }
        }

        // SIDを取得する
        sid = new byte[sidLen];
        domainName.EnsureCapacity((int)domainNameLen);
        if (!LookupAccountName(null, computerName, sid, ref sidLen, domainName, ref domainNameLen, out snu)) {
            throw new System.ComponentModel.Win32Exception();
        }

        // SIDを文字列に変換する
        IntPtr pSidString;
        if (!ConvertSidToStringSid(sid, out pSidString)) {
            throw new System.ComponentModel.Win32Exception();
        }

        // stringに変換
        string sidString = Marshal.PtrToStringUni(pSidString);

        // メモリの解放
        if (LocalFree(pSidString) != IntPtr.Zero) {
            throw new System.ComponentModel.Win32Exception();
        }

        return sidString;
    }

    private const int ERROR_NOT_ENOUGH_MEMORY = 122;

    public enum SID_NAME_USE {
        SidTypeUser = 1,
        SidTypeGroup,
        SidTypeDomain,
        SidTypeAlias,
        SidTypeWellKnownGroup,
        SidTypeDeletedAccount,
        SidTypeInvalid,
        SidTypeUnknown,
        SidTypeComputer,
        SidTypeLabel
    }

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "LookupAccountNameW", SetLastError = true)]
    private static extern bool LookupAccountName(
        string lpSystemName,
        string lpAccountName,
        [MarshalAs(UnmanagedType.LPArray)] byte[] Sid,
        ref uint cbSid,
        System.Text.StringBuilder ReferencedDomainName,
        ref uint cbReferencedDomainName, 
        out SID_NAME_USE peUse);

    [DllImport("advapi32.dll", CharSet = CharSet.Unicode, EntryPoint = "ConvertSidToStringSidW", SetLastError = true)]
    private static extern bool ConvertSidToStringSid([MarshalAs(UnmanagedType.LPArray)]byte[] sid, out IntPtr stringSid);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr LocalFree(IntPtr hMem);
}
'@

Add-Type -TypeDefinition $GetComputerSidDef

# 実際は変数に入れなくてもいいけど、Qiitaで表示されなかったので一旦変数に格納
$sid = [GetComputerSidClass]::GetComputerSid()
$sid

6
7
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7