2011-10-03 9 views
7

私は、Delphiコードを使用してコンピュータのSIDを抽出する方法を探しています。これを行うSysInternalsのPsGetSidというツールがありますが、私のアプリケーションでは使用できません。 Googleでコード例を検索したところ、見つからなかった。コンピュータ/マシンSIDを抽出する方法は?

どうすればこの問題をDelphiで達成できますか?

助けてください。

答えて

8

これはLookupAccountNameを使用したサンプルです。このサンプルになります@MikeKwanのようなWinAPi関数が示唆している。

{$APPTYPE CONSOLE} 

uses 
    Windows, 
    SysUtils; 


function ConvertSidToStringSid(Sid: PSID; out StringSid: PChar): BOOL; stdcall; external 'ADVAPI32.DLL' name {$IFDEF UNICODE} 'ConvertSidToStringSidW'{$ELSE} 'ConvertSidToStringSidA'{$ENDIF}; 

function SIDToString(ASID: PSID): string; 
var 
    StringSid : PChar; 
begin 
    if not ConvertSidToStringSid(ASID, StringSid) then 
    RaiseLastWin32Error; 

    Result := string(StringSid); 
end; 

function GetLocalComputerName: string; 
var 
    nSize: DWORD; 
begin 
    nSize := MAX_COMPUTERNAME_LENGTH + 1; 
    SetLength(Result, nSize); 
    if not GetComputerName(PChar(Result), {var}nSize) then 
    begin 
    Result := ''; 
    Exit; 
    end; 

    SetLength(Result, nSize); 
end; 

function GetComputerSID:string; 
var 
    Sid: PSID; 
    cbSid: DWORD; 
    cbReferencedDomainName : DWORD; 
    ReferencedDomainName: string; 
    peUse: SID_NAME_USE; 
    Success: BOOL; 
    lpSystemName : string; 
    lpAccountName: string; 
begin 
    Sid:=nil; 
    try 
    lpSystemName:=''; 
    lpAccountName:=GetLocalComputerName; 

    cbSid := 0; 
    cbReferencedDomainName := 0; 
    // First call to LookupAccountName to get the buffer sizes. 
    Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), nil, cbSid, nil, cbReferencedDomainName, peUse); 
    if (not Success) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) then 
    begin 
     SetLength(ReferencedDomainName, cbReferencedDomainName); 
     Sid := AllocMem(cbSid); 
     // Second call to LookupAccountName to get the SID. 
     Success := LookupAccountName(PChar(lpSystemName), PChar(lpAccountName), Sid, cbSid, PChar(ReferencedDomainName), cbReferencedDomainName, peUse); 
     if not Success then 
     begin 
     FreeMem(Sid); 
     Sid := nil; 
     RaiseLastOSError; 
     end 
     else 
     Result := SIDToString(Sid); 
    end 
    else 
     RaiseLastOSError; 
    finally 
    if Assigned(Sid) then 
    FreeMem(Sid); 
    end; 
end; 


begin 
try 
    Writeln(GetComputerSID); 
except 
    on E:Exception do 
     Writeln(E.Classname, ':', E.Message); 
end; 
Writeln('Press Enter to exit'); 
Readln; 
end. 
+0

可能な限りWMIの代わりにWin APIを使用することをお勧めします。これは私が必要としていたものです。ありがとう! – Ran

+0

GetLocalComputerNameは不正なデータを返します。GetComputerName APIが成功すると、nSizeに出力バッファ(結果var)にコピーされた数値またはTCHARが含まれます。したがって、成功時にsetLength(result、nSize)を実行する必要があります –

+2

'SIDToString'の最後に次のように追加する必要があります: ' LocalFree(HLocal(StringSid)); ' –

0

LookupAccountNameで取得できます。最初のパラメータはNULLで、2番目のパラメータはマシン名を渡します。

+0

渡す必要のあるマシン名は、GetComputerName()から取得したものと同じか、他の形式である必要がありますか? – Ran

3

Win32_Account WMIクラスを使用して、マシンSIDをユーザーアカウントSIDから抽出することができます。

SIDがあるユーザーアカウントの例えば

S-1-5-21-1299824301-1797996836-594316699-1009 

マシンSIDは

S-1-5-21-1299824301-1797996836-594316699 

チェック

program GetWMI_Info; 

{$APPTYPE CONSOLE} 

uses 
    SysUtils, 
    ActiveX, 
    ComObj, 
    Variants; 

function GetComputerSID:string; 
const 
    WbemUser   =''; 
    WbemPassword  =''; 
    WbemComputer  ='localhost'; 
    wbemFlagForwardOnly = $00000020; 
var 
    FSWbemLocator : OLEVariant; 
    FWMIService : OLEVariant; 
    FWbemObjectSet: OLEVariant; 
    FWbemObject : OLEVariant; 
    oEnum   : IEnumvariant; 
    iValue  : LongWord; 
begin; 
    FSWbemLocator := CreateOleObject('WbemScripting.SWbemLocator'); 
    FWMIService := FSWbemLocator.ConnectServer(WbemComputer, 'root\CIMV2', WbemUser, WbemPassword); 
    FWbemObjectSet:= FWMIService.ExecQuery('SELECT SID FROM Win32_Account Where SIDType=1','WQL',wbemFlagForwardOnly); 
    oEnum   := IUnknown(FWbemObjectSet._NewEnum) as IEnumVariant; 
    if oEnum.Next(1, FWbemObject, iValue) = 0 then 
    begin 
    Result:=FWbemObject.SID; 
    Result:=Copy(Result,1,LastDelimiter('-',Result)-1); 
    FWbemObject:=Unassigned; 
    end; 
end; 


begin 
try 
    CoInitialize(nil); 
    try 
     Writeln(GetComputerSID); 
    finally 
     CoUninitialize; 
    end; 
except 
    on E:EOleException do 
     Writeln(Format('EOleException %s %x', [E.Message,E.ErrorCode])); 
    on E:Exception do 
     Writeln(E.Classname, ':', E.Message); 
end; 
Writeln('Press Enter to exit'); 
Readln; 
end. 
関連する問題