首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C語言實現 Windows 用戶帳戶管理:從添加到枚舉的完整指南

     編輯:關於C語言

前言

在 Windows 系統編程中,用戶帳戶管理是一項基礎且關鍵的任務。無論是系統管理工具、自動化部署腳本,還是安全審計程序,都需要以程式化方式創建、刪除、查詢用戶,以及調整群組隸屬關係。Windows 提供了 NetUserAdd、NetUserDel、NetUserEnum、NetLocalGroupAddMembers 等 NetAPI 函數,配合 netapi32.lib,即可在 C/C++ 中輕鬆實現這些操作。

核心 API 速覽

函數用途關鍵參數
NetUserAdd新增本地用戶伺服器名、層級(如 USER_INFO_1)、用戶結構體、錯誤碼輸出
NetUserDel刪除本地用戶伺服器名、用戶名
NetUserEnum列舉所有本地用戶伺服器名、層級(如 USER_INFO_3)、過濾條件、緩衝區、續傳句柄
NetLocalGroupAddMembers將用戶加入本地群組伺服器名、群組名、層級(LOCALGROUP_MEMBERS_INFO_3)、成員陣列、成員數

完整範例程式

下列程式示範:取得用戶總數、列舉所有用戶、新增管理員用戶 alex、將其加入 Administrators 群組、最後刪除該用戶。程式需以管理員權限執行。

#define MAX_BUFF 1024*4
#include <stdio.h>
#include <windows.h>
#include <assert.h>
#include <lm.h>
#pragma comment(lib, "netapi32.lib")

char Temp[MAX_BUFF] = {0};

int UserEnum();
int GetUserNum();

int wmain(int argc, wchar_t *argv[])
{
    USER_INFO_1 ui;
    DWORD dwLevel = 1;
    DWORD dwError = 0;
    NET_API_STATUS nStatus;
    LPWSTR UserName = L"alex";

    // 1. 取得用戶總數
    int UserNum = GetUserNum();
    wprintf(L"Current user count: %d\n", UserNum);

    // 2. 列舉所有用戶
    UserEnum();

    // 3. 準備新增用戶資料
    ui.usri1_name = UserName;
    ui.usri1_password = UserName;          // 密碼同用戶名(示範用)
    ui.usri1_priv = USER_PRIV_USER;
    ui.usri1_home_dir = NULL;
    ui.usri1_comment = NULL;
    ui.usri1_flags = UF_SCRIPT;            // 不要求密碼過期
    ui.usri1_script_path = NULL;

    // 4. 新增用戶
    nStatus = NetUserAdd(NULL, dwLevel, (LPBYTE)&ui, &dwError);
    if (nStatus == NERR_Success)
        fwprintf(stderr, L"User %s has been successfully added.\n", UserName);
    else
        fwprintf(stderr, L"Add user failed: %d (error param: %d)\n", nStatus, dwError);

    // 5. 加入 Administrators 群組
    LPWSTR szGroup = L"Administrators";
    LOCALGROUP_MEMBERS_INFO_3 LGMInfo;
    LGMInfo.lgrmi3_domainandname = UserName;

    nStatus = NetLocalGroupAddMembers(NULL, szGroup, 3, (LPBYTE)&LGMInfo, 1);
    if (nStatus == NERR_Success)
        fwprintf(stderr, L"User %s added to %s.\n", UserName, szGroup);
    else
        fwprintf(stderr, L"Add to group failed: %d\n", nStatus);

    // 6. 刪除用戶(示範完整生命週期)
    nStatus = NetUserDel(NULL, UserName);
    if (nStatus == NERR_Success)
        fwprintf(stderr, L"User %s has been successfully deleted.\n", UserName);
    else
        fwprintf(stderr, L"Delete user failed: %d\n", nStatus);

    return 0;
}

