如何使用不同域账户运行本地PowerShell库中的函数?
Absolutely doable! You don’t need to rely on remote Invoke-Command to run your existing PowerShell library functions under a different domain account locally. Here are two reliable approaches tailored to your scenario:
1. Run as a New Local PowerShell Process (Recommended)
This method spins up a fresh PowerShell process under your target domain account, loads your script library, and executes the required function. It’s the most reliable option because the entire process runs in the domain account’s full security context—perfect for domain-authenticated operations like SQL backups or accessing network shares.
Example Implementation
# Define your configuration values (pull these from your XML config in production) $domainAccount = "DOMAIN\SQLBackupServiceAccount" $libraryPath = "C:\AutomationLib\SqlBackupFunctions.ps1" $sqlInstance = "PRODSQL01" $dbName = "CustomerTransactions" $backupPath = "\\DomainFileServer\SQLBackups\CustomerTransactions.bak" # Securely retrieve the credential (in production, load from encrypted config instead of prompt) $credential = Get-Credential -UserName $domainAccount -Message "Enter password for SQL backup service account" # Build the command to load the library and execute your backup function $executionCommand = @" & '$libraryPath'; Backup-SqlDatabase -SqlInstance '$sqlInstance' -Database '$dbName' -BackupFile '$backupPath' "@ # Launch the process under the domain account Start-Process powershell.exe -Credential $credential -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command `"$executionCommand`"" -Wait -NoNewWindow
Key Tips for This Method
- Use
-Waitto ensure your scheduling engine waits for the backup to complete before proceeding to the next step. -NoNewWindowkeeps output visible in your current console (or use-RedirectStandardOutput/-RedirectStandardErrorto log results to files).-NoProfileskips loading user-specific PowerShell profiles, avoiding unexpected conflicts with your automation library.
2. Temporary Identity Impersonation in the Current Session
If you need to run the function within your existing PowerShell session (instead of spawning a new process), you can temporarily impersonate the domain account. Note that this method has limitations—most notably, it can’t resolve the "double-hop" problem for network resources (like accessing a remote SQL server and a network backup share in the same operation).
Example Implementation
# Add .NET interop code for Windows identity impersonation Add-Type @" using System; using System.Runtime.InteropServices; public class ImpersonationHelper { [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, out IntPtr phToken); [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern bool DuplicateToken(IntPtr hToken, int impersonationLevel, out IntPtr hNewToken); [DllImport("kernel32.dll", CharSet = CharSet.Auto)] public static extern bool CloseHandle(IntPtr handle); public const int LOGON32_LOGON_INTERACTIVE = 2; public const int LOGON32_PROVIDER_DEFAULT = 0; } "@ # Wrapper function to execute code under impersonated identity function Invoke-Impersonated { [CmdletBinding()] param( [Parameter(Mandatory=$true)] [PSCredential]$Credential, [Parameter(Mandatory=$true)] [ScriptBlock]$ScriptBlock ) $tokenPtr = [IntPtr]::Zero $duplicateTokenPtr = [IntPtr]::Zero try { # Log on with the target domain account $logonSuccess = [ImpersonationHelper]::LogonUser( $Credential.GetNetworkCredential().UserName, $Credential.GetNetworkCredential().Domain, $Credential.GetNetworkCredential().Password, [ImpersonationHelper]::LOGON32_LOGON_INTERACTIVE, [ImpersonationHelper]::LOGON32_PROVIDER_DEFAULT, [ref]$tokenPtr ) if (-not $logonSuccess) { throw "Logon failed with error code: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" } # Duplicate token for impersonation $duplicateSuccess = [ImpersonationHelper]::DuplicateToken($tokenPtr, 2, [ref]$duplicateTokenPtr) if (-not $duplicateSuccess) { throw "Token duplication failed with error code: $([System.Runtime.InteropServices.Marshal]::GetLastWin32Error())" } # Impersonate the identity and run the script block $identity = New-Object System.Security.Principal.WindowsIdentity($duplicateTokenPtr) $impersonationContext = $identity.Impersonate() & $ScriptBlock $impersonationContext.Undo() } finally { # Clean up unmanaged resources if ($tokenPtr -ne [IntPtr]::Zero) { [ImpersonationHelper]::CloseHandle($tokenPtr) } if ($duplicateTokenPtr -ne [IntPtr]::Zero) { [ImpersonationHelper]::CloseHandle($duplicateTokenPtr) } } } # Usage: Run your backup function under the domain account $domainCred = Get-Credential -UserName "DOMAIN\SQLBackupServiceAccount" Invoke-Impersonated -Credential $domainCred -ScriptBlock { . "C:\AutomationLib\SqlBackupFunctions.ps1" Backup-SqlDatabase -SqlInstance "PRODSQL01" -Database "CustomerTransactions" -BackupFile "C:\LocalBackups\CustomerTransactions.bak" }
Critical Limitation to Note
Impersonation doesn’t pass your identity to remote servers (the "double-hop" issue). If your backup needs to write to a network share and authenticate to SQL, this method will fail—stick with the new process approach instead.
内容的提问来源于stack exchange,提问作者Zoltan Hernyak

