W jaki sposób standardowy użytkownik systemu Windows może zmienić swoje hasło z wiersza poleceń?

18

W systemie Windows Server 2008 R2 mam standardowego lokalnego użytkownika (niebędącego administratorem) (nie jest to konto Active Directory, chociaż serwer znajduje się w domenie), który ma dostęp do serwera tylko za pomocą usługi PowerShell Remoting. Użytkownik nie może zalogować się przez RDP.

Chciałbym, aby ten użytkownik mógł zmienić swoje hasło. Polecenie „użytkownik sieci” wymaga uprawnień administratora, nawet jeśli użytkownik próbuje zmienić własne hasło.

Jak zwykły użytkownik może zmienić swoje hasło z wiersza poleceń?

elijahbuck
źródło

Odpowiedzi:

18

Oto kod PowerShell do robienia tego, czego szukasz z kontami domeny:

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)

Dostawca ASDI obsługuje również składnię WinNT://computername/usernametej ChangePassword()metody. ADSystemInfoObiekt, jednak nie będą działać dla kont maszynowych lokalnego, tak właśnie modernizacji powyższy kod z WinNT://...składnia nie jest wykonalne.

(Czy ktoś chce zasugerować edycję kodu w / w celu rozróżnienia kont lokalnych i domenowych?)

W zupełnie innym rozwiązaniu stary NetUserChangePasswordinterfejs API będzie działał również z kontami lokalnymi (i domenowymi, pod warunkiem, że określisz nazwę domeny w składni 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)

Ten kod zakłada, że ​​zmieniasz hasło na komputerze lokalnym („.”).

Evan Anderson
źródło
1
Pokonałeś mnie, ale wygrywam dla zachowania postaci;) Czy wiesz, że dodatkowe części, których użyłeś, są konieczne? A może po prostu bardziej formalny i właściwy?
charleswj81
1
Zdecydowanie otrzymasz nagrodę Code Golf. Jestem po prostu formalny i właściwy ... Właściwie to głównie sprawia, że ​​skrypt jest trochę bardziej użyteczny dla innych, którzy mogą być typami do wycinania i wklejania.
Evan Anderson
1
@ charleswj81 - odpowiedź Evana jest znacznie bardziej kompletna. Jest to samodzielny PS1skrypt, który można wywoływać z parametrami lub bez nich. Jest też o wiele bardziej czytelny. Kod polega na tym, aby ludzie rozumieli, co napisał ktoś inny, a nie komputer. Żadne z rozwiązań nie będzie szybsze od drugiego.
Mark Henderson
1
Wygląda to obiecująco, ale powinienem wyjaśnić, że konto jest lokalne dla systemu. Próbowałem wykonać następujące czynności: ([ADSI]'WinNT://localhost/USERNAME').ChangePassword("OLDPASS", "NEWPASS") Ale to zwróciło „Hasło nie spełnia wymagań polityki haseł ...”. Nowe hasło spełnia te wymagania.
elijahbuck
1
W rzeczywistości po dodaniu użytkownika do „Pulpitu zdalnego” i próbie zmiany hasła w ten sposób otrzymuję ten sam błąd. Uważam, że poprawnym sposobem zmiany konta lokalnego jest: ([ADSI]'WinNT://localhost/USERNAME').ChangePassword("OLDPASS", "NEWPASS")
elijahbuck
9

Jest to w rzeczywistości dość proste w PowerShell:

([ADSI]'LDAP://CN=User,CN=Users,DC=domain').ChangePassword('currentpassword','newpassword')
charleswj81
źródło
3

Próbowałem obu powyższych odpowiedzi bezskutecznie, aby zmienić hasło lokalnego administratora, który nie jest przyłączony do domeny. Przeglądając komentarze, dostałem jednak to, czego potrzebowałem.

W przypadku drugiej części obecnie akceptowanej odpowiedzi chcesz zaktualizować podpis, aby używał longzamiast boolwartości zwracanej, i można je rozwiązać w dokumentacji kodów błędów systemu . W rezultacie otrzymujesz:

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)

Nie działało to jednak dla mnie. Kody błędów występowały naprzemiennie między 86 a 2221, w zależności od tego, jak skonfigurowałem parametry. Już miał się poddać i wkopać więcej w komentarze, aż w końcu odniósł sukces w:

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

To absurdalne, że prosta ZMIANA lokalnego hasła administratora jest tak skomplikowana w PowerShell. Jeśli w ogóle przechowujesz bezpieczne ciągi, to musisz je zaktualizować, podając stare hasło, inaczej ryzykujesz utratą możliwości prawidłowego odszyfrowania tych bezpiecznych ciągów!

gnalck
źródło