[英]Change logon account of a service using powershell when password has special symbols
[英]Powershell Service Account Password Change Logon Failure
我正在嘗試使用powershell腳本,允許我更改運行特定服務的用戶帳戶和密碼。
$account="domain\account"
$password="password"
$svc=gwmi win32_service -filter "name='MyService'"
$svc.change($null,$null,$null,$null,$null,$false,$account,$password,$null,$null,$null)
我可以檢查帳戶是否已更改,但是當我嘗試從Service.msc GUI運行該服務時,它會因登錄失敗而失敗。
如果我用來從腳本本身啟動服務,我會收到以下錯誤。
$svc.StartService()
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 0
PSComputerName :
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ReturnValue : 15
PSComputerName :
根據微軟的說法,這是一個登錄錯誤:返回值15。
http://msdn.microsoft.com/en-us/library/windows/desktop/aa384901%28v=vs.85%29.aspx
我已經驗證了密碼數百萬次,當我使用GUI復制並粘貼密碼時,它才能正常工作。
可能是我在腳本中遺漏了一些東西。 (SecurityPolicy在此計算機上不受限制)
並不完全與此線程相關,但對於搜索此類腳本的人可能會有用。
用於掃描計算機/服務器的PowerShell腳本查找在特定帳戶下運行的服務,並停止服務,更改密碼,然后限制服務。
我使用ListServices.psm1模塊, http: //gallery.technet.microsoft.com/scriptcenter/How-to-Clear-Printing-21d59516,讓我更容易完成任務。 一個快速記錄讓我花了15分鍾進行故障排除,看來如果有人試圖設置一個帶有美元符號($)的密碼,請將其包含在“單引號”中而不是“雙引號”中
Import-Module "C:\Tools\ListServices.psm1"
$pass = 'H:5Th7$!pc'
$Username = "abcservice"
$compName = gc env:computername
$newpass = [ADSI]"WinNT://$compName/$Username,user"
$newpass.SetPassword($pass)
$newpass.SetInfo()
Get-OSCServiceList -ComputerName "$compName" -UserName "$Username" | select Name | foreach { $_.Name} | Out-file -FilePath "C:\servicelist\service.txt"
foreach ($name in (Get-Content -Path "C:\servicelist\service.txt")) {
Write-Host "$name"
Stop-Service "$name"
Set-OSCServicePSW -ComputerName "$compName" -ServiceName $name -UserName ".\$Username" - NewPassWord $pass
Start-Service "$name"
}
HTH有人在那里。
在設置服務帳戶之前,需要為用戶設置SeServiceLogonRight權限。
Set-Privileges $account "SeServiceLogonRight"
$svc=gwmi win32_service -filter "name='MyService'"
$svc.change($null,$null,$null,$null,$null,$false,$account,$password,$null,$null,$null)
使用LSA的Set-Privileges功能示例:
function Set-Privileges
{
param(
$username,
$Privilege
)
# C# code from http://www.codeproject.com/Articles/4863/LSA-Functions-Privileges-and-Impersonation
$Source = @"
using System;
using System.Text;
using System.Runtime.InteropServices;
namespace Privileges {
public class LsaUtility {
// Import the LSA functions
[DllImport("advapi32.dll", PreserveSig=true)]
private static extern UInt32 LsaOpenPolicy(
ref LSA_UNICODE_STRING SystemName,
ref LSA_OBJECT_ATTRIBUTES ObjectAttributes,
Int32 DesiredAccess,
out IntPtr PolicyHandle
);
[DllImport("advapi32.dll", SetLastError=true, PreserveSig=true)]
private static extern int LsaAddAccountRights(
IntPtr PolicyHandle,
IntPtr AccountSid,
LSA_UNICODE_STRING[] UserRights,
int CountOfRights);
[DllImport("advapi32")]
public static extern void FreeSid(IntPtr pSid);
[DllImport( "advapi32.dll", CharSet=CharSet.Auto, SetLastError=true, PreserveSig=true)]
private static extern bool LookupAccountName(
string lpSystemName, string lpAccountName,
IntPtr psid,
ref int cbsid,
StringBuilder domainName, ref int cbdomainLength, ref int use );
[DllImport( "advapi32.dll")]
private static extern bool IsValidSid(IntPtr pSid);
[DllImport("advapi32.dll")]
private static extern int LsaClose(IntPtr ObjectHandle);
[DllImport("kernel32.dll")]
private static extern int GetLastError();
[DllImport("advapi32.dll")]
private static extern int LsaNtStatusToWinError(int status);
// define the structures
[StructLayout(LayoutKind.Sequential)]
private struct LSA_UNICODE_STRING {
public UInt16 Length;
public UInt16 MaximumLength;
public IntPtr Buffer;
}
[StructLayout(LayoutKind.Sequential)]
private struct LSA_OBJECT_ATTRIBUTES{
public int Length;
public IntPtr RootDirectory;
public LSA_UNICODE_STRING ObjectName;
public UInt32 Attributes;
public IntPtr SecurityDescriptor;
public IntPtr SecurityQualityOfService;}
// enum all policies
private enum LSA_AccessPolicy : long{
POLICY_VIEW_LOCAL_INFORMATION = 0x00000001L,
POLICY_VIEW_AUDIT_INFORMATION = 0x00000002L,
POLICY_GET_PRIVATE_INFORMATION = 0x00000004L,
POLICY_TRUST_ADMIN = 0x00000008L,
POLICY_CREATE_ACCOUNT = 0x00000010L,
POLICY_CREATE_SECRET = 0x00000020L,
POLICY_CREATE_PRIVILEGE = 0x00000040L,
POLICY_SET_DEFAULT_QUOTA_LIMITS = 0x00000080L,
POLICY_SET_AUDIT_REQUIREMENTS = 0x00000100L,
POLICY_AUDIT_LOG_ADMIN = 0x00000200L,
POLICY_SERVER_ADMIN = 0x00000400L,
POLICY_LOOKUP_NAMES = 0x00000800L,
POLICY_NOTIFICATION = 0x00001000L
}
/// <summary>Adds a privilege to an account</summary>
/// <param name="accountName">Name of an account - "domain\account" or only "account"</param>
/// <param name="privilegeName">Name ofthe privilege</param>
/// <returns>The windows error code returned by LsaAddAccountRights</returns>
public static int SetRight(String accountName, String privilegeName){
int winErrorCode = 0; //contains the last error
//pointer an size for the SID
IntPtr sid = IntPtr.Zero;
int sidSize = 0;
//StringBuilder and size for the domain name
StringBuilder domainName = new StringBuilder();
int nameSize = 0;
//account-type variable for lookup
int accountType = 0;
//get required buffer size
LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
//allocate buffers
domainName = new StringBuilder(nameSize);
sid = Marshal.AllocHGlobal(sidSize);
//lookup the SID for the account
bool result = LookupAccountName(String.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
//say what you're doing for debug
//Console.WriteLine("LookupAccountName result = "+result);
//Console.WriteLine("IsValidSid: "+IsValidSid(sid));
//Console.WriteLine("LookupAccountName domainName: "+domainName.ToString());
if( ! result ){
winErrorCode = GetLastError();
Console.WriteLine("LookupAccountName failed: "+ winErrorCode);
}else{
//initialize an empty unicode-string
LSA_UNICODE_STRING systemName = new LSA_UNICODE_STRING();
//combine all policies
int access = (int)(
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
LSA_AccessPolicy.POLICY_CREATE_ACCOUNT |
LSA_AccessPolicy.POLICY_CREATE_PRIVILEGE |
LSA_AccessPolicy.POLICY_CREATE_SECRET |
LSA_AccessPolicy.POLICY_GET_PRIVATE_INFORMATION |
LSA_AccessPolicy.POLICY_LOOKUP_NAMES |
LSA_AccessPolicy.POLICY_NOTIFICATION |
LSA_AccessPolicy.POLICY_SERVER_ADMIN |
LSA_AccessPolicy.POLICY_SET_AUDIT_REQUIREMENTS |
LSA_AccessPolicy.POLICY_SET_DEFAULT_QUOTA_LIMITS |
LSA_AccessPolicy.POLICY_TRUST_ADMIN |
LSA_AccessPolicy.POLICY_VIEW_AUDIT_INFORMATION |
LSA_AccessPolicy.POLICY_VIEW_LOCAL_INFORMATION
);
//initialize a pointer for the policy handle
IntPtr policyHandle = IntPtr.Zero;
//these attributes are not used, but LsaOpenPolicy wants them to exists
LSA_OBJECT_ATTRIBUTES ObjectAttributes = new LSA_OBJECT_ATTRIBUTES();
ObjectAttributes.Length = 0;
ObjectAttributes.RootDirectory = IntPtr.Zero;
ObjectAttributes.Attributes = 0;
ObjectAttributes.SecurityDescriptor = IntPtr.Zero;
ObjectAttributes.SecurityQualityOfService = IntPtr.Zero;
//get a policy handle
int resultPolicy = (int)LsaOpenPolicy(ref systemName, ref ObjectAttributes, access, out policyHandle);
winErrorCode = LsaNtStatusToWinError(resultPolicy);
if(winErrorCode != 0){
Console.WriteLine("OpenPolicy failed: "+ winErrorCode);
}else{
//Now that we have the SID an the policy,
//we can add rights to the account.
//initialize an unicode-string for the privilege name
LSA_UNICODE_STRING[] userRights = new LSA_UNICODE_STRING[1];
userRights[0] = new LSA_UNICODE_STRING();
userRights[0].Buffer = Marshal.StringToHGlobalUni(privilegeName);
userRights[0].Length = (UInt16)( privilegeName.Length * UnicodeEncoding.CharSize );
userRights[0].MaximumLength = (UInt16)( (privilegeName.Length+1) * UnicodeEncoding.CharSize );
//add the right to the account
int res = LsaAddAccountRights(policyHandle, sid, userRights, 1);
winErrorCode = LsaNtStatusToWinError(res);
if(winErrorCode != 0){
Console.WriteLine("LsaAddAccountRights failed: "+ winErrorCode);
}else{
Console.WriteLine("LsaAddAccountRights successful");
}
LsaClose(policyHandle);
}
FreeSid(sid);
}
return winErrorCode;
}
}
}
"@
Add-Type -TypeDefinition $Source -Language CSharp
[Privileges.LsaUtility]::SetRight($username, $Privilege) | Out-Null
}
如果您只是更新服務帳戶的密碼,而不是更改哪個帳戶運行該服務,您可能只需更改密碼本身就可以獲得更多運氣。 我對Win32_Service.Change()的調用取得了成功:
$service.Change($Null,$Null,$Null,$Null,$Null,$Null,$Null,$Password)
這一直對我來說更新密碼。
您是否嘗試在更改密碼之前停止服務?
以下是為我工作
$account="domain\account"
$password="password"
$svc=gwmi win32_service -filter "name='MyService'"
$svc.StopService();
$result = $svc.change($null,$null,$null,$null,$null,$false,$account,$password,$null,$null,$null)
if ($result.ReturnValue -eq '0') {write-host "Password changed"} else {write-host "Error: $result.ReturnValue"};
$svc.StartService();
我懷疑你的密碼可能至少有一個在插值字符串中有特殊含義的字符。 嘗試單引號:
$password='password'
一般來說,默認情況下使用單引號是一個更好的習慣,當你特別想要插入某些內容時,只使用雙引號。
順便說一句,還要驗證您使用的是正確的服務名稱。 您需要使用Name屬性而不是DisplayName。 在提示符下嘗試gwmi win32_service -filter "name='MyService'"
並確保不會返回錯誤。 不過,這可能是單引號和雙引號問題。
我知道這個問題是在幾年前發布的,但是,我剛剛遇到了同樣的問題,幾乎完全相同的代碼,導致完全相同的返回。 我使用的安裝程序利用subinacl.exe來設置權限。 以下文章介紹了如何設置這些權限: http : //www.waynezim.com/2010/02/how-to-set-permission-on-a-service-using-subinacl/
我只是在安裝中添加了'i'開關,並將用戶添加到適當的組(如果適用)。 考慮到文章的年齡,我希望有人覺得這很有用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.