Загрузка данных


#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
"@