param([switch]$Auto, [switch]$WindowsOnly, [switch]$OfficeOnly) # ===================================================================== # KMS Activation Menu (GVLK, корпоративный KMS-хост) # Ключи Windows взяты со страницы Microsoft Learn (KMS client activation and product keys) # Запуск: irm https://kms.example.local | iex # Без меню: & ([scriptblock]::Create((irm https://kms.example.local))) -Auto # ===================================================================== # ---------- Настройки ---------- $KmsHost = "kms.rave-tech.ru" # пусто = использовать автопоиск по DNS SRV (_vlmcs._tcp) $KmsPort = 1688 $LogUrl = "" # необязательно: URL для POST-лога (JSON), пусто = выключено try { [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 } catch {} function W($t, $c = 'Gray') { Write-Host $t -ForegroundColor $c } function Pause2 { Read-Host "`nEnter для возврата" | Out-Null } function Test-Admin { ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } function Send-Log($action) { if (-not $LogUrl) { return } try { $body = @{ host = $env:COMPUTERNAME; user = $env:USERNAME; action = $action; time = (Get-Date).ToString('s') } | ConvertTo-Json Invoke-RestMethod -Uri $LogUrl -Method Post -Body $body -ContentType 'application/json' -TimeoutSec 5 | Out-Null } catch {} } # Запуск cscript: Run - показать вывод, RunQ - скрыть function Run($file, [string[]]$a) { & cscript.exe //nologo $file @a | Out-Host } function RunQ($file, [string[]]$a) { & cscript.exe //nologo $file @a | Out-Null } function Test-Kms { if (-not $KmsHost) { return $true } try { $c = New-Object Net.Sockets.TcpClient $ok = $c.BeginConnect($KmsHost, $KmsPort, $null, $null).AsyncWaitHandle.WaitOne(3000) if ($ok) { $ok = $c.Connected } $c.Close() return $ok } catch { return $false } } # ===================================================================== # WINDOWS # Fam = семейство сборки, Ed = EditionID системы # ===================================================================== function K($fam, $ed, $name, $key) { [pscustomobject]@{ Fam = $fam; Ed = $ed; Name = $name; Key = $key } } $WinKeys = @( K 'W10' 'Professional' 'Windows 10/11 Pro' 'W269N-WFGWX-YVC9B-4J6C9-T83GX' K 'W10' 'ProfessionalN' 'Windows 10/11 Pro N' 'MH37W-N47XK-V7XM9-C7227-GCQG9' K 'W10' 'ProfessionalWorkstation' 'Windows 10/11 Pro for Workstations' 'NRG8B-VKK3Q-CXVCJ-9G2XF-6Q84J' K 'W10' 'ProfessionalWorkstationN' 'Windows 10/11 Pro for Workstations N' '9FNHH-K3HBT-3W4TD-6383H-6XYWF' K 'W10' 'ProfessionalEducation' 'Windows 10/11 Pro Education' '6TP4R-GNPTD-KYYHQ-7B7DP-J447Y' K 'W10' 'ProfessionalEducationN' 'Windows 10/11 Pro Education N' 'YVWGF-BXNMC-HTQYQ-CPQ99-66QFC' K 'W10' 'Education' 'Windows 10/11 Education' 'NW6C2-QMPVW-D7KKK-3GKT6-VCFB2' K 'W10' 'EducationN' 'Windows 10/11 Education N' '2WH4N-8QGBV-H22JP-CT43Q-MDWWJ' K 'W10' 'Enterprise' 'Windows 10/11 Enterprise' 'NPPR9-FWDCX-D2C8J-H872K-2YT43' K 'W10' 'EnterpriseN' 'Windows 10/11 Enterprise N' 'DPH2V-TTNVB-4X9Q3-TJR4H-KHJW4' K 'W10' 'EnterpriseG' 'Windows 10/11 Enterprise G' 'YYVX9-NTFWV-6MDM3-9PT4T-4M68B' K 'W10' 'EnterpriseGN' 'Windows 10/11 Enterprise G N' '44RPN-FTY23-9VTTB-MP9BX-T84FV' K 'LTSC' 'EnterpriseS' 'Windows 10/11 Enterprise LTSC 2019/2021/2024' 'M7XTQ-FN8P6-TTKYV-9D4CC-J462D' K 'LTSC' 'EnterpriseSN' 'Windows 10/11 Enterprise N LTSC 2019/2021/2024' '92NFX-8DJQP-P6BBQ-THF9C-7CG2H' K 'LTSC' 'IoTEnterpriseS' 'Windows IoT Enterprise LTSC 2021/2024' 'KBN8V-HFGQ4-MGXVD-347P6-PDQGT' K 'LTSB2016' 'EnterpriseS' 'Windows 10 Enterprise LTSB 2016' 'DCPHK-NFMTC-H88MJ-PFHPY-QJ4BJ' K 'LTSB2016' 'EnterpriseSN' 'Windows 10 Enterprise N LTSB 2016' 'QFFDN-GRT3P-VKWWX-X7T3R-8B639' K 'LTSB2015' 'EnterpriseS' 'Windows 10 Enterprise LTSB 2015' 'WNMTR-4C88C-JK8YV-HQ7T2-76DF9' K 'LTSB2015' 'EnterpriseSN' 'Windows 10 Enterprise N LTSB 2015' '2F77B-TNFGY-69QQF-B8YKP-D69TJ' K 'Win81' 'Professional' 'Windows 8.1 Pro' 'GCRJD-8NW9H-F2CDX-CCM8D-9D6T9' K 'Win81' 'ProfessionalN' 'Windows 8.1 Pro N' 'HMCNV-VVBFX-7HMBH-CTY9B-B4FXY' K 'Win81' 'Enterprise' 'Windows 8.1 Enterprise' 'MHF9N-XY6XB-WVXMC-BTDCT-MKKG7' K 'Win81' 'EnterpriseN' 'Windows 8.1 Enterprise N' 'TT4HM-HN7YT-62K67-RGRQJ-JFFXW' K 'Win8' 'Professional' 'Windows 8 Pro' 'NG4HW-VH26C-733KW-K6F98-J8CK4' K 'Win8' 'ProfessionalN' 'Windows 8 Pro N' 'XCVCF-2NXM9-723PB-MHCB7-2RYQQ' K 'Win8' 'Enterprise' 'Windows 8 Enterprise' '32JNW-9KQ84-P47T8-D8GGY-CWCK7' K 'Win8' 'EnterpriseN' 'Windows 8 Enterprise N' 'JMNMF-RHW7P-DMY6X-RF3DR-X2BQT' K 'Win7' 'Professional' 'Windows 7 Professional' 'FJ82H-XT6CR-J8D7P-XQJJ2-GPDD4' K 'Win7' 'ProfessionalN' 'Windows 7 Professional N' 'MRPKT-YTG23-K7D7T-X2JMM-QY7MG' K 'Win7' 'ProfessionalE' 'Windows 7 Professional E' 'W82YF-2Q76Y-63HXB-FGJG9-GF7QX' K 'Win7' 'Enterprise' 'Windows 7 Enterprise' '33PXH-7Y6KF-2VJC9-XBBR8-HVTHH' K 'Win7' 'EnterpriseN' 'Windows 7 Enterprise N' 'YDRBP-3D83W-TY26F-D46B2-XCKRJ' K 'Win7' 'EnterpriseE' 'Windows 7 Enterprise E' 'C29WB-22CC8-VJ326-GHFJW-H9DH4' K 'Srv2025' 'ServerStandard' 'Windows Server 2025 Standard' 'TVRH6-WHNXV-R9WG3-9XRFY-MY832' K 'Srv2025' 'ServerDatacenter' 'Windows Server 2025 Datacenter' 'D764K-2NDRG-47T6Q-P8T8W-YP6DF' K 'Srv2025' 'ServerTurbine' 'Windows Server 2025 Datacenter: Azure Edition' 'XGN3F-F394H-FD2MY-PP6FD-8MCRC' K 'Srv2022' 'ServerStandard' 'Windows Server 2022 Standard' 'VDYBN-27WPP-V4HQT-9VMD4-VMK7H' K 'Srv2022' 'ServerDatacenter' 'Windows Server 2022 Datacenter' 'WX4NM-KYWYW-QJJR4-XV3QB-6VM33' K 'Srv2022' 'ServerTurbine' 'Windows Server 2022 Datacenter: Azure Edition' 'NTBV8-9K7Q8-V27C6-M2BTV-KHMXV' K 'Srv2019' 'ServerStandard' 'Windows Server 2019 Standard' 'N69G4-B89J2-4G8F4-WWYCC-J464C' K 'Srv2019' 'ServerDatacenter' 'Windows Server 2019 Datacenter' 'WMDGN-G9PQG-XVVXX-R3X43-63DFG' K 'Srv2019' 'ServerSolution' 'Windows Server 2019 Essentials' 'WVDHN-86M7X-466P6-VHXV7-YY726' K 'Srv2016' 'ServerStandard' 'Windows Server 2016 Standard' 'WC2BQ-8NRM3-FDDYY-2BFGV-KHKQY' K 'Srv2016' 'ServerDatacenter' 'Windows Server 2016 Datacenter' 'CB7KF-BWN84-R7R2Y-793K2-8XDDG' K 'Srv2016' 'ServerSolution' 'Windows Server 2016 Essentials' 'JCKRF-N37P4-C2D82-9YXRT-4M63B' K 'SrvSAC' 'ServerStandardACor' 'Windows Server SAC (1809-20H2) Standard' 'N2KJX-J94YW-TQVFB-DG9YT-724CC' K 'SrvSAC' 'ServerDatacenterACor' 'Windows Server SAC (1809-20H2) Datacenter' '6NMRW-2C8FM-D24W7-TQWMY-CWH2D' K 'SrvSAC1803' 'ServerStandardACor' 'Windows Server 1803 Standard' 'PTXN8-JFHJM-4WC78-MPCBR-9W4KR' K 'SrvSAC1803' 'ServerDatacenterACor' 'Windows Server 1803 Datacenter' '2HXDN-KRXHB-GPYC7-YCKFJ-7FVDG' K 'SrvSAC1709' 'ServerStandardACor' 'Windows Server 1709 Standard' 'DPCNP-XQFKJ-BJF7R-FRC8D-GF6G4' K 'SrvSAC1709' 'ServerDatacenterACor' 'Windows Server 1709 Datacenter' '6Y6KB-N82V8-D8CQV-23MJW-BWTG6' K 'Srv2012R2' 'ServerStandard' 'Windows Server 2012 R2 Standard' 'D2N9P-3P6X9-2R39C-7RTCD-MDVJX' K 'Srv2012R2' 'ServerDatacenter' 'Windows Server 2012 R2 Datacenter' 'W3GGN-FT8W3-Y4M27-J84CP-Q3VJ9' K 'Srv2012R2' 'ServerSolution' 'Windows Server 2012 R2 Essentials' 'KNC87-3J2TX-XB4WP-VCPJV-M4FWM' K 'Srv2012' 'ServerStandard' 'Windows Server 2012 Standard' 'XC9B7-NBPP2-83J2H-RHMBY-92BT4' K 'Srv2012' 'ServerDatacenter' 'Windows Server 2012 Datacenter' '48HP8-DN98B-MYWDG-T2DCC-8W83P' K 'Srv2012' 'ServerSolution' 'Windows Server 2012 Essentials' 'HTDQM-NBMMG-KGYDT-2DTKT-J2MPV' K 'Srv2008R2' 'ServerWeb' 'Windows Server 2008 R2 Web' '6TPJF-RBVHG-WBW2R-86QPH-6RTM4' K 'Srv2008R2' 'ServerHPC' 'Windows Server 2008 R2 HPC' 'TT8MH-CG224-D3D7Q-498W2-9QCTX' K 'Srv2008R2' 'ServerStandard' 'Windows Server 2008 R2 Standard' 'YC6KT-GKW9T-YTKYR-T4X34-R7VHC' K 'Srv2008R2' 'ServerEnterprise' 'Windows Server 2008 R2 Enterprise' '489J6-VHDMP-X63PK-3K798-CPX3Y' K 'Srv2008R2' 'ServerDatacenter' 'Windows Server 2008 R2 Datacenter' '74YFP-3QFB3-KQT8W-PMXWJ-7M648' ) function Get-WinInfo { $os = Get-CimInstance Win32_OperatingSystem $cv = Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' $b = [int]$os.BuildNumber $ed = [string]$cv.EditionID $srv = ($os.ProductType -ne 1) if ($srv) { $fam = switch ($b) { 26100 { 'Srv2025' } 20348 { 'Srv2022' } 17763 { if ($ed -match 'ACor$') { 'SrvSAC' } else { 'Srv2019' } } 14393 { 'Srv2016' } 9600 { 'Srv2012R2' } 9200 { 'Srv2012' } 7601 { 'Srv2008R2' } 17134 { 'SrvSAC1803' } 16299 { 'SrvSAC1709' } { $_ -in 18362, 18363, 19041, 19042 } { 'SrvSAC' } default { $null } } } else { if ($b -eq 7601) { $fam = 'Win7' } elseif ($b -eq 9200) { $fam = 'Win8' } elseif ($b -eq 9600) { $fam = 'Win81' } elseif ($b -lt 10240) { $fam = $null } elseif ($ed -in 'EnterpriseS', 'EnterpriseSN') { $fam = if ($b -ge 17763) { 'LTSC' } elseif ($b -eq 14393) { 'LTSB2016' } else { 'LTSB2015' } } elseif ($ed -eq 'IoTEnterpriseS') { $fam = 'LTSC' } else { $fam = 'W10' } } [pscustomobject]@{ Caption = $os.Caption.Trim(); Build = $b; Ed = $ed; Fam = $fam; Server = $srv } } # Редакции, на которые Windows реально может перейти (locale-независимо) function Get-TargetEditions { try { @(Get-WindowsEdition -Online -Target -ErrorAction Stop | ForEach-Object { $_.Edition }) } catch { @() } } function Show-WinResult { $l = Get-CimInstance SoftwareLicensingProduct -ErrorAction SilentlyContinue ` -Filter "ApplicationId='55c92734-d682-4d71-983e-d6ec3f16059f' AND PartialProductKey IS NOT NULL" | Select-Object -First 1 if (-not $l) { W "[!] Лицензия Windows не найдена" Red; return } W " Продукт: $($l.Name)" Gray W " Канал: $($l.Description)" Gray if ($l.LicenseStatus -eq 1) { W "[OK] Windows активирована" Green } else { W "[!] Windows НЕ активирована (LicenseStatus=$($l.LicenseStatus)). Код ошибки смотри в выводе slmgr выше" Red } } function Invoke-WinConvert($e) { W "[*] Смена редакции на $($e.Ed) через DISM (нужна перезагрузка)..." Cyan $dargs = @('/Online', "/Set-Edition:$($e.Ed)", "/ProductKey:$($e.Key)", '/AcceptEula', '/NoRestart') & dism.exe @dargs | Out-Host if ($LASTEXITCODE -in 0, 3010) { Send-Log "windows-convert:$($e.Ed)" W "[i] Редакция сменена. Перезагрузи ПК и запусти скрипт ещё раз: Windows, активация." Yellow if ($Interactive -and (Read-Host "Перезагрузить сейчас? (y/N)") -match '^[yYдД]') { Restart-Computer -Force } } else { W "[!] DISM завершился с кодом $LASTEXITCODE, смена редакции не удалась. Подробности: C:\Windows\Logs\DISM\dism.log" Red } } function Invoke-WinActivation($e) { $i = Get-WinInfo if (-not (Test-Kms)) { W "[!] Порт $KmsPort на ${KmsHost} не отвечает, всё равно пробую" Yellow } # Другая редакция -> DISM /Set-Edition (slmgr /ipk сам редакцию не меняет) if ($e.Ed -and $e.Ed -ne $i.Ed) { if ((Get-TargetEditions) -contains $e.Ed) { Invoke-WinConvert $e; return } W "[i] Windows не предлагает переход $($i.Ed) -> $($e.Ed), пробую поставить ключ напрямую..." Yellow } $s = "$env:SystemRoot\System32\slmgr.vbs" W "[*] Ключ: $($e.Name)" Cyan; Run $s @('/ipk', $e.Key) if ($KmsHost) { W "[*] KMS-хост: ${KmsHost}:$KmsPort" Cyan; Run $s @('/skms', "${KmsHost}:$KmsPort") } W "[*] Активация..." Cyan; Run $s @('/ato') Show-WinResult Send-Log "windows-activate:$($e.Name)" } function Invoke-WinAuto { $i = Get-WinInfo W "[i] $($i.Caption) | build $($i.Build) | EditionID=$($i.Ed) | семейство=$($i.Fam)" Yellow $e = $WinKeys | Where-Object { $_.Fam -eq $i.Fam -and $_.Ed -eq $i.Ed } | Select-Object -First 1 if (-not $e) { if ($i.Ed -match '^Core') { W "[!] Windows Home: GVLK для неё не существует. Пункт 3 попробует перевести её в Pro" Red } else { W "[!] Для EditionID=$($i.Ed), семейство '$($i.Fam)' нет ключа в таблице. Используй пункт 3" Red } return } Invoke-WinActivation $e } function Select-Windows { $i = Get-WinInfo $t = Get-TargetEditions $c = @($WinKeys | Where-Object { $_.Fam -eq $i.Fam -and ($_.Ed -eq $i.Ed -or $t -contains $_.Ed) }) if ($c.Count -eq 0) { W "[!] Для этой системы (EditionID=$($i.Ed), семейство '$($i.Fam)') нет доступных редакций для перехода" Red if ($t.Count -gt 0) { W " Windows предлагает: $($t -join ', ')" DarkGray } return } Write-Host ""; W "Доступные редакции (текущая: $($i.Ed)):" Yellow for ($n = 0; $n -lt $c.Count; $n++) { $mark = if ($c[$n].Ed -eq $i.Ed) { ' (текущая)' } else { '' } W (" [{0}] {1}{2}" -f ($n + 1), $c[$n].Name, $mark) } W " [0] Назад" DarkGray $x = Read-Host "Выбор" if ($x -match '^\d+$' -and [int]$x -ge 1 -and [int]$x -le $c.Count) { return $c[[int]$x - 1] } } # ===================================================================== # КАТАЛОГ OFFICE (GVLK) # Prod: ProPlus / Standard / ProjectPro / ProjectStd / VisioPro / VisioStd # ===================================================================== $OfficeList = @( @{ Name="Office 2024 Professional Plus"; Year="2024"; Prod="ProPlus"; Key="XJ2XN-FW8RK-P4HMP-DKDBV-GCVGB" } @{ Name="Office 2024 Standard"; Year="2024"; Prod="Standard"; Key="V28N4-JG22K-W66P8-VTMGK-H6HGR" } @{ Name="Project 2024 Professional"; Year="2024"; Prod="ProjectPro"; Key="FQQ23-N4YCY-73HQ3-FM9WC-76HF4" } @{ Name="Project 2024 Standard"; Year="2024"; Prod="ProjectStd"; Key="PD3TT-NTHQQ-VC7CY-MFXK3-G87F8" } @{ Name="Visio 2024 Professional"; Year="2024"; Prod="VisioPro"; Key="B7TN8-FJ8V3-7QYCP-HQPMV-YY89G" } @{ Name="Visio 2024 Standard"; Year="2024"; Prod="VisioStd"; Key="JMMVY-XFNQC-KK4HK-9H7R3-WQQTV" } @{ Name="Office 2021 Professional Plus"; Year="2021"; Prod="ProPlus"; Key="FXYTK-NJJ8C-GB6DW-3DYQT-6F7TH" } @{ Name="Office 2021 Standard"; Year="2021"; Prod="Standard"; Key="KDX7X-BNVR8-TXXGX-4Q7Y8-78VT3" } @{ Name="Project 2021 Professional"; Year="2021"; Prod="ProjectPro"; Key="FTNWT-C6WBT-8HMGF-K9PRX-QV9H8" } @{ Name="Project 2021 Standard"; Year="2021"; Prod="ProjectStd"; Key="J2JDC-NJCYY-9RGQ4-YXWMH-T3D4T" } @{ Name="Visio 2021 Professional"; Year="2021"; Prod="VisioPro"; Key="KNH8D-FGHT4-T8RK3-CTDYJ-K2HT4" } @{ Name="Visio 2021 Standard"; Year="2021"; Prod="VisioStd"; Key="MJVNY-BYWPY-CWV6J-2RKRT-4M8QG" } @{ Name="Office 2019 Professional Plus"; Year="2019"; Prod="ProPlus"; Key="NMMKJ-6RK4F-KMJVX-8D9MJ-6MWKP" } @{ Name="Office 2019 Standard"; Year="2019"; Prod="Standard"; Key="6NWWJ-YQWMR-QKGCB-6TMB3-9D9HK" } @{ Name="Project 2019 Professional"; Year="2019"; Prod="ProjectPro"; Key="B4NPR-3FKK7-T2MBV-FRQ4W-PKD2B" } @{ Name="Project 2019 Standard"; Year="2019"; Prod="ProjectStd"; Key="C4F7P-NCP8C-6CQPT-MQHV9-JXD2M" } @{ Name="Visio 2019 Professional"; Year="2019"; Prod="VisioPro"; Key="9BGNQ-K37YR-RQHF2-38RQ3-7VCBB" } @{ Name="Visio 2019 Standard"; Year="2019"; Prod="VisioStd"; Key="7TQNQ-K3YQQ-3PFH7-CCPPM-X4VQ2" } @{ Name="Office 2016 Professional Plus"; Year="2016"; Prod="ProPlus"; Key="XQNVK-8JYDB-WJ9W3-YJ8YR-WFG99" } @{ Name="Office 2016 Standard"; Year="2016"; Prod="Standard"; Key="JNRGM-WHDWX-FJJG3-K47QV-DRTFM" } @{ Name="Project 2016 Professional"; Year="2016"; Prod="ProjectPro"; Key="YG9NW-3K39V-2T3HJ-93F3Q-G83KT" } @{ Name="Project 2016 Standard"; Year="2016"; Prod="ProjectStd"; Key="GNFHQ-F6YQM-KQDGJ-327XX-KQBVC" } @{ Name="Visio 2016 Professional"; Year="2016"; Prod="VisioPro"; Key="PD3PC-RHNGV-FXJ29-8JK7D-RJRJK" } @{ Name="Visio 2016 Standard"; Year="2016"; Prod="VisioStd"; Key="7WHWN-4T7MP-G96JF-G33KR-W8GF4" } @{ Name="Office 2013 Professional Plus"; Year="2013"; Prod="ProPlus"; Key="YC7DK-G2NP3-2QQC3-J6H88-GVGXT" } @{ Name="Office 2013 Standard"; Year="2013"; Prod="Standard"; Key="KBKQT-2NMXY-JJWGP-M62JB-92CD4" } @{ Name="Project 2013 Professional"; Year="2013"; Prod="ProjectPro"; Key="FN8TT-7WMH6-2D4X9-M337T-2342K" } @{ Name="Project 2013 Standard"; Year="2013"; Prod="ProjectStd"; Key="6NTH3-CW976-3G3Y2-JK3TX-8QHTT" } @{ Name="Visio 2013 Professional"; Year="2013"; Prod="VisioPro"; Key="C2FG9-N6J68-H8BTJ-BW3QX-RM3B3" } @{ Name="Visio 2013 Standard"; Year="2013"; Prod="VisioStd"; Key="J484Y-4NKBF-W2HMG-DBMJC-PGWR7" } @{ Name="Office 2010 Professional Plus"; Year="2010"; Prod="ProPlus"; Key="VYBBJ-TRJPB-QFQRF-QFT4D-H3GVB" } @{ Name="Office 2010 Standard"; Year="2010"; Prod="Standard"; Key="V7QKV-4XVVR-XYV4D-F7DFM-8R6BM" } @{ Name="Project 2010 Professional"; Year="2010"; Prod="ProjectPro"; Key="YGX6F-PGV49-PGW3J-9BTGG-VHKC6" } @{ Name="Visio 2010 Premium"; Year="2010"; Prod="VisioPro"; Key="D9DWC-HPYVV-JGF4P-BTWQB-WX8BJ" } ) # Год продукта -> номер папки OfficeNN function Get-OfficeVer($year) { switch ($year) { '2010' {'14'} '2013' {'15'} default {'16'} } } # Найти все установленные ospp.vbs (по одному на версию 14/15/16) function Get-OsppList { $roots = @($env:ProgramFiles, ${env:ProgramFiles(x86)}) | Where-Object { $_ } | Select-Object -Unique $found = @{} foreach ($r in $roots) { $cands = @( @{ V='16'; P="$r\Microsoft Office\root\Office16" }, @{ V='16'; P="$r\Microsoft Office\Office16" }, @{ V='15'; P="$r\Microsoft Office 15\root\Office15" }, @{ V='15'; P="$r\Microsoft Office\Office15" }, @{ V='14'; P="$r\Microsoft Office\Office14" } ) foreach ($c in $cands) { $f = Join-Path $c.P 'ospp.vbs' if ((Test-Path $f) -and -not $found.ContainsKey($c.V)) { $found[$c.V] = $f } } } foreach ($k in ($found.Keys | Sort-Object -Descending)) { [pscustomobject]@{ Ver = $k; Path = $found[$k] } } } # ProductReleaseIds из реестра Click-to-Run function Get-InstalledOfficeIds { $paths = @('HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration', 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Office\ClickToRun\Configuration') foreach ($p in $paths) { $v = (Get-ItemProperty $p -ErrorAction SilentlyContinue).ProductReleaseIds if ($v) { return ($v -split ',' | ForEach-Object { $_.Trim() } | Where-Object { $_ }) } } } # ProductReleaseId (например ProPlus2021Volume) -> запись каталога function Resolve-OfficeEntry($id) { $n = $id -replace 'Volume$', '' if ($n -match '^(ProPlus|Standard|ProjectPro|ProjectStd|VisioPro|VisioStd)(\d{4})?$') { $prod = $Matches[1] $year = if ($Matches[2]) { $Matches[2] } else { '2016' } return $OfficeList | Where-Object { $_.Year -eq $year -and $_.Prod -eq $prod } | Select-Object -First 1 } } function Set-OfficeKms($ospp) { if ($KmsHost) { RunQ $ospp @("/sethst:$KmsHost") RunQ $ospp @("/setprt:$KmsPort") } } # Автоматическая активация всего установленного function Invoke-OfficeAuto { $list = @(Get-OsppList) if ($list.Count -eq 0) { W "[!] Office не найден (ospp.vbs отсутствует)" Red; return } if (-not (Test-Kms)) { W "[!] Порт $KmsPort на ${KmsHost} не отвечает, всё равно пробую" Yellow } W "[i] Найдены версии Office: $(($list | ForEach-Object { 'Office' + $_.Ver }) -join ', ')" Yellow # 1) Click-to-Run: ставим GVLK по ProductReleaseId $ids = @(Get-InstalledOfficeIds) foreach ($id in $ids) { if ($id -match 'Retail|O365|M365|Subscription') { W "[!] ${id}: розничная/подписочная версия, KMS не подходит. Нужна установка из VL-канала" Yellow continue } $e = Resolve-OfficeEntry $id if (-not $e) { W "[i] ${id}: нет в таблице, оставляю встроенный ключ" DarkGray; continue } $o = $list | Where-Object { $_.Ver -eq (Get-OfficeVer $e.Year) } | Select-Object -First 1 if (-not $o) { $o = $list | Select-Object -First 1 } W "[*] $id -> GVLK ($($e.Name))" Cyan RunQ $o.Path @("/inpkey:$($e.Key)") } if ($ids.Count -eq 0) { W "[i] Click-to-Run не обнаружен (MSI-установка), GVLK уже встроен в VL-образ" DarkGray } # 2) Хост + активация для каждой найденной версии foreach ($o in $list) { W "`n=== Office $($o.Ver) ===" Green Set-OfficeKms $o.Path W "[*] Активация..." Cyan Run $o.Path @('/act') W "Итог:" Yellow & cscript.exe //nologo $o.Path /dstatus | Select-String 'LICENSE NAME|LICENSE STATUS|ERROR CODE|ERROR DESCRIPTION' | ForEach-Object { $_.Line } | Out-Host } Send-Log "office-auto" } # Ручной выбор продукта function Invoke-OfficeManual($entry) { $list = @(Get-OsppList) if ($list.Count -eq 0) { W "[!] Office не найден (ospp.vbs отсутствует)" Red; return } if (-not (Test-Kms)) { W "[!] Порт $KmsPort на ${KmsHost} не отвечает, всё равно пробую" Yellow } $o = $list | Where-Object { $_.Ver -eq (Get-OfficeVer $entry.Year) } | Select-Object -First 1 if (-not $o) { W "[!] Для $($entry.Name) не найден ospp.vbs нужной версии (Office$(Get-OfficeVer $entry.Year))" Red; return } W "[*] Ставлю ключ: $($entry.Name)" Cyan; Run $o.Path @("/inpkey:$($entry.Key)") Set-OfficeKms $o.Path W "[*] Активация..." Cyan; Run $o.Path @('/act') Send-Log "office-manual:$($entry.Name)" } function Show-OfficeStatus { $list = @(Get-OsppList) if ($list.Count -eq 0) { W "[!] Office не найден" Red; return } foreach ($o in $list) { W "`n=== Office $($o.Ver) ===" Green; Run $o.Path @('/dstatus') } } # ---------- Выбор из списка ---------- function Select-Office { Write-Host ""; W "Продукт Office:" Yellow for ($i = 0; $i -lt $OfficeList.Count; $i++) { W (" [{0,2}] {1}" -f ($i + 1), $OfficeList[$i].Name) } W " [ 0] Назад" DarkGray $n = Read-Host "Выбор" if ($n -match '^\d+$' -and [int]$n -ge 1 -and [int]$n -le $OfficeList.Count) { return $OfficeList[[int]$n - 1] } } # ===================================================================== # ЗАПУСК # ===================================================================== if (-not (Test-Admin)) { W "Запусти PowerShell от имени администратора" Red; return } $Interactive = -not ($Auto -or $WindowsOnly -or $OfficeOnly) if (-not $Interactive) { if ($Auto -or $WindowsOnly) { Invoke-WinAuto } if ($Auto -or $OfficeOnly) { Invoke-OfficeAuto } return } while ($true) { Clear-Host W "==========================================" Green W " KMS Activation Menu " Green W "==========================================" Green $srv = if ($KmsHost) { "${KmsHost}:$KmsPort" } else { "автопоиск (DNS SRV)" } $wi = Get-WinInfo W " Сервер: $srv" DarkGray W " Система: $($wi.Caption) [$($wi.Ed)]" DarkGray Write-Host "" W " [1] Всё сразу: Windows + Office (авто)" W " [2] Windows: активировать текущую редакцию" W " [3] Windows: сменить редакцию и активировать" W " [4] Office: активировать всё установленное" W " [5] Office: выбрать продукт вручную" W " [6] Статус Windows" W " [7] Статус Office" W " [0] Выход" Write-Host "" switch (Read-Host "Выбор") { '1' { Invoke-WinAuto; Invoke-OfficeAuto; Pause2 } '2' { Invoke-WinAuto; Pause2 } '3' { $e = Select-Windows; if ($e) { Invoke-WinActivation $e; Pause2 } } '4' { Invoke-OfficeAuto; Pause2 } '5' { $e = Select-Office; if ($e) { Invoke-OfficeManual $e; Pause2 } } '6' { Run "$env:SystemRoot\System32\slmgr.vbs" @('/dli'); Show-WinResult; Pause2 } '7' { Show-OfficeStatus; Pause2 } '0' { return } }