2014-07-10 2 views
1

Quser.exe을 사용하면 클라이언트가 원격 RDP 서버에서 사용자 세션을 볼 수 있습니다. 예 :API 호출을 사용하여 quser.exe를 재현하는 방법은 무엇입니까?

C:\>quser /server:MyRDPserver 

USERNAME    SESSIONNAME  ID STATE IDLE TIME LOGON TIME 
userA          3 Disc  1+20:03 08/07/2014 12:36 
userB          4 Disc  1+22:28 08/07/2014 10:38 

이 기능을 C++ 또는 C# 프로그램에 구현하고자합니다. 예, quser.exe를 생성하고 출력을 파싱 할 수 있지만 동일한 정보를 제공 할 수있는 Win32 API 또는 .Net 프레임 워크 클래스가 있습니까? 특히 :

  • 사용자 이름
  • 연결 상태
  • 나는 종종 오래된 연결을 나열과 같은 정보를 찾기 위해 WMI (Win32_LoggedOnUser)를 사용하는, 신뢰할 수없는 것으로 나타났습니다

로그온 시간 . 또한 psloggedon HKEY_USERS 하위 키를 열거하고 휘발성 환경 키를 찾는 방법을 시도했지만 동일한 문제가 있습니다.

+1

아마도 WTS 기능이 도움이 될 수 있습니다. – Xearinox

답변

1

나는 내 자신의 질문에 대답 할 것입니다.

우선, 대상 컴퓨터에서 사용 권한이 올바르게 설정되어 있는지 확인해야합니다. 이이 작업을 수행하기 위해 1. 파워 쉘 스크립트 컨트롤 \ 터미널 서버 \ AllowRemoteRPC \ HKLM \ 시스템 \ CURRENTCONTROLSET 설정 수반하는 것은 :

# Get the service account credential 
$cred = Get-Credential my_admin_account 
$Target_Computers = @("Computer_1","Computer_2") 

# open the remote registry 
[long]$HIVE_HKLM = 2147483650 
foreach($c in $Target_Computers) 
{ 
    $StdRegProv = Get-WmiObject -List -Namespace root\default -ComputerName $c -Credential $cred | where { $_.Name -eq "StdRegProv" } 
    $StdRegProv.SetDWORDValue($HIVE_HKLM, "SYSTEM\CurrentControlSet\Control\Terminal Server", "AllowRemoteRPC", 1) 
} 

Xearinox 말했듯이, C에 대한 ++ 당신이는 Win32 API에 WTSxxx 기능을 사용할 수 있습니다. 가장 쉬운 방법은 기본적으로 동일한 API 함수 주위에 C#을 래퍼 인 Cassia library을 사용하는 것입니다,

#include <string> 
#include <iostream> 
#include <iomanip> 
#include <windows.h> 
#include <WtsApi32.h> 

using namespace std; 

const unsigned num_connection_states = 10; 
const wchar_t* connection_state_list[num_connection_states] = { 
    L"Active", 
    L"Connected", 
    L"ConnectQuery", 
    L"Shadow", 
    L"Disc", 
    L"Idle", 
    L"Listen", 
    L"Reset", 
    L"Down", 
    L"Init" }; 

int print_error(DWORD err) 
{ 
    // format the message 
    LPTSTR* ppBuffer = nullptr; 
    DWORD retval = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, err, 0, reinterpret_cast<LPTSTR>(ppBuffer), 0, nullptr); 

    // print out 
    wcerr << "Error: *ppBuffer" << endl; 
    return 1; 
} 

wstring format_time(const LARGE_INTEGER& time) 
{ 
    // convert to a local Win32 file time 
    FILETIME ft = { time.LowPart, time.HighPart }; 
    FileTimeToLocalFileTime(&ft, &ft); 

    // convert to a system time 
    SYSTEMTIME st; 
    FileTimeToSystemTime(&ft, &st); 

    wchar_t local_date[255], local_time[255]; 
    GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, local_date, sizeof(local_date)/sizeof(wchar_t)); 
    GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t)); 

    wstring result = local_date; 
    result.append(L" "); 
    result.append(local_time); 

    return result; 
} 

const _int64 SECOND = 10000000; 
const _int64 MINUTE = 60*SECOND; 
const _int64 HOUR = 60*MINUTE; 
const _int64 DAY = 24*HOUR; 

wstring format_timespan(const LARGE_INTEGER& timespan) 
{ 
    // convert to a local Win32 file time 
    FILETIME ft = { timespan.LowPart, timespan.HighPart }; 
    FileTimeToLocalFileTime(&ft, &ft); 

    // convert to a system time 
    SYSTEMTIME st; 
    FileTimeToSystemTime(&ft, &st); 

    wchar_t local_time[255]; 
    int daydiff = floor(
    GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, local_time, sizeof(local_time)/sizeof(wchar_t)); 

    wstring result = local_date; 
    result.append(L" "); 
    result.append(local_time); 

    return result; 
} 

