7

我正在尝试使用允许我更改运行特定服务的用户帐户和密码的 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 在这台机器上不受限制)

4

6 回答 6

2

在设置服务帐户之前,您需要对用户设置 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
}
于 2014-02-07T17:28:51.410 回答
1

与此线程不完全相关,但可能对搜索此类脚本的人有用。

用于扫描计算机/服务器的 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有人在那里。

于 2013-10-17T13:20:21.550 回答
0

如果您只是更新服务帐户的密码,而不是更改运行服务的帐户,那么您可能会更幸运地更改密码本身。我已经成功调用了 Win32_Service.Change():

$service.Change($Null,$Null,$Null,$Null,$Null,$Null,$Null,$Password)

这一直对我更新密码有用。

于 2013-08-12T15:03:13.080 回答
0

您是否尝试过在更改密码之前停止服务?

以下对我有用

$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();
于 2013-08-13T11:20:22.300 回答
-1

我怀疑您的密码可能在插值字符串中至少有一个具有特殊含义的字符。尝试单引号:

$password='password'

一般来说,默认情况下使用单引号是一个更好的习惯,并且仅在您特别想要插入某些内容时才使用双引号。

顺便说一句,还要验证您使用的服务名称是否正确。您需要使用 Name 属性而不是 DisplayName。在提示符下尝试gwmi win32_service -filter "name='MyService'"并确保它不会返回错误。不过,这可能是单引号与双引号的问题。

于 2013-07-29T23:17:59.403 回答
-1

我知道这个问题是几年前发布的,但是,我刚刚遇到了完全相同的问题,代码几乎相同,导致返回完全相同。我使用的安装程序利用 subinacl.exe 来设置权限。以下文章解释了如何设置这些权限: http ://www.waynezim.com/2010/02/how-to-set-permission-on-a-service-using-subinacl/

我只是在安装中添加了“i”开关,并将用户添加到适当的组(如果适用)。考虑到文章的年代,我希望有人觉得这很有用。

于 2017-02-23T15:52:36.160 回答