在 Windows 環境下以程式化方式建立本機使用者帳戶,主要有兩種路徑:
System.Diagnostics.Process 執行 net user / net localgroup (本文重點)本文詳細介紹命令列模式的實作細節、參數完整說明、權限考量,並提供 DirectoryServices 替代方案概覽。
using System;
using System.Diagnostics;
namespace LocalAccountManager
{
public class AccountCreatorViaCmd
{
///
/// 建立本機標準使用者帳戶
///
/// 帳戶名稱
/// 密碼 (null 或空字串表示無密碼)
/// 顯示名稱 (可選)
/// 描述 (可選)
/// 是否成功
public static bool CreateLocalUser(string username, string password,
string fullName = "", string description = "")
{
try
{
// 1. 建立帳戶: net user username password /add
string args = $"user \"{username}\" ";
args += string.IsNullOrEmpty(password) ? '""' : $"\"{password}\"";
args += " /add";
if (!string.IsNullOrEmpty(fullName))
args += $" /fullname:\"{fullName}\"";
if (!string.IsNullOrEmpty(description))
args += $" /comment:\"{description}\"";
if (!RunNetCommand(args))
return false;
// 2. (可選) 設定密碼永不過期
// RunNetCommand($"user \"{username}\" /expires:never");
// 3. (可選) 禁止使用者變更密碼
// RunNetCommand($"user \"{username}\" /passwordchg:no");
Console.WriteLine($"帳戶 {username} 建立成功");
return true;
}
catch (Exception ex)
{
Console.WriteLine($"建立帳戶失敗: {ex.Message}");
return false;
}
}
///
/// 將使用者加入指定本機群組 (如 Administrators)
///
public static bool AddToLocalGroup(string username, string groupName)
{
string args = $"localgroup \"{groupName}\" \"{username}\" /add";
return RunNetCommand(args);
}
///
/// 修改使用者密碼
///
public static bool ChangePassword(string username, string newPassword)
{
string args = $"user \"{username}\" \"{newPassword}\"";
return RunNetCommand(args);
}
///
/// 刪除本機使用者
///
public static bool DeleteUser(string username)
{
string args = $"user \"{username}\" /delete";
return RunNetCommand(args);
}
///
/// 啟用/停用帳戶
///
public static bool SetAccountActive(string username, bool active)
{
string args = $"user \"{username}\" /active:{(active ? "yes" : "no")}";
return RunNetCommand(args);
}
///
/// 執行 net.exe 命令的核心方法
///
private static bool RunNetCommand(string arguments)
{
var startInfo = new ProcessStartInfo
{
FileName = "net.exe",
Arguments = arguments,
UseShellExecute = false, // 必須 false 才能重導向輸出
CreateNoWindow = true, // 不顯示視窗
RedirectStandardOutput = true, // 捕捉標準輸出
RedirectStandardError = true, // 捕捆錯誤輸出
StandardOutputEncoding = System.Text.Encoding.GetEncoding(950), // 繁體中文系統代碼頁
StandardErrorEncoding = System.Text.Encoding.GetEncoding(950),
Verb = "runas" // 要求管理員權限 (UAC 提升)
};
try
{
using Process? proc = Process.Start(startInfo);
if (proc == null)
{
Console.WriteLine("無法啟動 net.exe");
return false;
}
// 讀取輸出避免緩衝區填滿導致死結
string output = proc.StandardOutput.ReadToEnd();
string error = proc.StandardError.ReadToEnd();
proc.WaitForExit(); // 等待結束
if (proc.ExitCode != 0)
{
Console.WriteLine($"指令失敗 (ExitCode: {proc.ExitCode})");
Console.WriteLine($"輸出: {output}");
Console.WriteLine($"錯誤: {error}");
return false;
}
Console.WriteLine($"指令成功: net.exe {arguments}");
if (!string.IsNullOrWhiteSpace(output))
Console.WriteLine($"輸出: {output.Trim()}");
return true;
}
catch (System.ComponentModel.Win32Exception ex) when (ex.NativeErrorCode == 740)
{
Console.WriteLine("錯誤: 需要系統管理員權限執行 (UAC 提升失敗)");
return false;
}
catch (Exception ex)
{
Console.WriteLine($"執行例外: {ex.Message}");
return false;
}
}
}
}
class Program
{
static void Main()
{
// 需以系統管理員身分執行!
// 1. 建立一般使用者
AccountCreatorViaCmd.CreateLocalUser("devuser", "P@ssw0rd123",
"開發測試帳戶", "自動建立的測試帳號");
// 2. 建立管理員帳戶
AccountCreatorViaCmd.CreateLocalUser("admin01", "Admin@2024", "系統管理員");
AccountCreatorViaCmd.AddToLocalGroup("admin01", "Administrators");
// 3. 修改密碼
// AccountCreatorViaCmd.ChangePassword("devuser", "NewP@ssw0rd");
// 4. 停用帳戶
// AccountCreatorViaCmd.SetAccountActive("devuser", false);
// 5. 刪除帳戶
// AccountCreatorViaCmd.DeleteUser("olduser");
Console.WriteLine("作業完成,按任意鍵離開...");
Console.ReadKey();
}
}
net user [password | *] [/add | /delete] [options] [/domain]
| 參數 | 說明 | 範例 |
|---|---|---|
username |
帳戶名稱 (最長 20 字元) | john |
password |
指定密碼 | P@ssw0rd |
* |
提示輸入密碼 (互動模式) | net user john * /add |
/add |
建立新帳戶 | |
/delete |
刪除帳戶 | |
/domain |
在網域控制站執行 (非本機) | |
/active:{yes|no} |
啟用/停用帳戶 | /active:no |
/comment:"text" |
帳戶描述 | /comment:"測試帳號" |
/fullname:"name" |
顯示全名 | /fullname:"John Doe" |
/expires:{date|never} |
帳戶到期日 (格式依系統地區) | /expires:2024/12/31 |
/passwordchg:{yes|no} |
允許/禁止使用者變更密碼 | /passwordchg:no |
/passwordreq:{yes|no} |
要求/不要求密碼 | /passwordreq:yes |
/times:{times|all} |
允許登入時間 (如 M-F,8am-5pm) | /times:M-F,08:00-17:00 |
/homedir:path |
主目錄路徑 | /homedir:C:\Users\john |
/profilepath:path |
漫遊設定檔路徑 | |
/scriptpath:path |
登入腳本路徑 | |
/workstations:{names|*} |
限制可登入的工作站電腦名 | /workstations:PC01,PC02 |
net localgroup [username[...]] [/add | /delete] [/domain]
| 常用內建群組 | 說明 |
|---|---|
Administrators |
完全控制電腦 |
Users |
標準使用者 (預設) |
Guests |
受限訪客存取 |
Power Users |
較舊版本相容性群組 |
Remote Desktop Users |
允許遠端桌面連線 |
IIS_IUSRS |
IIS 應用程式池身分 |
<requestedExecutionLevel> 設為 requireAdministratorProcessStartInfo.Verb = "runas" 會觸發 UAC 提升提示net.exe 輸出編碼為系統作用代碼頁 (繁中通常為 CP950 / Big5)StandardOutputEncoding = Encoding.GetEncoding(950) 正確讀取中文訊息命令列模式雖簡單但有缺點:需解析文字輸出、難以處理複雜屬性、效能較差。DirectoryServices 提供物件導向操作:
| 特性 | net.exe (Process) | DirectoryServices |
|---|---|---|
| 程式碼風格 | 命令列字串拼湊 | 強型別物件操作 |
| 錯誤處理 | ExitCode + 文字解析 | 標準 .NET Exception |
| 屬性設定 | 有限參數 | 完整屬性支援 (PasswordExpired, UserFlags 等) |
| 效能 | 啟動進程開銷大 | 進程內 COM 呼叫,較快 |
| 相依性 | 無 (系統內建) | 需參考 System.DirectoryServices.dll |
using System.DirectoryServices;
public static void CreateUserDS(string username, string password, string fullName)
{
// 連接本機 SAM 資料庫
using DirectoryEntry computer = new DirectoryEntry("WinNT://" + Environment.MachineName + ",computer");
// 建立使用者
using DirectoryEntry user = computer.Children.Add(username, "user");
user.Invoke("SetPassword", new object[] { password });
user.Invoke("Put", new object[] { "Description", "透過 DirectoryServices 建立" });
user.Invoke("Put", new object[] { "FullName", fullName });
user.CommitChanges(); // 寫入
// 設定密碼永不過期 (UserFlags: ADS_UF_DONT_EXPIRE_PASSWD = 0x10000)
int flags = (int)user.Properties["UserFlags"].Value;
user.Properties["UserFlags"].Value = flags | 0x10000;
user.CommitChanges();
Console.WriteLine("DirectoryServices 建立成功");
}
using DirectoryEntry group = new DirectoryEntry("WinNT://" + Environment.MachineName + "/Administrators,group");
group.Invoke("Add", new object[] { "WinNT://" + Environment.MachineName + "/" + username });
group.CommitChanges();
/expires) 自動失效| Exit Code | 意義 | 處理建議 |
|---|---|---|
| 0 | 成功 | - |
| 1 | 參數錯誤 / 語法錯誤 | 檢查引數格式、特殊字元逸出 |
| 2 | 存取被拒 | 確認以管理員執行、目標帳戶權限 |
| 3 | 系統找不到指定路徑/帳戶 | 帳戶不存在、群組名稱錯誤 |
| 5 | 存取被拒 (權限不足) | UAC 未提升、群組原則限制 |
| 87 | 參數錯誤 (ERROR_INVALID_PARAMETER) | 參數格式不符、密碼不符複雜度要求 |
| 1326 | 登入失敗 (未知使用者/密碼錯誤) | 網域操作時認證問題 |
| 2224 | 帳戶已存在 | 建立前先檢查或捕捉此代碼 |
使用 Process.Start 呼叫 net.exe 是以 C# 建立本機 Windows 帳戶最直接、零相依性的方法,適合簡單自動化腳本、安裝程式、部署工具。關鍵在於:正確處理 UAC 提升、編碼設定、參數逸出、錯誤代碼解讀。對於企業級應用、需大量帳戶管理、或需設定進階屬性 (智慧卡、到期日、漫遊設定檔等) 的場景,強烈建議改用 System.DirectoryServices (WinNT Provider) 或更現代的 System.DirectoryServices.AccountManagement (SAM) 命名空間,獲得型別安全、豐富 API 與更好效能。