int wmain(int argc, wchar_t* argv[]) 
{ 
    // check args 
    if(argc > 2) 
    { 
    wcout << "Usage: " << argv[0] << " [server_name]\n"; 
    return 1; 
    } 

    // server name 
    bool current_server = true; 
    wstring server_name = L"."; 
    if(argc == 2) 
    { 
    server_name = argv[1]; 
    current_server = false; 
    } 

    // open the server 
    HANDLE hServer; 
    if(current_server) 
    hServer = WTS_CURRENT_SERVER_HANDLE; 
    else 
    hServer = WTSOpenServer(const_cast<LPWSTR>(server_name.c_str())); 

    // enumerate through the sessions 
    DWORD Count = 0; 
    WTS_SESSION_INFO* pSessionInfo = nullptr; 
    BOOL success = WTSEnumerateSessions(hServer, 0, 1, &pSessionInfo, &Count); 
    if(success == 0) 
    return false; 

    // write the headers 
    wcout << " " << left << setw(24) << "USERNAME"; 
    wcout << setw(19) << "SESSIONNAME"; 
    wcout << "ID "; 
    wcout << setw(9) << "STATE"; 
    wcout << "IDLE TIME LOGON TIME"; 

    // loop through each session 
    for(unsigned long s=0; s<Count; s++) 
    { 
    LPTSTR pBuffer = nullptr; 
    DWORD BytesReturned = 0; 
    wcout << "\n " << left; 

    // try getting all info at once 
    WTSINFO* info = nullptr; 
    success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSSessionInfo, reinterpret_cast<LPTSTR*>(&info), &BytesReturned); 
    bool have_wtsinfo = true; 
    if(!success) 
    { 
     // see why failed 
     DWORD err = GetLastError(); 
     if(err == ERROR_NOT_SUPPORTED) 
     have_wtsinfo = false; 
     else 
     return print_error(err); 
    } 

    // print user name 
    wstring user_name; 
    if(have_wtsinfo) 
     user_name = info->UserName; 
    else 
    { 
     success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSUserName, &pBuffer, &BytesReturned); 
     if(!success) 
     continue; 
     user_name = pBuffer; 
     WTSFreeMemory(pBuffer); 
    } 
    wcout << setw(24) << user_name; 

    // print session name 
    wstring session_name; 
    if(have_wtsinfo) 
     session_name = info->WinStationName; 
    else 
    { 
     success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSWinStationName, &pBuffer, &BytesReturned); 
     if(!success) 
     continue; 
     session_name = pBuffer; 
     WTSFreeMemory(pBuffer); 
    } 
    wcout << setw(19) << session_name; 

    // print session ID 
    wcout << right << setw(2) << pSessionInfo[s].SessionId; 

    // print connection state 
    WTS_CONNECTSTATE_CLASS connect_state; 
    if(have_wtsinfo) 
     connect_state = info->State; 
    else 
    { 
     success = WTSQuerySessionInformation(hServer, pSessionInfo[s].SessionId, WTSConnectState, &pBuffer, &BytesReturned); 
     if(!success) 
     continue; 
     connect_state = *reinterpret_cast<WTS_CONNECTSTATE_CLASS*>(pBuffer); 
     WTSFreeMemory(pBuffer); 
    } 
    if(connect_state>=num_connection_states) 
     continue; 
    wcout << " " << left << setw(8) << connection_state_list[connect_state]; 

    // get idle time 
    LARGE_INTEGER idle = info->CurrentTime; 
    idle.QuadPart -= info->LogonTime.QuadPart; 

    // print logon time - not supported 
    if(info->LogonTime.QuadPart!=0) 
    { 
     wcout << format_time(info->LogonTime); 
    } 

    // clean up 
    WTSFreeMemory(info); 
    } 

    // clean up 
    WTSFreeMemory(pSessionInfo); 
    if(!current_server) 
    WTSCloseServer(hServer); 
} 

C 번호 : 컴퓨터가되지 XP가되어 가정하면, 여기에 몇 가지 C++ 코드입니다.

1

당신은 프로세스를 생성하고 "QUSER/서버 : MyRDPserver을"통과는 Win32 API를 호출 할 수있는 매개 변수로, 나는 보통 다음과 같이 수행

PROCESS_INFORMATION process_info; 
STARTUPINFOA startup_info; 
string cmdline2; 
char error_msg[1024]; 

memset(&process_info, 0, sizeof(process_info)); 
memset(&startup_info, 0, sizeof(startup_info)); 
startup_info.cb = sizeof(startup_info); 

argc = argarray.size(); 
for(int i = 0; i < argc; i++) { 
    cmdline2 += argarray.at(i); 
    if(i != (argc - 1)) cmdline2 += " "; 
} 

string command = suCmdLineRemoveQuotations(argarray.at(0)); 
retval = CreateProcessA(command.c_str(), (LPSTR)cmdline2.c_str(), NULL, NULL, TRUE, 
    0, NULL, NULL, &startup_info, &process_info); 

if (!retval) { 
    windows_error_string(error_msg, sizeof(error_msg)); 
    error = error_msg; 
    return false; 
} 

WaitForSingleObject(process_info.hProcess, msecs); 
if(GetExitCodeProcess(process_info.hProcess, &status)) { 
    // status maybe is STILL_ACTIVE, in that case, the process is killed 
    if(status == STILL_ACTIVE) { 
     TerminateProcess(process_info.hProcess, 1); 
    } 
    ecode = status; 
} 

return true; 

프로세스의 시작, 당신은 출력을 리디렉션 할 수 있습니다 때 Qt를 사용하면 문제가 간단 해집니다. QProcess를 사용하여 구현할 수 있습니다.

+0

나는 그것을 생각했지만, 내가 찾고있는 것은 quser.exe와 같은 API 함수를 사용하는 방법에 관한 정보이다. –

관련 문제