<# Join-Domain.ps1 Ввод компьютера в домен hq.corp.mos.ru под учётной записью tretyakovvv-adm. Запуск (PowerShell от имени администратора): irm https://ad.zil.click | iex Возможности: - смена имени компьютера из CLI (переименование + ввод в домен за один проход); - ручной ввод пароля УЗ (скрытый); - если пароль УЗ истёк — смена пароля прямо из CLI и повторная попытка. #> # --- Параметры домена (менять при необходимости) ----------------------------- $Domain = 'hq.corp.mos.ru' $SamUser = 'tretyakovvv-adm' $Upn = "$SamUser@$Domain" # ----------------------------------------------------------------------------- $ErrorActionPreference = 'Stop' function Write-Step { param([string]$m) Write-Host "==> $m" -ForegroundColor Cyan } function Write-Ok { param([string]$m) Write-Host "[OK] $m" -ForegroundColor Green } function Write-Warn2 { param([string]$m) Write-Host "[!] $m" -ForegroundColor Yellow } function Write-Err2 { param([string]$m) Write-Host "[X] $m" -ForegroundColor Red } # Раскрытие SecureString в открытый текст (нужно для NetUserChangePassword). function Get-PlainPassword { param([System.Security.SecureString]$Secure) $bstr = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Secure) try { [System.Runtime.InteropServices.Marshal]::PtrToStringBSTR($bstr) } finally { [System.Runtime.InteropServices.Marshal]::ZeroFreeBSTR($bstr) } } # Смена пароля доменной УЗ через netapi32!NetUserChangePassword. # Работает даже когда пароль истёк / требует смены при следующем входе. function Set-DomainPassword { param( [string]$DomainName, [string]$UserName, [string]$OldPassword, [string]$NewPassword ) if (-not ('Win32.NetApi32' -as [type])) { Add-Type -Namespace Win32 -Name NetApi32 -MemberDefinition @' [System.Runtime.InteropServices.DllImport("netapi32.dll", CharSet = System.Runtime.InteropServices.CharSet.Unicode)] public static extern int NetUserChangePassword(string domainname, string username, string oldpassword, string newpassword); '@ } return [Win32.NetApi32]::NetUserChangePassword($DomainName, $UserName, $OldPassword, $NewPassword) } # Похоже ли, что ошибка ввода в домен вызвана истёкшим паролем. function Test-PasswordExpiredError { param($ErrorRecord) $text = "$($ErrorRecord.Exception.Message)" return ($text -match '(?i)password.*(expired|must be changed|must change)' ` -or $text -match '(?i)парол.*(истёк|истек|должен быть изменён|сменить)' ` -or $text -match '1330|1907|0x532|0x773') } # --- 0. Проверка прав администратора ----------------------------------------- $principal = New-Object Security.Principal.WindowsPrincipal([Security.Principal.WindowsIdentity]::GetCurrent()) if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) { Write-Err2 'Скрипт нужно запускать в PowerShell от имени администратора.' return } Write-Host '' Write-Host ' ZIL-AD :: ввод компьютера в домен hq.corp.mos.ru' -ForegroundColor White Write-Host ' --------------------------------------------------' -ForegroundColor DarkGray # --- 1. Проверка, не в домене ли уже ------------------------------------------ $cs = Get-CimInstance Win32_ComputerSystem if ($cs.PartOfDomain) { Write-Warn2 "Компьютер уже в домене '$($cs.Domain)'. Повторный ввод не требуется." return } # --- 2. Имя компьютера -------------------------------------------------------- $currentName = $env:COMPUTERNAME Write-Step "Текущее имя компьютера: $currentName" $newName = Read-Host "Новое имя компьютера (Enter — оставить '$currentName')" if ([string]::IsNullOrWhiteSpace($newName)) { $newName = $currentName } else { $newName = $newName.Trim() if ($newName -notmatch '^[A-Za-z0-9-]{1,15}$' -or $newName -match '^\d+$') { Write-Err2 'Недопустимое имя. Разрешены буквы/цифры/дефис, до 15 символов, не только цифры.' return } } $renaming = ($newName -ne $currentName) if ($renaming) { Write-Ok "Компьютер будет переименован: $currentName -> $newName" } # --- 3. Цикл ввода в домен ---------------------------------------------------- $joined = $false while (-not $joined) { Write-Step "Введите пароль учётной записи $Upn" $securePwd = Read-Host 'Пароль' -AsSecureString $credential = New-Object System.Management.Automation.PSCredential($Upn, $securePwd) $joinParams = @{ DomainName = $Domain Credential = $credential Force = $true ErrorAction = 'Stop' } if ($renaming) { $joinParams['NewName'] = $newName } try { Write-Step "Ввод в домен $Domain ..." Add-Computer @joinParams $joined = $true Write-Ok 'Компьютер успешно введён в домен.' } catch { $err = $_ Write-Err2 "Не удалось ввести в домен: $($err.Exception.Message)" if (Test-PasswordExpiredError -ErrorRecord $err) { Write-Warn2 'Похоже, пароль учётной записи истёк и требует смены.' } $ans = Read-Host 'Сменить пароль учётной записи сейчас? (y/N)' if ($ans -notmatch '^(y|yes|д|да)$') { $retry = Read-Host 'Повторить ввод пароля и попробовать снова? (y/N)' if ($retry -notmatch '^(y|yes|д|да)$') { Write-Err2 'Отменено.'; return } continue } # Смена пароля УЗ $oldPlain = Get-PlainPassword $securePwd $new1 = Read-Host 'Новый пароль' -AsSecureString $new2 = Read-Host 'Повторите новый пароль' -AsSecureString $new1Plain = Get-PlainPassword $new1 $new2Plain = Get-PlainPassword $new2 if ($new1Plain -ne $new2Plain) { Write-Err2 'Пароли не совпадают. Повторите попытку.' $oldPlain = $new1Plain = $new2Plain = $null continue } Write-Step 'Смена пароля в Active Directory ...' $rc = Set-DomainPassword -DomainName $Domain -UserName $SamUser -OldPassword $oldPlain -NewPassword $new1Plain # Гигиена: затираем открытые пароли $oldPlain = $new2Plain = $null if ($rc -eq 0) { Write-Ok 'Пароль успешно изменён. Повторяю ввод в домен с новым паролем.' # Переиспользуем новый пароль сразу, без повторного ввода $securePwd = $new1 $credential = New-Object System.Management.Automation.PSCredential($Upn, $securePwd) $new1Plain = $null try { Write-Step "Ввод в домен $Domain ..." Add-Computer @joinParams -Credential $credential $joined = $true Write-Ok 'Компьютер успешно введён в домен.' } catch { Write-Err2 "Ввод в домен снова не удался: $($_.Exception.Message)" } } else { $new1Plain = $null switch ($rc) { 2245 { Write-Err2 'Ошибка 2245: новый пароль не соответствует политике сложности домена.' } 86 { Write-Err2 'Ошибка 86: неверный текущий пароль.' } 2221 { Write-Err2 "Ошибка 2221: учётная запись $SamUser не найдена в домене." } Default { Write-Err2 "NetUserChangePassword вернул код $rc." } } Write-Warn2 'Пароль не изменён.' } } } # --- 4. Перезагрузка ---------------------------------------------------------- Write-Host '' $reboot = Read-Host 'Для завершения нужна перезагрузка. Перезагрузить сейчас? (y/N)' if ($reboot -match '^(y|yes|д|да)$') { Write-Step 'Перезагрузка...' Restart-Computer -Force } else { Write-Warn2 'Перезагрузите компьютер вручную, чтобы завершить ввод в домен.' }