基于计算机名在C#中生成安全本地管理员密码
Alright, let's tackle this problem head-on. You need a deterministic way to generate 8-12 character local admin passwords from computer names, build a simple UI for this, and reuse the same logic via a DLL in PowerShell to set passwords across workstations. Here's a step-by-step solution that fits your .NET Core 2.0 (or Framework) needs:
The key here is to take a computer name, generate a secure hash, then convert that hash into a human-usable password (no unprintable characters, meets length/complexity rules). We'll use HMACSHA256 with a secret key to ensure the same computer name always produces the same password, while adding a layer of security against brute-force attacks.
using System; using System.Linq; using System.Security.Cryptography; using System.Text; public class PasswordGenerator { // Store this secret key securely (e.g., Azure Key Vault, encrypted config) private static readonly byte[] _secretKey = Encoding.UTF8.GetBytes("YourOrgSecureSecretKey123!"); public static string GeneratePassword(string computerName, int minLength = 8, int maxLength = 12) { if (string.IsNullOrWhiteSpace(computerName)) throw new ArgumentNullException(nameof(computerName)); if (minLength < 8 || maxLength > 12 || minLength > maxLength) throw new ArgumentOutOfRangeException(nameof(minLength), "Password length must be 8-12 characters"); // Normalize computer name to lowercase for consistency var inputBytes = Encoding.UTF8.GetBytes(computerName.ToLowerInvariant()); using (var hmac = new HMACSHA256(_secretKey)) { var hashBytes = hmac.ComputeHash(inputBytes); // Convert hash to Base64 (avoids unprintable bytes) var base64Hash = Convert.ToBase64String(hashBytes); // Replace Base64 chars that are problematic for passwords var sanitizedHash = base64Hash.Replace("+", "x").Replace("/", "y").Replace("=", "z"); // Pick a random length between min/max (deterministic random based on computer name) var passwordLength = new Random(computerName.GetHashCode()).Next(minLength, maxLength + 1); var rawPassword = sanitizedHash.Substring(0, passwordLength); // Ensure password meets common complexity rules (adjust to match your org's policy) return EnsureComplexity(rawPassword); } } private static string EnsureComplexity(string password) { var chars = password.ToCharArray(); var random = new Random(password.GetHashCode()); // Deterministic random seed // Add uppercase if missing if (!chars.Any(char.IsUpper)) { var idx = random.Next(chars.Length); chars[idx] = char.ToUpper(chars[idx]); } // Add digit if missing if (!chars.Any(char.IsDigit)) { var idx = random.Next(chars.Length); chars[idx] = (char)random.Next('0', '9' + 1); } // Add special character if missing var specialChars = new[] { '!', '@', '#', '$', '%', '^', '&', '*' }; if (!chars.Any(c => specialChars.Contains(c))) { var idx = random.Next(chars.Length); chars[idx] = specialChars[random.Next(specialChars.Length)]; } return new string(chars); } }
To share this logic between your UI and PowerShell, package it as a .NET Standard 2.0 class library (compatible with .NET Core 2.0 and .NET Framework 4.6.1+):
- Create a new "Class Library (.NET Standard)" project in Visual Studio
- Add the
PasswordGeneratorclass above - Compile to generate your DLL (e.g.,
OrgPasswordGenerator.dll)
Build a lightweight WinForms UI to input computer names and view generated passwords. Reference your DLL in the WinForms project:
using System; using System.Windows.Forms; namespace PasswordGeneratorUI { public partial class MainForm : Form { public MainForm() { InitializeComponent(); } private void btnGenerate_Click(object sender, EventArgs e) { if (string.IsNullOrWhiteSpace(txtComputerName.Text)) { MessageBox.Show("Please enter a computer name.", "Input Required", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } try { var password = PasswordGenerator.GeneratePassword(txtComputerName.Text); txtPassword.Text = password; } catch (Exception ex) { MessageBox.Show($"Error generating password: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } // Auto-generated form initialization (add via Visual Studio designer) private void InitializeComponent() { this.txtComputerName = new System.Windows.Forms.TextBox(); this.btnGenerate = new System.Windows.Forms.Button(); this.txtPassword = new System.Windows.Forms.TextBox(); this.label1 = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.SuspendLayout(); // txtComputerName this.txtComputerName.Location = new System.Drawing.Point(12, 35); this.txtComputerName.Size = new System.Drawing.Size(220, 23); // btnGenerate this.btnGenerate.Location = new System.Drawing.Point(238, 35); this.btnGenerate.Size = new System.Drawing.Size(120, 23); this.btnGenerate.Text = "Generate Password"; this.btnGenerate.Click += new System.EventHandler(this.btnGenerate_Click); // txtPassword this.txtPassword.Location = new System.Drawing.Point(12, 85); this.txtPassword.ReadOnly = true; this.txtPassword.Size = new System.Drawing.Size(346, 23); // Labels this.label1.Text = "Computer Name:"; this.label1.Location = new System.Drawing.Point(12, 15); this.label2.Text = "Generated Password:"; this.label2.Location = new System.Drawing.Point(12, 65); // MainForm this.ClientSize = new System.Drawing.Size(370, 120); this.Controls.Add(this.label2); this.Controls.Add(this.label1); this.Controls.Add(this.txtPassword); this.Controls.Add(this.btnGenerate); this.Controls.Add(this.txtComputerName); this.Text = "Local Admin Password Generator"; this.ResumeLayout(false); } private System.Windows.Forms.TextBox txtComputerName; private System.Windows.Forms.Button btnGenerate; private System.Windows.Forms.TextBox txtPassword; private System.Windows.Forms.Label label1; private System.Windows.Forms.Label label2; } }
Use your DLL in PowerShell to generate and set the password on local or remote workstations:
Local Workstation Script
# Load the DLL Add-Type -Path "C:\Path\To\OrgPasswordGenerator.dll" # Get local computer name $computerName = $env:COMPUTERNAME # Generate password $password = [PasswordGenerator]::GeneratePassword($computerName) # Set local admin password (replace "Administrator" with your admin account name) $adminUser = Get-LocalUser -Name "Administrator" $securePassword = ConvertTo-SecureString $password -AsPlainText -Force Set-LocalUser -InputObject $adminUser -Password $securePassword Write-Host "Successfully set local admin password for $computerName" -ForegroundColor Green
Remote Workstations (PSRemoting Enabled)
$targetComputers = @("Workstation01", "Workstation02", "Workstation03") $dllNetworkPath = "\\FileServer\Shared\OrgPasswordGenerator.dll" Invoke-Command -ComputerName $targetComputers -ScriptBlock { param($dllPath) Add-Type -Path $dllPath $computerName = $env:COMPUTERNAME $password = [PasswordGenerator]::GeneratePassword($computerName) $adminUser = Get-LocalUser -Name "Administrator" $securePassword = ConvertTo-SecureString $password -AsPlainText -Force Set-LocalUser -InputObject $adminUser -Password $securePassword } -ArgumentList $dllNetworkPath Write-Host "Passwords updated for all target workstations" -ForegroundColor Green
- Protect the Secret Key: If an attacker gains access to
_secretKey, they can generate passwords for any computer in your org. Store it in a secure vault or use DPAPI to encrypt it in your config. - Deterministic vs. Random: This logic is intentionaly deterministic (same computer name = same password) to avoid needing a central password store. If you ever need to rotate passwords, update the secret key.
- Complexity Rules: Adjust the
EnsureComplexitymethod to match your organization's password policy (e.g., add more special characters, enforce specific length ranges).
内容的提问来源于stack exchange,提问作者Appsum Solutions

