commit 58f026f30fbbb3966d115076af1582fbb3a0d637 Author: Julian Freeman Date: Fri Dec 5 22:46:17 2025 -0400 install software and make configurations diff --git a/assets/keepassxc/keepassxc.ini b/assets/keepassxc/keepassxc.ini new file mode 100644 index 0000000..1d05a54 --- /dev/null +++ b/assets/keepassxc/keepassxc.ini @@ -0,0 +1,15 @@ +[General] +ConfigVersion=1 +UpdateCheckMessageShown=true +RememberLastDatabases=false +RememberLastKeyFiles=false +OpenPreviousDatabasesOnStartup=false + +[GUI] +CheckForUpdates=false +TrayIconAppearance=monochrome + +[Security] +ClearClipboardTimeout=30 +LockDatabaseIdle=true +LockDatabaseIdleSeconds=600 diff --git a/assets/openoffice/historymanager2.1.oxt b/assets/openoffice/historymanager2.1.oxt new file mode 100644 index 0000000..6bdb720 Binary files /dev/null and b/assets/openoffice/historymanager2.1.oxt differ diff --git a/assets/openoffice/registrymodifications.xcu b/assets/openoffice/registrymodifications.xcu new file mode 100644 index 0000000..9f01d8c --- /dev/null +++ b/assets/openoffice/registrymodifications.xcu @@ -0,0 +1,274 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + zh-CN + + + + + true + + + + + 190,213,1424,714;1;0,0,0,0; + + + + + true + + + + + 4116m3(Build:9816) + + + + + 0 + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + true + + + + + + + + + + true + + + + + 0 + + + + + auto + + + + + 1 + + + + + true + + + + + false + + + + + false + + + + + true + + + + + false + + + + + true + + + + + false + + + + + true + + + + + 2 + + + + + true + + + + + 1 + + + + + + + + + + false + + + + + true + + + + + false + + + + + false + + + + + false + + + + + + + 565,335,,;;,,,; + + + + \ No newline at end of file diff --git a/assets/veracrypt/Configuration.xml b/assets/veracrypt/Configuration.xml new file mode 100644 index 0000000..0159167 --- /dev/null +++ b/assets/veracrypt/Configuration.xml @@ -0,0 +1,59 @@ + + + + 0 + 1 + 0 + 0 + 0 + 1 + 1 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 0 + 1 + 1 + 1 + 0 + 0 + 0 + 1 + -60 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 0 + 1 + 1 + zh-cn + + 1 + + \ No newline at end of file diff --git a/assets/vlc/vlcrc b/assets/vlc/vlcrc new file mode 100644 index 0000000..97cfed0 --- /dev/null +++ b/assets/vlc/vlcrc @@ -0,0 +1,10 @@ +[qt] # Qt interface +qt-recentplay=0 +qt-privacy-ask=0 +qt-updates-notif=0 + +[core] # core program +video-title-show=0 +vout=any +repeat=1 +metadata-network-access=0 diff --git a/config/adobe_acrobat.reg b/config/adobe_acrobat.reg new file mode 100644 index 0000000..1b775a9 --- /dev/null +++ b/config/adobe_acrobat.reg @@ -0,0 +1,4 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CURRENT_USER\Software\Adobe\Adobe Acrobat\DC\AVGeneral] +"iMaxMRUCntToBeStored"=dword:00000000 diff --git a/config/apps.json b/config/apps.json new file mode 100644 index 0000000..68fd128 --- /dev/null +++ b/config/apps.json @@ -0,0 +1,104 @@ +[ + { + "Name": "7-Zip", + "Id": "7zip.7zip", + "Version": "", + "PostInstall": [ + { + "Type": "Command", + "Command": "del /f /q \"C:\\Program Files\\7-Zip\\7-zip.chm\"", + "Description": "Remove 7-zip.chm file" + } + ] + }, + { + "Name": "Google Chrome", + "Id": "Google.Chrome", + "Version": "", + "PostInstall": [ + { + "Type": "RegImport", + "Path": "./config/chrome.reg" + } + ] + }, + { + "Name": "OpenOffice", + "Id": "Apache.OpenOffice", + "Version": "4.116.9816", + "PostInstall": [ + { + "Type": "Command", + "Command": "\"C:\\Program Files (x86)\\OpenOffice 4\\program\\soffice.exe\" -headless -nologo -nodefault", + "Description": "Run software once to generate the configuration files" + }, + { + "Type": "FileCopy", + "Source": "./assets/openoffice/registrymodifications.xcu", + "Destination": "$env:APPDATA\\OpenOffice\\4\\user\\registrymodifications.xcu" + }, + { + "Type": "Command", + "Command": "echo y | \"C:\\Program Files (x86)\\OpenOffice 4\\program\\unopkg.com\" add --shared -s \"$PSScriptRoot\\assets\\openoffice\\historymanager2.1.oxt\"", + "Description": "Install history extension" + } + ] + }, + { + "Name": "KeePassXC", + "Id": "KeePassXCTeam.KeePassXC", + "Version": "2.6.6", + "PostInstall": [ + { + "Type": "FileCopy", + "Source": "./assets/keepassxc/keepassxc.ini", + "Destination": "$env:APPDATA\\KeePassXC\\keepassxc.ini" + } + ] + }, + { + "Name": "VeraCrypt", + "Id": "IDRIX.VeraCrypt", + "Version": "1.26.20", + "PostInstall": [ + { + "Type": "FileCopy", + "Source": "./assets/veracrypt/Configuration.xml", + "Destination": "$env:APPDATA\\VeraCrypt\\Configuration.xml" + } + ] + }, + { + "Name": "File Shredder", + "Id": "PowTools.FileShredder", + "Version": "", + "PostInstall": [] + }, + { + "Name": "VLC", + "Id": "VideoLAN.VLC", + "Version": "", + "PostInstall": [ + { + "Type": "FileCopy", + "Source": "./assets/vlc/vlcrc", + "Destination": "$env:APPDATA\\vlc\\vlcrc" + }, + { + "Type": "RegImport", + "Path": "./config/vlc.reg" + } + ] + }, + { + "Name": "Adobe Acrobat Reader", + "Id": "Adobe.Acrobat.Reader.64-bit", + "Version": "", + "PostInstall": [ + { + "Type": "RegImport", + "Path": "./config/adobe_acrobat.reg" + } + ] + } +] \ No newline at end of file diff --git a/config/chrome.reg b/config/chrome.reg new file mode 100644 index 0000000..69f5f80 --- /dev/null +++ b/config/chrome.reg @@ -0,0 +1,49 @@ +Windows Registry Editor Version 5.00 + +;uBlock Origin Lite +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\ExtensionSettings\ddkjiahejlhfcafbddmgiahcphecmpfh] +"installation_mode"="normal_installed" +"update_url"="https://clients2.google.com/service/update2/crx" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome\Recommended] +"AutofillAddressEnabled"=dword:00000000 +"AutofillCreditCardEnabled"=dword:00000000 +"DefaultGeolocationSetting"=dword:00000002 +"PasswordManagerEnabled"=dword:00000000 +"PaymentMethodQueryEnabled"=dword:00000000 +"PrivacySandboxAdMeasurementEnabled"=dword:00000000 +"PrivacySandboxAdTopicsEnabled"=dword:00000000 +"PrivacySandboxPromptEnabled"=dword:00000000 +"PrivacySandboxSiteEnabledAdsEnabled"=dword:00000000 + +; Microsoft Edge (Bonus ;) +;uBlock Origin +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\ExtensionSettings\odfafepnkmbhccpbejgmiehpchacaeak] +"installation_mode"="normal_installed" +"update_url"="https://edge.microsoft.com/extensionwebstorebase/v1/crx" + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\Recommended] +"AlternateErrorPagesEnabled"=dword:00000000 +"AutofillAddressEnabled"=dword:00000000 +"AutofillCreditCardEnabled"=dword:00000000 +"AutofillMembershipsEnabled"=dword:00000000 +"ConfigureDoNotTrack"=dword:00000001 +"ControlDefaultStateOfAllowExtensionFromOtherStoresSettingEnabled"=dword:00000001 +"DefaultGeolocationSetting"=dword:00000002 +"DiagnosticData"=dword:00000001 +"EdgeShoppingAssistantEnabled"=dword:00000000 +"EdgeWalletCheckoutEnabled"=dword:00000000 +"PasswordManagerEnabled"=dword:00000000 +"PaymentMethodQueryEnabled"=dword:00000000 +"PersonalizationReportingEnabled"=dword:00000000 +"PrimaryPasswordSetting"=dword:00000003 +"RelatedMatchesCloudServiceEnabled"=dword:00000000 +"ResolveNavigationErrorsUseWebService"=dword:00000000 +"ShowMicrosoftRewards"=dword:00000000 +"TabServicesEnabled"=dword:00000000 + +[HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Edge\Recommended\ManagedSearchEngines\1] +"is_default"=dword:00000001 +"keyword"="google.com" +"name"="Google" +"search_url"="{google:baseURL}search?q={searchTerms}&{google:RLZ}{google:originalQueryForSuggestion}{google:assistedQueryStats}{google:searchboxStats}{google:searchFieldtrialParameter}{google:iOSSearchLanguage}{google:prefetchSource}{google:searchClient}{google:sourceId}{google:contextualSearchVersion}ie={inputEncoding}" diff --git a/config/vlc.reg b/config/vlc.reg new file mode 100644 index 0000000..7a74ede --- /dev/null +++ b/config/vlc.reg @@ -0,0 +1,4 @@ +Windows Registry Editor Version 5.00 + +[HKEY_CURRENT_USER\Software\VideoLAN\VLC] +"Lang"="zh_CN" diff --git a/install.bat b/install.bat new file mode 100644 index 0000000..6b99e98 --- /dev/null +++ b/install.bat @@ -0,0 +1,26 @@ +@echo off +:: ========================================== +:: 自动化装机工具启动器 +:: ========================================== + +:: 1. 强制切换到当前批处理文件所在的目录 +:: 这一步至关重要,防止以管理员身份运行时路径变成了 C:\Windows\System32 +cd /d "%~dp0" + +:: 2. 检查管理员权限 +if not "%1" == "am_admin" ( + rem you'd better keep the following line as it is. + powershell start -verb runas '%0' am_admin & exit /b +) + +:: ========================================== +:: 3. 核心执行逻辑 +:: ========================================== + +echo Calling main.ps1... + +:: -NoProfile: 不加载用户配置文件,加快启动速度 +:: -ExecutionPolicy Bypass: 绕过默认的脚本执行策略限制 +:: -File: 指定要运行的脚本文件 + +powershell.exe -NoExit -NoProfile -ExecutionPolicy Bypass -File ".\main.ps1" diff --git a/lib/invoke-cmdexec.ps1 b/lib/invoke-cmdexec.ps1 new file mode 100644 index 0000000..df7a41e --- /dev/null +++ b/lib/invoke-cmdexec.ps1 @@ -0,0 +1,54 @@ +param( + [Parameter(Mandatory=$true)] [string]$Command, + [string]$WorkDir = $null +) + +# 1. 处理工作目录 +if ([string]::IsNullOrEmpty($WorkDir)) { + $WorkDir = $PSScriptRoot +} else { + # 如果 WorkDir 里包含变量(如 $env:APPDATA),展开它 + $WorkDir = $ExecutionContext.InvokeCommand.ExpandString($WorkDir) +} + +# 确保目录存在,否则命令会报错 +if (-not (Test-Path $WorkDir)) { + Write-Warning "`n[CMD] WARNING: The work dir does not exist, using ($WorkDir)" + $WorkDir = $PSScriptRoot +} + +# 2. 处理命令中的环境变量 +$ProjectRoot = Split-Path $PSScriptRoot -Parent +# === 替换 $PSScriptRoot 为实际的绝对路径 === +# 注意:要处理反斜杠转义问题,直接用字符串替换最安全 +if ($Command.Contains('$PSScriptRoot')) { + $Command = $Command.Replace('$PSScriptRoot', $ProjectRoot) +} + +# 这一步很关键,让你可以写 "echo $env:USERNAME" +$Command = $ExecutionContext.InvokeCommand.ExpandString($Command) + +Write-Host "`n[CMD] Execute: $Command" -ForegroundColor Gray + +# 3. 启动进程 +# /c 表示执行完命令后关闭 cmd 窗口 +# /s 开启参数的一般处理(忽略第一个和最后一个引号,为了兼容复杂引号情况) +$processOptions = @{ + FilePath = "cmd.exe" + ArgumentList = "/s", "/c", "`"$Command`"" + WorkingDirectory = $WorkDir + Wait = $true + NoNewWindow = $true + PassThru = $true +} + +try { + $proc = Start-Process @processOptions + + # 4. 检查退出代码 (ExitCode) + if ($proc.ExitCode -ne 0) { + Write-Error "`n[CMD] Failed to execute, exit code: $($proc.ExitCode)" + } +} catch { + Write-Error "`n[CMD] Failed to start process: $_" +} \ No newline at end of file diff --git a/lib/invoke-filecopy.ps1 b/lib/invoke-filecopy.ps1 new file mode 100644 index 0000000..fe202f4 --- /dev/null +++ b/lib/invoke-filecopy.ps1 @@ -0,0 +1,41 @@ +param( + [Parameter(Mandatory=$true)] + [string]$Source, + + [Parameter(Mandatory=$true)] + [string]$Destination +) + +try { + # 1. 路径预处理:展开环境变量 (例如把 $env:APPDATA 变成 C:\Users\...\AppData\Roaming) + $ResolvedSource = $ExecutionContext.InvokeCommand.ExpandString($Source) + $ResolvedDest = $ExecutionContext.InvokeCommand.ExpandString($Destination) + + # 2. 处理相对路径 (针对源文件) + # 如果源路径是相对路径 (./assets/...), 尝试将其转换为绝对路径 + # 假设脚本是从项目根目录调用的 + if (-not (Test-Path $ResolvedSource) -and (Test-Path "$PWD\$ResolvedSource")) { + $ResolvedSource = Join-Path $PWD $ResolvedSource + } + + # 3. 再次检查源文件是否存在 + if (-not (Test-Path $ResolvedSource -PathType Leaf)) { + Write-Warning "`n[FileCopy] [Skip] File not found: $ResolvedSource" + return # 退出脚本 + } + + # 4. 处理目标目录 (自动创建不存在的文件夹) + $DestDir = Split-Path -Path $ResolvedDest -Parent + if (-not (Test-Path $DestDir)) { + Write-Host "`n[FileCopy] Create dir: $DestDir" -ForegroundColor DarkGray + New-Item -Path $DestDir -ItemType Directory -Force | Out-Null + } + + # 5. 执行复制 (Force = 覆盖) + Copy-Item -Path $ResolvedSource -Destination $ResolvedDest -Force -ErrorAction Stop + + Write-Host "`n[FileCopy] Success: $ResolvedDest" -ForegroundColor Green + +} catch { + Write-Error "`n[FileCopy] Fail: $_" +} \ No newline at end of file diff --git a/lib/invoke-regimport.ps1 b/lib/invoke-regimport.ps1 new file mode 100644 index 0000000..a3d1eeb --- /dev/null +++ b/lib/invoke-regimport.ps1 @@ -0,0 +1,37 @@ +param( + [Parameter(Mandatory=$true)] + [string]$Path +) + +try { + # 1. 路径预处理 + # 展开环境变量 (虽然 .reg 路径通常是固定的,但支持一下没坏处) + $ResolvedPath = $ExecutionContext.InvokeCommand.ExpandString($Path) + + # 2. 处理相对路径 + # 如果路径是相对的 (./assets/...), 转换为绝对路径 + if (-not (Test-Path $ResolvedPath) -and (Test-Path "$PWD\$ResolvedPath")) { + $ResolvedPath = Join-Path $PWD $ResolvedPath + } + + # 3. 检查文件是否存在 + if (-not (Test-Path $ResolvedPath)) { + Write-Warning "`n[RegImport] [Skip] Cannot find: $ResolvedPath" + return + } + + Write-Host "`n[RegImport] Importing: $(Split-Path $ResolvedPath -Leaf)" -ForegroundColor Gray + + # 4. 调用 reg.exe 导入 + # 使用 Start-Process 以获取退出代码 + $proc = Start-Process -FilePath "reg.exe" -ArgumentList "import", "`"$ResolvedPath`"" -Wait -PassThru -NoNewWindow + + if ($proc.ExitCode -eq 0) { + Write-Host "`n[RegImport] Successfully imported." -ForegroundColor Green + } else { + Write-Error "`n[RegImport] Failed to import: $($proc.ExitCode)" + } + +} catch { + Write-Error "`n[RegImport] Failed to start process: $_" +} \ No newline at end of file diff --git a/main.ps1 b/main.ps1 new file mode 100644 index 0000000..e158c44 --- /dev/null +++ b/main.ps1 @@ -0,0 +1,119 @@ +# 设置严格模式,遇到错误停止,防止错误的命令雪崩 +$ErrorActionPreference = "Stop" +#Set-StrictMode -Version Latest + +# === 1. 加载依赖库 === +# 确保 lib 目录存在 +if (-not (Test-Path "$PSScriptRoot\lib")) { + Write-Error "Cannot find ./lib, some files missing." + exit 1 +} + +# === 2. 读取配置 === +$jsonPath = "$PSScriptRoot\config\apps.json" +if (-not (Test-Path $jsonPath)) { + Write-Error "Cannot find: $jsonPath" + exit 1 +} + +Write-Host "Reading configurations..." -ForegroundColor Cyan +# 使用 UTF8 读取防止中文乱码 +$apps = Get-Content $jsonPath -Encoding UTF8 | ConvertFrom-Json + +# === 3. 主循环 === +foreach ($app in $apps) { + Write-Host "`n==========================================" -ForegroundColor Cyan + Write-Host "Installing: $($app.Name)" -ForegroundColor Yellow + Write-Host "==========================================" + + # --- 步骤 A: Winget 安装 --- + $wingetArgs = @( + "install", + "--id", $app.Id, + "-e", + "--silent", + "--accept-package-agreements", + "--accept-source-agreements", + "--disable-interactivity", + "--scope", "machine" + ) + + # [版本检查逻辑] + # 检查 Version 是否存在且不为空字符串 + if (-not [string]::IsNullOrWhiteSpace($app.Version)) { + Write-Host "-> Version: $($app.Version)" + $wingetArgs += "-v" + $wingetArgs += $app.Version + } else { + Write-Host "-> Version: latest" + } + + Write-Host "-> Installing via winget..." + + # 执行安装 + $proc = Start-Process -FilePath "winget" -ArgumentList $wingetArgs -Wait -PassThru -NoNewWindow + + # 检查安装结果 (0=成功, -1978335189=已安装) + if ($proc.ExitCode -eq 0) { + Write-Host "[Success]" -ForegroundColor Green + } elseif ($proc.ExitCode -eq -1978335189) { + Write-Host "[Skip] Already installed" -ForegroundColor Yellow + continue # 已经安装的为了避免覆盖配置,也就不配置了 + } else { + Write-Error "[Fail] Error code: $($proc.ExitCode)" + continue # 安装失败则跳过后续配置 + } + + # --- 步骤 B: PostInstall 配置 --- + if ($app.PostInstall -and $app.PostInstall.Count -gt 0) { + Write-Host "`n-> Configuring..." -ForegroundColor Cyan + + $stepIndex = 0 + foreach ($action in $app.PostInstall) { + + # [间隔逻辑] 如果这不是第一步,先等待 2 秒 + if ($stepIndex -gt 0) { + Write-Host "(Waiting 2 seconds...)" -ForegroundColor DarkGray + Start-Sleep -Seconds 2 + } + + try { + switch ($action.Type) { + + # 1. 复制文件 + "FileCopy" { + & "$PSScriptRoot\lib\invoke-filecopy.ps1" ` + -Source $action.Source ` + -Destination $action.Destination + } + + # 2. 导入注册表 + "RegImport" { + & "$PSScriptRoot\lib\invoke-regimport.ps1" ` + -Path $action.Path + } + + # 3. 执行 CMD + "Command" { + & "$PSScriptRoot\lib\invoke-cmdexec.ps1" ` + -Command $action.Command ` + -WorkDir $action.WorkDir + } + + Default { + Write-Warning "`nUnknown action: $($action.Type)" + } + } + } catch { + Write-Error "`nFailed to operate step $($stepIndex + 1): $_" + } + + $stepIndex++ + } + } else { + Write-Host "-> No configurations." -ForegroundColor DarkGray + } +} + +Write-Host "`n=== Done ===" -ForegroundColor Green +Pause