公开
版本 1.0
scoop安装脚本
描述
kuma
提示词内容
<#
.SYNOPSIS
生产级 Scoop 环境一键部署脚本(支持中断恢复)
.DESCRIPTION
功能特性:
1. 自动安装 Scoop(如未安装)
2. 优先安装核心依赖(Git, 7zip, aria2)
3. 批量添加 buckets(含错误处理和重试机制)
4. 按清单安装应用(最小系统必备 + 个人使用)
5. 完整的日志记录和错误追踪
6. 支持中断后重新执行(幂等性设计)
7. 自动权限检查和环境变量刷新
8. 交互式选择是否启用 aria2c 下载加速
.PARAMETER LogPath
日志文件保存路径,默认为 $env:TEMP\scoop-init.log
.PARAMETER SkipAdminCheck
跳过管理员权限检查(不推荐)
.PARAMETER UseAria2
是否启用 aria2c 加速下载。
- 如果指定此参数,则自动启用
- 如果不指定,脚本会交互式询问用户
.EXAMPLE
.\scoop-init.ps1
# 执行时会询问是否启用 aria2c
.EXAMPLE
.\scoop-init.ps1 -UseAria2
# 直接启用 aria2c,不询问
.EXAMPLE
.\scoop-init.ps1 -UseAria2:$false
# 直接禁用 aria2c,不询问
.EXAMPLE
.\scoop-init.ps1 -LogPath "D:\logs\scoop-init.log"
.NOTES
Author: Your Name
Version: 2.1
LastModified: 2025-12-06
#>
[CmdletBinding()]
param(
[string]$LogPath = "$env:TEMP\scoop-init-$(Get-Date -Format 'yyyyMMdd-HHmmss').log",
[switch]$SkipAdminCheck,
[Parameter(Mandatory=$false)]
[bool]$UseAria2 = $null
)
# ============================================
# 全局配置
# ============================================
$ErrorActionPreference = 'Continue'
$global:FailedOperations = @()
$global:SuccessCount = 0
$global:SkipCount = 0
$global:EnableAria2 = $null # 用于存储用户选择
# ============================================
# 日志与输出函数
# ============================================
function Write-Log {
param(
[string]$Message,
[ValidateSet('INFO', 'SUCCESS', 'WARNING', 'ERROR', 'SKIP')]
[string]$Level = 'INFO'
)
$timestamp = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
$logMessage = "[$timestamp] [$Level] $Message"
# 输出到文件
Add-Content -Path $LogPath -Value $logMessage
# 输出到控制台(带颜色)
$colors = @{
'INFO' = 'Cyan'
'SUCCESS' = 'Green'
'WARNING' = 'Yellow'
'ERROR' = 'Red'
'SKIP' = 'DarkGray'
}
Write-Host $logMessage -ForegroundColor $colors[$Level]
}
function Write-SectionHeader {
param([string]$Title)
$separator = "=" * 60
Write-Log "`n$separator" -Level INFO
Write-Log " $Title" -Level INFO
Write-Log "$separator" -Level INFO
}
# ============================================
# 用户交互函数
# ============================================
function Get-UserConfirmation {
<#
.SYNOPSIS
获取用户的是/否确认
.DESCRIPTION
显示提示信息并等待用户输入 Y/N
#>
param(
[Parameter(Mandatory)]
[string]$Prompt,
[string]$DefaultChoice = 'Y'
)
$choices = if ($DefaultChoice -eq 'Y') { '[Y/n]' } else { '[y/N]' }
do {
Write-Host "`n$Prompt $choices " -ForegroundColor Yellow -NoNewline
$response = Read-Host
# 如果用户直接回车,使用默认值
if ([string]::IsNullOrWhiteSpace($response)) {
$response = $DefaultChoice
}
$response = $response.Trim().ToUpper()
if ($response -eq 'Y' -or $response -eq 'YES') {
return $true
} elseif ($response -eq 'N' -or $response -eq 'NO') {
return $false
} else {
Write-Host "无效输入,请输入 Y 或 N" -ForegroundColor Red
}
} while ($true)
}
function Request-Aria2Preference {
<#
.SYNOPSIS
询问用户是否启用 aria2c 加速
#>
Write-Host "`n" -NoNewline
Write-Host "╔════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
Write-Host "║ 是否启用 aria2c 多线程下载加速? ║" -ForegroundColor Cyan
Write-Host "╠════════════════════════════════════════════════════════════╣" -ForegroundColor Cyan
Write-Host "║ 优点: ║" -ForegroundColor Cyan
Write-Host "║ • 显著提升大文件下载速度(最多 16 线程) ║" -ForegroundColor Green
Write-Host "║ • 支持断点续传 ║" -ForegroundColor Green
Write-Host "║ • 自动重试失败的下载 ║" -ForegroundColor Green
Write-Host "║ ║" -ForegroundColor Cyan
Write-Host "║ 缺点: ║" -ForegroundColor Cyan
Write-Host "║ • 需额外安装 aria2c 工具(约 5MB) ║" -ForegroundColor Yellow
Write-Host "║ • 某些网站可能限制多线程下载 ║" -ForegroundColor Yellow
Write-Host "║ ║" -ForegroundColor Cyan
Write-Host "║ 推荐: 如果网络环境良好,建议启用以加速安装 ║" -ForegroundColor White
Write-Host "╚════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan
return Get-UserConfirmation -Prompt "是否启用 aria2c 加速?" -DefaultChoice 'Y'
}
# ============================================
# 环境检查函数
# ============================================
function Test-AdminPrivilege {
<#
.SYNOPSIS
检查当前 PowerShell 会话是否具有管理员权限
#>
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Test-PowerShellVersion {
<#
.SYNOPSIS
检查 PowerShell 版本是否满足要求(>= 5.0)
#>
$version = $PSVersionTable.PSVersion
if ($version.Major -lt 5) {
Write-Log "PowerShell 版本过低 ($version),需要 5.0 及以上版本" -Level ERROR
return $false
}
Write-Log "PowerShell 版本检查通过: $version" -Level SUCCESS
return $true
}
function Refresh-EnvironmentPath {
<#
.SYNOPSIS
刷新当前会话的 PATH 环境变量
#>
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "User") + ";" +
[System.Environment]::GetEnvironmentVariable("Path", "Machine")
Write-Log "环境变量已刷新" -Level INFO
}
# ============================================
# Scoop 安装与配置函数
# ============================================
function Install-ScoopIfNeeded {
<#
.SYNOPSIS
检查并安装 Scoop(如未安装)
#>
if (Get-Command scoop -ErrorAction SilentlyContinue) {
Write-Log "Scoop 已安装,跳过安装步骤" -Level SKIP
$global:SkipCount++
return $true
}
Write-Log "未检测到 Scoop,开始安装..." -Level INFO
try {
# 设置执行策略
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force -ErrorAction Stop
Write-Log "执行策略已设置为 RemoteSigned" -Level SUCCESS
# 使用官方安装脚本
Write-Log "正在下载并执行 Scoop 安装脚本..." -Level INFO
Invoke-RestMethod -Uri 'https://get.scoop.sh' | Invoke-Expression
# 验证安装
Refresh-EnvironmentPath
if (Get-Command scoop -ErrorAction SilentlyContinue) {
Write-Log "Scoop 安装成功" -Level SUCCESS
$global:SuccessCount++
return $true
} else {
throw "安装完成但无法找到 scoop 命令"
}
} catch {
Write-Log "Scoop 安装失败: $($_.Exception.Message)" -Level ERROR
$global:FailedOperations += "安装 Scoop"
return $false
}
}
function Install-CoreDependencies {
<#
.SYNOPSIS
安装核心依赖工具(Git, 7zip, 可选的 aria2)
#>
param(
[Parameter(Mandatory)]
[bool]$InstallAria2
)
# 基础依赖(必装)
$coreDeps = @('git', '7zip')
# 根据用户选择决定是否安装 aria2
if ($InstallAria2) {
$coreDeps += 'aria2'
Write-Log "用户已选择启用 aria2c 加速" -Level INFO
} else {
Write-Log "用户已选择不使用 aria2c 加速" -Level INFO
}
foreach ($dep in $coreDeps) {
try {
# 检查是否已安装
$installed = scoop list | Select-String "^\s*$dep\s" -ErrorAction SilentlyContinue
if ($installed) {
Write-Log "$dep 已安装,跳过" -Level SKIP
$global:SkipCount++
continue
}
Write-Log "正在安装 $dep ..." -Level INFO
scoop install $dep 2>&1 | Out-Null
# 验证安装
$verified = scoop list | Select-String "^\s*$dep\s"
if ($verified) {
Write-Log "$dep 安装成功" -Level SUCCESS
$global:SuccessCount++
} else {
throw "安装后验证失败"
}
} catch {
Write-Log "$dep 安装失败: $($_.Exception.Message)" -Level ERROR
$global:FailedOperations += "安装 $dep"
}
}
# Git 安装后刷新环境变量
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
Refresh-EnvironmentPath
}
# 配置 aria2(如果用户选择启用且安装成功)
if ($InstallAria2) {
try {
# 检查 aria2 是否安装成功
$aria2Installed = scoop list | Select-String "^\s*aria2\s"
if ($aria2Installed) {
scoop config aria2-enabled true 2>&1 | Out-Null
scoop config aria2-warning-enabled false 2>&1 | Out-Null
scoop config aria2-max-connection-per-server 16 2>&1 | Out-Null
scoop config aria2-split 16 2>&1 | Out-Null
scoop config aria2-min-split-size '1M' 2>&1 | Out-Null
Write-Log "aria2c 下载加速已启用(16 线程)" -Level SUCCESS
} else {
Write-Log "aria2 未安装成功,跳过配置" -Level WARNING
}
} catch {
Write-Log "aria2 配置失败(不影响主流程): $($_.Exception.Message)" -Level WARNING
}
} else {
# 确保 aria2 被禁用
try {
scoop config aria2-enabled false 2>&1 | Out-Null
Write-Log "aria2c 已禁用,使用默认下载方式" -Level INFO
} catch {
# 忽略配置失败(可能 Scoop 是首次安装,配置文件不存在)
}
}
}
# ============================================
# Bucket 管理函数
# ============================================
function Add-ScoopBucketSafe {
<#
.SYNOPSIS
安全地添加 Scoop bucket(含重试机制)
#>
param(
[Parameter(Mandatory)]
[string]$Name,
[Parameter(Mandatory)]
[string]$Url,
[int]$MaxRetries = 2
)
try {
# 检查是否已存在
$exists = scoop bucket list 2>&1 | Select-String "^\s*$Name\s" -ErrorAction SilentlyContinue
if ($exists) {
Write-Log "Bucket '$Name' 已存在,跳过" -Level SKIP
$global:SkipCount++
return $true
}
# 尝试添加(含重试)
for ($i = 1; $i -le $MaxRetries; $i++) {
try {
Write-Log "正在添加 Bucket '$Name' (尝试 $i/$MaxRetries)..." -Level INFO
scoop bucket add $Name $Url 2>&1 | Out-Null
# 验证添加是否成功
$verified = scoop bucket list 2>&1 | Select-String "^\s*$Name\s"
if ($verified) {
Write-Log "Bucket '$Name' 添加成功" -Level SUCCESS
$global:SuccessCount++
return $true
}
} catch {
if ($i -eq $MaxRetries) {
throw
}
Write-Log "添加失败,2 秒后重试..." -Level WARNING
Start-Sleep -Seconds 2
}
}
throw "达到最大重试次数"
} catch {
Write-Log "Bucket '$Name' 添加失败: $($_.Exception.Message)" -Level ERROR
$global:FailedOperations += "添加 Bucket: $Name"
return $false
}
}
# ============================================
# 应用安装函数
# ============================================
function Install-ScoopAppSafe {
<#
.SYNOPSIS
安全地安装 Scoop 应用(含错误处理)
#>
param(
[Parameter(Mandatory)]
[string]$Name,
[Parameter(Mandatory)]
[string]$Bucket
)
$fullName = "$Bucket/$Name"
try {
# 检查是否已安装
$installed = scoop list 2>&1 | Select-String "^\s*$Name\s" -ErrorAction SilentlyContinue
if ($installed) {
Write-Log "$fullName 已安装,跳过" -Level SKIP
$global:SkipCount++
return $true
}
Write-Log "正在安装 $fullName ..." -Level INFO
# 捕获安装输出
$output = scoop install $fullName 2>&1
# 检查是否包含警告信息(某些应用可能需要额外配置)
if ($output -match "WARN") {
Write-Log "安装完成但有警告: $($output -join ' ')" -Level WARNING
}
# 验证安装
$verified = scoop list 2>&1 | Select-String "^\s*$Name\s"
if ($verified) {
Write-Log "$fullName 安装成功" -Level SUCCESS
$global:SuccessCount++
return $true
} else {
throw "安装后验证失败"
}
} catch {
Write-Log "$fullName 安装失败: $($_.Exception.Message)" -Level ERROR
$global:FailedOperations += "安装应用: $fullName"
return $false
}
}
# ============================================
# 主流程
# ============================================
function Main {
$startTime = Get-Date
Write-Log "========================================" -Level INFO
Write-Log " Scoop 环境初始化脚本 v2.1" -Level INFO
Write-Log " 日志文件: $LogPath" -Level INFO
Write-Log "========================================" -Level INFO
# 0. 确定 aria2 使用偏好
Write-SectionHeader "步骤 0: 配置下载加速"
if ($PSBoundParameters.ContainsKey('UseAria2')) {
# 用户通过命令行参数明确指定了
$global:EnableAria2 = $UseAria2
if ($UseAria2) {
Write-Log "通过参数指定:启用 aria2c 加速" -Level INFO
} else {
Write-Log "通过参数指定:禁用 aria2c 加速" -Level INFO
}
} else {
# 交互式询问用户
$global:EnableAria2 = Request-Aria2Preference
Write-Log "用户选择:$(if ($global:EnableAria2) { '启用' } else { '禁用' }) aria2c 加速" -Level INFO
}
# 1. 环境检查
Write-SectionHeader "步骤 1: 环境检查"
if (-not (Test-PowerShellVersion)) {
Write-Log "环境检查失败,脚本终止" -Level ERROR
return
}
if (-not $SkipAdminCheck) {
if (Test-AdminPrivilege) {
Write-Log "检测到管理员权限,某些应用可能需要此权限" -Level SUCCESS
} else {
Write-Log "当前未以管理员身份运行,部分应用安装可能需要提升权限" -Level WARNING
}
}
# 2. 安装 Scoop
Write-SectionHeader "步骤 2: 安装 Scoop"
if (-not (Install-ScoopIfNeeded)) {
Write-Log "Scoop 安装失败,无法继续" -Level ERROR
return
}
# 3. 安装核心依赖
Write-SectionHeader "步骤 3: 安装核心依赖工具"
Install-CoreDependencies -InstallAria2 $global:EnableAria2
# 验证 Git 是否可用
if (-not (Get-Command git -ErrorAction SilentlyContinue)) {
Write-Log "Git 未正确安装,无法添加 buckets" -Level ERROR
Write-Log "请手动运行 'scoop install git' 后重新执行本脚本" -Level ERROR
return
}
# 4. 添加 Buckets
Write-SectionHeader "步骤 4: 添加 Buckets"
$buckets = @(
@{ Name = 'main'; Url = 'https://github.com/ScoopInstaller/Main.git' }
@{ Name = 'extras'; Url = 'https://github.com/ScoopInstaller/Extras' }
@{ Name = 'versions'; Url = 'https://github.com/ScoopInstaller/Versions' }
@{ Name = 'apps'; Url = 'https://github.com/kkzzhizhou/scoop-apps' }
@{ Name = 'atm'; Url = 'https://github.com/zhaochengcube/scoop-atm' }
@{ Name = 'extras-cn'; Url = 'https://github.com/Scoopforge/Extras-CN' }
@{ Name = 'lemon'; Url = 'https://github.com/hoilc/scoop-lemon' }
@{ Name = 'MorFans-apt'; Url = 'https://github.com/Paxxs/Cluttered-bucket.git' }
)
foreach ($bucket in $buckets) {
Add-ScoopBucketSafe -Name $bucket.Name -Url $bucket.Url
}
# 5. 安装应用
Write-SectionHeader "步骤 5: 安装应用清单"
# 最小系统必备
$coreApps = @(
@{ Name = '7zip'; Bucket = 'main' }
@{ Name = 'aria2'; Bucket = 'main' }
@{ Name = 'oh-my-posh'; Bucket = 'main' }
@{ Name = 'ddu'; Bucket = 'extras' }
@{ Name = 'potplayer'; Bucket = 'extras' }
@{ Name = 'office-tool-plus'; Bucket = 'extras' }
@{ Name = 'libreoffice'; Bucket = 'extras' }
@{ Name = 'googlechrome'; Bucket = 'extras' }
@{ Name = 'spacesniffer'; Bucket = 'extras' }
@{ Name = 'ezunlock'; Bucket = 'extras' }
@{ Name = 'autoruns'; Bucket = 'apps' }
@{ Name = 'sparkle'; Bucket = 'lemon' }
@{ Name = 'notepadplusplus'; Bucket = 'extras' }
@{ Name = 'wechat'; Bucket = 'extras' }
@{ Name = 'qq'; Bucket = 'extras' }
@{ Name = 'baidu-net-disk'; Bucket = 'apps' }
@{ Name = 'defender-control'; Bucket = 'apps' }
@{ Name = 'defender-remover'; Bucket = 'apps' }
@{ Name = 'listary'; Bucket = 'extras' }
@{ Name = 'hibit-uninstaller'; Bucket = 'extras' }
@{ Name = 'snipaste'; Bucket = 'extras' }
@{ Name = 'idm'; Bucket = 'apps' }
@{ Name = 'pot'; Bucket = 'lemon' }
@{ Name = 'everything'; Bucket = 'extras' }
@{ Name = 'dismplusplus'; Bucket = 'extras' }
@{ Name = 'localsend'; Bucket = 'extras' }
@{ Name = 'JetBrainsMono-NF-Mono'; Bucket = 'apps' }
@{ Name = 'nilesoft-shell'; Bucket = 'extras' }
@{ Name = 'diskgenius'; Bucket = 'extras' }
@{ Name = 'pwsh'; Bucket = 'main' }
)
# 个人使用清单
$personalApps = @(
@{ Name = 'battlenet'; Bucket = 'apps' }
@{ Name = 'steam'; Bucket = 'versions'}
@{ Name = 'bilibili'; Bucket = 'apps' }
@{ Name = 'docker-desktop'; Bucket = 'apps' }
@{ Name = 'vmware'; Bucket = 'apps' }
@{ Name = 'jetbrains-toolbox'; Bucket = 'apps' }
@{ Name = 'LXGWWenKaiScreenR'; Bucket = 'apps' }
@{ Name = 'obsidian'; Bucket = 'extras' }
@{ Name = 'vscode'; Bucket = 'extras' }
@{ Name = 'finalshell'; Bucket = 'apps' }
@{ Name = 'apifox'; Bucket = 'extras' }
@{ Name = 'wireshark'; Bucket = 'extras' }
@{ Name = 'telegram'; Bucket = 'apps' }
@{ Name = 'cherry-studio'; Bucket = 'extras' }
@{ Name = 'ollama'; Bucket = 'main' }
@{ Name = 'mqttx'; Bucket = 'extras' }
@{ Name = 'clangd'; Bucket = 'main' }
@{ Name = 'cmake'; Bucket = 'main' }
@{ Name = 'gcc-arm-none-eabi'; Bucket = 'extras' }
@{ Name = 'mingw'; Bucket = 'main' }
@{ Name = 'ninja'; Bucket = 'main' }
@{ Name = 'openocd'; Bucket = 'main' }
@{ Name = 'vcpkg'; Bucket = 'main' }
)
# 合并应用清单
$allApps = $coreApps + $personalApps
Write-Log "开始安装 $($allApps.Count) 个应用..." -Level INFO
foreach ($app in $allApps) {
Install-ScoopAppSafe -Name $app.Name -Bucket $app.Bucket
}
# 6. 生成执行报告
Write-SectionHeader "执行完成 - 统计报告"
$duration = (Get-Date) - $startTime
Write-Log "执行时长: $($duration.ToString('hh\:mm\:ss'))" -Level INFO
Write-Log "成功操作: $global:SuccessCount 项" -Level SUCCESS
Write-Log "跳过操作: $global:SkipCount 项" -Level SKIP
Write-Log "失败操作: $($global:FailedOperations.Count) 项" -Level $(if ($global:FailedOperations.Count -eq 0) { 'SUCCESS' } else { 'WARNING' })
Write-Log "aria2c 加速: $(if ($global:EnableAria2) { '已启用' } else { '未启用' })" -Level INFO
if ($global:FailedOperations.Count -gt 0) {
Write-Log "`n失败清单:" -Level WARNING
foreach ($failed in $global:FailedOperations) {
Write-Log " - $failed" -Level ERROR
}
Write-Log "`n建议: 修复网络/权限问题后重新运行本脚本,已完成的步骤会被自动跳过" -Level INFO
} else {
Write-Log "`n🎉 所有操作已成功完成!" -Level SUCCESS
}
Write-Log "`n详细日志已保存至: $LogPath" -Level INFO
}
# ============================================
# 脚本入口
# ============================================
try {
Main
} catch {
Write-Log "脚本执行出现未预期的错误: $($_.Exception.Message)" -Level ERROR
Write-Log "堆栈跟踪: $($_.ScriptStackTrace)" -Level ERROR
} finally {
Write-Log "`n脚本执行结束" -Level INFO
}