Загрузка данных
#Requires -RunAsAdministrator
<#
.SYNOPSIS
Installs a programming toolset for ALL users (machine scope) via winget.
.DESCRIPTION
Core : Git, VS Code, Node.js (LTS), Python
Extras : PowerShell 7, Windows Terminal, GitHub CLI, 7-Zip, Notepad++ (skip with -Core)
Also : system-wide Git defaults, Windows long paths, PowerShell script policy
(so npm/yarn .ps1 shims work in the VS Code terminal), corepack (pnpm/yarn) if present.
.EXAMPLE
.\install-dev-tools.ps1 -DryRun # only print the winget commands
.\install-dev-tools.ps1 # install everything
.\install-dev-tools.ps1 -Core # only Git, VS Code, Node.js, Python
Run in Windows PowerShell as Administrator:
powershell -ExecutionPolicy Bypass -File .\install-dev-tools.ps1
#>
[CmdletBinding()]
param(
[switch]$Core,
[switch]$DryRun,
# set to $false to leave the PowerShell script policy untouched
[bool]$AllowLocalScripts = $true
)
$ErrorActionPreference = 'Continue'
# ---------------- editable lists ----------------
$PythonId = 'Python.Python.3.13'
$CorePackages = @(
@{ Name = 'Git'; Id = 'Git.Git' },
@{ Name = 'VS Code'; Id = 'Microsoft.VisualStudioCode' },
@{ Name = 'Node.js LTS'; Id = 'OpenJS.NodeJS.LTS' },
@{ Name = 'Python'; Id = $PythonId;
# all users + PATH + py launcher
Override = '/quiet InstallAllUsers=1 PrependPath=1 Include_launcher=1 Include_test=0' }
)
$ExtraPackages = @(
@{ Name = 'PowerShell 7'; Id = 'Microsoft.PowerShell' },
@{ Name = 'Windows Terminal'; Id = 'Microsoft.WindowsTerminal' },
@{ Name = 'GitHub CLI'; Id = 'GitHub.cli' },
@{ Name = '7-Zip'; Id = '7zip.7zip' },
@{ Name = 'Notepad++'; Id = 'Notepad++.Notepad++' }
# @{ Name = 'Postman'; Id = 'Postman.Postman' }
)
# ---------------- helpers ----------------
function Step-Header { param([string]$Text) Write-Host "`n== $Text ==" -ForegroundColor Cyan }
function Invoke-WingetInstall {
param($Pkg, [bool]$UseScope = $true)
$wargs = @('install', '--id', $Pkg.Id, '--exact', '--source', 'winget', '--silent',
'--accept-package-agreements', '--accept-source-agreements', '--disable-interactivity')
if ($UseScope) { $wargs += @('--scope', 'machine') }
if ($Pkg.Override) { $wargs += @('--override', $Pkg.Override) }
if ($DryRun) { Write-Host "[dry-run] winget $($wargs -join ' ')" -ForegroundColor Yellow; return 0 }
& winget @wargs | Out-Host
return $LASTEXITCODE
}
function Install-Pkg {
param($Pkg)
Write-Host "`n-> $($Pkg.Name) ($($Pkg.Id))" -ForegroundColor White
$code = Invoke-WingetInstall -Pkg $Pkg -UseScope $true
if ($code -ne 0 -and $code -ne -1978335189 -and $code -ne -1978335135) {
Write-Warning "$($Pkg.Name): exit code $code with --scope machine, retrying without scope"
$code = Invoke-WingetInstall -Pkg $Pkg -UseScope $false
}
# 0 = ok, -1978335189 = no newer version, -1978335135 = already installed
if ($code -eq 0 -or $code -eq -1978335189 -or $code -eq -1978335135) {
$script:Ok += $Pkg.Name
}
else {
Write-Warning "$($Pkg.Name): FAILED (exit code $code)"
$script:Failed += $Pkg.Name
}
}
$script:Ok = @()
$script:Failed = @()
# ---------------- main ----------------
if (-not (Get-Command winget -ErrorAction SilentlyContinue)) {
Write-Error "winget not found. Update 'App Installer' from Microsoft Store (or install it from github.com/microsoft/winget-cli), then rerun."
exit 1
}
if ($DryRun) { Write-Host 'DRY RUN: nothing will be installed.' -ForegroundColor Yellow }
Step-Header 'Updating winget sources'
if (-not $DryRun) { & winget source update --name winget | Out-Null }
Step-Header 'Installing packages'
$list = $CorePackages
if (-not $Core) { $list = $CorePackages + $ExtraPackages }
foreach ($p in $list) { Install-Pkg $p }
if ($DryRun) { Write-Host "`nDry run finished."; exit 0 }
# make new PATH visible in this session
$env:Path = [Environment]::GetEnvironmentVariable('Path', 'Machine') + ';' + [Environment]::GetEnvironmentVariable('Path', 'User')
Step-Header 'System settings'
if (Get-Command git -ErrorAction SilentlyContinue) {
& git config --system init.defaultBranch main
& git config --system core.longpaths true
Write-Host ' Git: system defaults set (default branch main, long paths)'
}
try {
New-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1 -PropertyType DWord -Force | Out-Null
Write-Host ' Windows long paths enabled (helps node_modules)'
}
catch { Write-Warning "Long paths: $($_.Exception.Message)" }
if ($AllowLocalScripts) {
try {
Set-ExecutionPolicy -Scope LocalMachine -ExecutionPolicy RemoteSigned -Force -ErrorAction Stop
Write-Host ' PowerShell policy RemoteSigned (npm/yarn .ps1 shims work in the terminal)'
}
catch { Write-Warning "Execution policy: $($_.Exception.Message)" }
}
if (Get-Command corepack -ErrorAction SilentlyContinue) {
& corepack enable
Write-Host ' corepack enabled (pnpm / yarn available)'
}
else {
Write-Host ' corepack not bundled with this Node version: the user can run npm i -g pnpm himself'
}
Step-Header 'Versions'
$checks = @(@('git', '--version'), @('node', '--version'), @('npm', '--version'),
@('python', '--version'), @('pip', '--version'), @('code', '--version'))
foreach ($c in $checks) {
try {
$out = & $c[0] $c[1] 2>&1 | Select-Object -First 1
Write-Host (" {0,-8} {1}" -f $c[0], $out)
}
catch { Write-Host (" {0,-8} NOT FOUND (reopen the terminal and check again)" -f $c[0]) -ForegroundColor Yellow }
}
Write-Host "`nInstalled/present: $($script:Ok -join ', ')" -ForegroundColor Green
if ($script:Failed.Count -gt 0) { Write-Host "Failed: $($script:Failed -join ', ')" -ForegroundColor Red }
Write-Host @"
Next:
- Reopen the terminal / log in as the standard user and run: git --version ; node -v ; python --version
- VS Code extensions are per user. As the standard user (one time):
code --install-extension ms-python.python
code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
- The user sets his own Git identity:
git config --global user.name "Name"
git config --global user.email "mail@example.com"
- Updates need admin: from time to time run winget upgrade --all --scope machine as admin
"@