// 取得本地用戶總數
int GetUserNum()
{
    DWORD dwLevel = 1;
    DWORD dwPrefMaxLen = MAX_PREFERRED_LENGTH;
    DWORD dwEntriesRead = 0;
    DWORD dwTotalEntries = 0;
    NET_API_STATUS nStatus;
    LPUSER_INFO_1 pBuf = NULL;

    nStatus = NetUserEnum(NULL, dwLevel, FILTER_NORMAL_ACCOUNT,
                          (LPBYTE*)&pBuf, dwPrefMaxLen,
                          &dwEntriesRead, &dwTotalEntries, NULL);
    if (pBuf) NetApiBufferFree(pBuf);
    return (nStatus == NERR_Success) ? (int)dwTotalEntries : 0;
}

// 列舉並印出所有用戶名稱與權限
int UserEnum()
{
    LPUSER_INFO_3 pBuf = NULL;
    LPUSER_INFO_3 pTmpBuf;
    DWORD i, dwLevel = 3, dwPrefMaxLen = MAX_PREFERRED_LENGTH;
    DWORD dwEntriesRead = 0, dwTotalEntries = 0, dwResumeHandle = 0;
    NET_API_STATUS nStatus;
    LPTSTR pszServerName = NULL;

    do {
        nStatus = NetUserEnum(pszServerName, dwLevel, FILTER_NORMAL_ACCOUNT,
                              (LPBYTE*)&pBuf, dwPrefMaxLen,
                              &dwEntriesRead, &dwTotalEntries, &dwResumeHandle);
        if ((nStatus == NERR_Success) || (nStatus == ERROR_MORE_DATA)) {
            if ((pTmpBuf = pBuf) != NULL) {
                for (i = 0; i < dwEntriesRead; i++) {
                    if (pTmpBuf == NULL) {
                        printf("Access violation.\n");
                        break;
                    }
                    sprintf(Temp, "%-20S ", pTmpBuf->usri3_name);
                    switch (pTmpBuf->usri3_priv) {
                        case USER_PRIV_GUEST:     strcat(Temp, "(Guest) "); break;
                        case USER_PRIV_USER:      strcat(Temp, "(User) "); break;
                        case USER_PRIV_ADMIN:     strcat(Temp, "(Administrator) "); break;
                        default:                  strcat(Temp, "(Unknown) "); break;
                    }
                    printf("%s\n", Temp);
                    pTmpBuf++;
                }
            }
        } else {
            printf("NetUserEnum failed: %d\n", nStatus);
        }
        if (pBuf) {
            NetApiBufferFree(pBuf);
            pBuf = NULL;
        }
    } while (nStatus == ERROR_MORE_DATA);

    printf("List system accounts completed.\n");
    return 0;
}

關鍵點解析

  • 權限提升:操作本地用戶帳戶需要管理員權限,建議在 Manifest 中設定 requireAdministrator 或以「以系統管理員身分執行」啟動。
  • 記憶體管理:NetUserEnum 分配的緩衝區必須呼叫 NetApiBufferFree 釋放,否則會洩漏。
  • 錯誤代碼:常見錯誤包括 NERR_UserExists (2231)、ERROR_ACCESS_DENIED (5)、NERR_InvalidComputer (2351) 等,應依 nStatus 做細緻處理。
  • Unicode:範例使用 wmain 與 LPWSTR,確保中文用戶名亦能正確處理。

擴充應用

  • 搭配 NetUserGetInfo / NetUserSetInfo 讀寫完整用戶屬性(全名、描述、帳戶到期日、登入時段等)。
  • 使用 NetLocalGroupEnum 列舉所有本地群組,NetLocalGroupGetMembers 查詢群組成員。
  • 遠端管理:將第一個參數由 NULL 改為目標機器名(如 L"\\\\SERVER01"),前提是具備 RPC 存取權限且防火牆開放 445/139 埠。

結語

掌握 NetAPI 用戶管理函數,能讓 C/C++ 程式直接與 Windows 安全子系統對話,是開發系統級工具、自動化運維腳本的核心技能。實務上建議將上述操作封裝為 RAII 風格的 C++ 類別,並加入完整的錯誤處理與日誌記錄,打造可維護、可複用的系統管理元件。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved