Как обычный пользователь Windows может изменить свой пароль из командной строки?

18

В Windows Server 2008 R2 у меня есть стандартный (не администратор) локальный пользователь (не учетная запись Active Directory, хотя сервер находится в домене), который имеет доступ к серверу только через PowerShell Remoting. Пользователь не может войти через RDP.

Я хотел бы, чтобы этот пользователь мог изменить свой пароль. Команда «net user» требует прав администратора, даже если пользователь пытается изменить свой пароль.

Как обычный пользователь может изменить свой пароль из командной строки?

elijahbuck
источник

Ответы:

18

Вот некоторый код PowerShell, чтобы сделать то, что вы ищете с учетными записями домена:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$ADSystemInfo = New-Object -ComObject ADSystemInfo
$type = $ADSystemInfo.GetType()
$user = [ADSI] "LDAP://$($type.InvokeMember('UserName', 'GetProperty', $null, $ADSystemInfo, $null))"
$user.ChangePassword( $oldPassword, $newPassword)

Провайдер ASDI также поддерживает синтаксис WinNT://computername/usernameдля ChangePassword()метода. Однако ADSystemInfoобъект не будет работать для локальных учетных записей компьютера, поэтому просто модифицировать приведенный выше код с помощью WinNT://...синтаксиса невозможно.

(Кто-нибудь хочет предложить изменить код с разницей между локальными и доменными учетными записями?)

С другой стороны, старый NetUserChangePasswordAPI будет работать с локальными (и доменными, если вы укажете доменное имя в синтаксисе NetBIOS) тоже:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$MethodDefinition = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern bool NetUserChangePassword(string domainname, string username, string oldPassword, string newPassword);
'@

$NetAPI32 = Add-Type -MemberDefinition $MethodDefinition -Name 'NetAPI32' -Namespace 'Win32' -PassThru

$NetAPI32::NetUserChangePassword('.', $env:username, $oldPassword, $newPassword)

Этот код предполагает, что вы меняете пароль на локальном компьютере (".").

Эван Андерсон
источник
1
Вы победили меня, но я выиграл для сохранения персонажей;) Есть ли причина, по которой вы знаете, что дополнительные части, которые вы использовали, необходимы? Или просто быть более формальным и правильным?
charleswj81
1
Вы определенно получаете награду за гольф-код. Я просто формальный и правильный ... На самом деле, это в основном делает скрипт немного более удобным для других, которые могут быть вырезаны и вставлены.
Эван Андерсон
1
@ charleswj81 - ответ Эвана более полный. Это автономный PS1скрипт, который можно вызывать с параметрами или без них. Это также намного более читабельно. Кодекс - это все о понимании людьми того, что написал кто-то другой, а не компьютера. Ни одно из решений не будет быстрее другого.
Марк Хендерсон
1
Это выглядит многообещающе, но я должен уточнить, что учетная запись является локальной для системы. Я попытался сделать следующее: ([ADSI]'WinNT://localhost/USERNAME').ChangePassword("OLDPASS", "NEWPASS") Но это вернуло: «Пароль не соответствует требованиям политики паролей ...». Новый пароль соответствует этим требованиям.
elijahbuck
1
На самом деле, после добавления пользователя в «Пользователи удаленного рабочего стола» и попытки изменить пароль таким образом, я получаю ту же ошибку. Я считаю, что правильный способ изменить локальную учетную запись: ([ADSI]'WinNT://localhost/USERNAME').ChangePassword("OLDPASS", "NEWPASS")
elijahbuck
9

На самом деле это довольно просто в PowerShell:

([ADSI]'LDAP://CN=User,CN=Users,DC=domain').ChangePassword('currentpassword','newpassword')
charleswj81
источник
3

Я попробовал оба ответа выше, но безрезультатно, для смены пароля локального администратора, который не присоединен к домену. Копаясь в комментариях, я получил то, что мне было нужно.

Для второй части текущего принятого ответа вы хотите обновить подпись, чтобы использовать longвместо boolвозвращаемого значения, и это можно устранить в документации по системным ошибкам . Итак, вы в конечном итоге:

param (
    [string]$oldPassword = $( Read-Host "Old password"),
    [string]$newPassword = $( Read-Host "New password")
)

$MethodDefinition = @'
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
public static extern **long** NetUserChangePassword(string domainname, string username, string oldPassword, string newPassword);
'@

$NetAPI32 = Add-Type -MemberDefinition $MethodDefinition -Name 'NetAPI32' -Namespace 'Win32' -PassThru

$NetAPI32::NetUserChangePassword('.', $env:username, $oldPassword, $newPassword)

Однако это не сработало для меня. Коды ошибок чередовались от 86 до 2221, в зависимости от того, как я настроил параметры. Собирался сдаться и больше копаться в комментариях, и, наконец, добился успеха в выполнении:

([ADSI]'WinNT://./USERNAME').ChangePassword("OLDPASS‌​", "NEWPASS")

Абсолютно нелепо, что простое ИЗМЕНЕНИЕ пароля локального администратора так сложно в Powershell. Если в вашей системе вообще хранятся строки безопасности, то обновление пароля должно быть выполнено с предоставлением старого пароля, иначе вы рискуете потерять способность правильно расшифровать эти строки безопасности!

gnalck
источник