コンピューター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