常用软件安装包下载工具
作者建议
我将文档发布到了多个平台,不同的平台阅读体验不同,排版也可能有区别,本人强烈建议直接点击下面的链接查看原始文档,因为下面的链接是原始文档,阅读体验极佳,排版美观,有目录结构,您可以很容易找到您想要阅读的章节。另外,文档一直持续更新,不断完善,内容更加准确且与时俱进。原始文档始终是最新版本的,其它平台中的文档可能已经过时了。
单击查看原始文档(持续更新中):《常用软件安装包下载工具》
如果您是在微信上查看此文章的,也可以直接点击文末的“阅读原文”查看原始文档
原创不易,如果对您有帮助,还请您一键三连[抱拳]
有任何问题都可以联系作者,文末有作者联系方式,欢迎交流。
以下是正文
为什么需要这个自动下载软件安装包的脚本
企业用户常用的许多软件,如微信、企业微信、钉钉、飞书、7zip、搜狗输入法等等,这些软件更新都比较频繁,而运维工程师希望每次安装这些软件时,都是最新版本的,传统手工下载的方法效率比较低。为了提供效率,我编写了一个Powershell脚本,可以自动下载常用的办公软件的安装包,更进一步,我们可以创建任务计划,比如让脚本每天凌晨3点自动运行,将下载的软件安装包放入文件服务器中。如此,文件服务器中的安装包始终是最新版本的,运维工程师完全不需要干预,整个都是自动化的。
Powershell脚本代码
代码已经在github上开源了,github项目网址为:iamtornado/Software-Download-Tool
进入网站后,可以查看README文件,有中文和英文版本的,详细说明了使用方法,在此就不赘述了。
<#
.SYNOPSIS
Download common software installers for offline installation.
.DESCRIPTION
This script downloads various commonly used software installers from official sources,
organizes them into separate folders, and saves them to the Downloads\SoftwarePackages directory.
It supports downloading via winget package manager or direct URLs.
.PARAMETER None
This script currently does not accept parameters.
.EXAMPLE
PS> .\download_software.ps1
Downloads all configured software packages.
.NOTES
File Name : download_software.ps1
Author : iamtornado (1426693102@qq.com)
Prerequisite : PowerShell 5.1 or higher, winget installed
Copyright : (c) 2025 iamtornado. All rights reserved.
License : MIT License
GitHub : https://github.com/iamtornado/Automatically_download_commonly_used_software_installation_packages
#>
# Set encoding and error handling
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$ErrorActionPreference = 'Stop'
# Script introduction
Write-Host @"
====================== Software Download Tool ======================
This script will:
1. Download common software installers for offline installation
2. Create organized folders for each software
3. Save all installers in the Downloads\SoftwarePackages directory
4. Generate detailed log file for the process
Software list:
- QQ
- 微信
- 企业微信
- 网易灵犀办公
- 7-Zip
- 搜狗拼音输入法
- 搜狗五笔输入法
- Microsoft Edge
- Microsoft Edge WebView2 Runtime
- 全时云会议软件
- 钉钉
- Microsoft Visual C++ Redistributable 2015-2022 (x86/x64)
================================================================
"@ -ForegroundColor Cyan
# Create statistics hashtable
$stats = @{
Successful = @()
Failed = @()
}
# Function to get software version from winget
function Get-SoftwareVersion {
param (
[string]$WingetId
)
try {
$wingetInfo = winget show $WingetId --accept-source-agreements
$versionLine = $wingetInfo | Where-Object { $_ -match 'Version:|版本:' }
if ($versionLine) {
return ($versionLine -split ':\s*')[1].Trim()
}
return "Version not found"
}
catch {
return "Version check failed"
}
}
# Create log directory
$logRoot = Join-Path $env:TEMP "IT_Service"
if (-not (Test-Path $logRoot)) {
New-Item -ItemType Directory -Path $logRoot -Force | Out-Null
}
# Start logging
$logFile = Join-Path $logRoot ("software_download_" + (Get-Date -Format "yyyyMMdd_HHmmss") + ".log")
Start-Transcript -Path $logFile -Force
# Display basic information
Write-Host "Software download script starting..."
Write-Host "PowerShell Version: $($PSVersionTable.PSVersion)"
Write-Host "Log file location: $logFile"
# Check PowerShell version
$requiredVersion = "5.1"
if ($PSVersionTable.PSVersion -lt [Version]$requiredVersion) {
Write-Error "PowerShell $requiredVersion or higher is required"
exit 1
}
# Get the actual download folder location
$shell = New-Object -ComObject Shell.Application
$downloads = $shell.NameSpace('shell:Downloads').Self.Path
# Define configuration parameters
$config = @{
MaxRetries = 3
RetryDelaySeconds = 3
TimeoutSeconds = 300
DownloadRoot = Join-Path $downloads 'SoftwarePackages'
SkipExisting = 1 # Added: 1 means skip if file exists, 0 means always download
}
# Define software list to download
$software = @(
@{
Name = "QQ"
Id = "Tencent.QQ.NT"
FileName = "QQ.exe"
},
@{
Name = "WeChat"
Id = "Tencent.WeChat"
FileName = "WeChatSetup.exe"
},
@{
Name = "企业微信"
Id = "Tencent.WeCom"
FileName = "WeCom.exe"
},
@{
Name = "网易灵犀办公"
Id = "NetEase.Lingxi"
FileName = "lingxi_win_x64.exe"
},
@{
Name = "7-Zip"
Id = "7zip.7zip"
FileName = "7zip.exe"
},
@{
Name = "搜狗拼音输入法"
Id = "Sogou.SogouInput"
FileName = "sogou_pinyin.exe"
},
@{
Name = "搜狗五笔输入法"
Id = "Sogou.SogouWBInput"
FileName = "sogou_wubi.exe"
},
@{
Name = "Microsoft Edge"
Id = "Microsoft.Edge"
FileName = "MicrosoftEdgeEnterpriseX64.msi"
},
@{
Name = "Microsoft Edge WebView2 Runtime"
Id = "Microsoft.EdgeWebView2Runtime"
FileName = "MicrosoftEdgeWebView2RuntimeInstallerX64.exe"
},
@{
Name = "全时云会议软件"
DirectUrl = "https://dle.quanshi.com/onemeeting/download/v2/G-Net_MeetNow_Setup.exe"
FileName = "G-Net_MeetNow_Setup.exe"
}
# @{
# Name = "DingTalk"
# Id = "Alibaba.DingTalk"
# FileName = "DingTalk_Setup.exe"
# }
)
# Special handling for Visual C++ Redistributable
$vcredist = @(
@{
Name = "VC_Redist_x64_VC++2015-2022(64bit)"
Url = "https://aka.ms/vs/17/release/vc_redist.x64.exe"
FileName = "VC_redist.x64.exe"
},
@{
Name = "VC_Redist_x86_VC++2015-2022(32bit)"
Url = "https://aka.ms/vs/17/release/vc_redist.x86.exe"
FileName = "VC_redist.x86.exe"
}
)
# Create download root directory
if (-not (Test-Path $config.DownloadRoot)) {
Write-Host "Download directory does not exist, creating: $($config.DownloadRoot)" -ForegroundColor Yellow
try {
New-Item -ItemType Directory -Path $config.DownloadRoot -Force | Out-Null
Write-Host "Successfully created download directory" -ForegroundColor Green
}
catch {
Write-Error "Failed to create download directory: $_"
exit 1
}
}
else {
Write-Host "Using existing download directory: $($config.DownloadRoot)" -ForegroundColor Green
}
# Verify downloaded file
function Test-DownloadedFile {
param (
[string]$FilePath,
[string]$Name
)
if (Test-Path $FilePath) {
$fileSize = (Get-Item $FilePath).Length
if ($fileSize -eq 0) {
Write-Error "$Name download failed: File size is 0"
Remove-Item $FilePath
return $false
}
return $true
}
return $false
}
# Generic file download function
function Invoke-FileDownload {
param (
[string]$Url,
[string]$OutputPath,
[string]$Name
)
# Check if file exists and skip if configured
if ($config.SkipExisting -eq 1 -and (Test-Path $OutputPath)) {
$fileSize = (Get-Item $OutputPath).Length
if ($fileSize -gt 0) {
Write-Host "File already exists and is valid, skipping download: $OutputPath" -ForegroundColor Yellow
return $true
}
else {
Write-Host "Existing file is empty, will download again: $OutputPath" -ForegroundColor Yellow
Remove-Item $OutputPath
}
}
$retryCount = 0
do {
try {
Write-Host "Downloading $Name..."
# Enable progress bar display
$ProgressPreference = 'Continue'
# Use Invoke-WebRequest to download file
Invoke-WebRequest -Uri $Url -OutFile $OutputPath -UseBasicParsing
if (Test-DownloadedFile -FilePath $OutputPath -Name $Name) {
Write-Host "Download completed: $Name" -ForegroundColor Green
return $true
}
}
catch {
$retryCount++
if ($retryCount -eq $config.MaxRetries) {
Write-Error ("Failed to download " + $Name + ": " + $_.Exception.Message)
return $false
}
Write-Warning "Download failed, retrying in $($config.RetryDelaySeconds) seconds ($retryCount/$($config.MaxRetries))..."
Start-Sleep -Seconds $config.RetryDelaySeconds
}
} while ($retryCount -lt $config.MaxRetries)
}
# Download regular software function
function Get-Software {
param (
[string]$Name,
[string]$WingetId,
[string]$FileName,
[string]$DirectUrl
)
Write-Host "`nProcessing $Name..." -ForegroundColor Cyan
# Create software-specific directory
$softwareDir = Join-Path $config.DownloadRoot $Name
if (-not (Test-Path $softwareDir)) {
New-Item -ItemType Directory -Path $softwareDir | Out-Null
}
try {
if ($DirectUrl) {
# Direct URL download
Write-Host "Using direct download URL for $Name"
$outputPath = Join-Path $softwareDir $FileName
if (Invoke-FileDownload -Url $DirectUrl -OutputPath $outputPath -Name $Name) {
$stats.Successful += @{
Name = $Name
Path = $outputPath
Version = "From direct URL"
}
} else {
$stats.Failed += $Name
}
return
}
# Get software version
$version = Get-SoftwareVersion -WingetId $WingetId
Write-Host "Querying winget for $WingetId information..."
# Get complete winget output for diagnostics
$allOutput = winget show $WingetId --accept-source-agreements
Write-Host "Winget complete output:" -ForegroundColor Yellow
$allOutput | ForEach-Object { Write-Host $_ }
# Try to get download URL
$info = $allOutput | Where-Object { $_ -match '安装程序 URL:\s*(.+)|Installer URL:\s*(.+)' }
if ($info) {
$url = if ($matches[1]) { $matches[1].Trim() } else { $matches[2].Trim() }
Write-Host "Found download URL: $url" -ForegroundColor Green
if ($url) {
# Use custom filename if provided, otherwise use URL filename
$outputFileName = if ($FileName) { $FileName } else { Split-Path $url -Leaf }
$outputPath = Join-Path $softwareDir $outputFileName
Write-Host "Download path: $outputPath"
# Download file
if (Invoke-FileDownload -Url $url -OutputPath $outputPath -Name $Name) {
$stats.Successful += @{
Name = $Name
Path = $outputPath
Version = $version
}
} else {
$stats.Failed += $Name
}
}
}
else {
Write-Warning "Could not get download link for $Name"
Write-Host "Please check if Winget ID is correct: $WingetId"
}
}
catch {
$stats.Failed += $Name
Write-Error ("Error processing " + $Name + ": " + $_.Exception.Message)
Write-Host "Error details:" -ForegroundColor Red
$_.Exception | Format-List -Force
}
}
# Download VC++ Redistributable function
function Get-VCRedist {
param (
[string]$Name,
[string]$Url,
[string]$CustomFileName
)
Write-Host "`nProcessing $Name..." -ForegroundColor Cyan
# Create VC++-specific directory
$vcDir = Join-Path $config.DownloadRoot $Name
if (-not (Test-Path $vcDir)) {
New-Item -ItemType Directory -Path $vcDir | Out-Null
}
try {
$fileName = if ($CustomFileName) {
$CustomFileName
} else {
Split-Path $Url -Leaf
}
$outputPath = Join-Path $vcDir $fileName
# Download file
Invoke-FileDownload -Url $Url -OutputPath $outputPath -Name $Name
}
catch {
Write-Error ("Error processing " + $Name + ": " + $_.Exception.Message)
}
}
# Main execution logic
Write-Host "`nStarting software downloads..." -ForegroundColor Yellow
# Download regular software
foreach ($item in $software) {
if ($item.DirectUrl) {
Get-Software -Name $item.Name -DirectUrl $item.DirectUrl -FileName $item.FileName
} else {
Get-Software -Name $item.Name -WingetId $item.Id -FileName $item.FileName
}
}
# Download VC++ Redistributable
foreach ($item in $vcredist) {
Get-VCRedist -Name $item.Name -Url $item.Url -CustomFileName $item.FileName
}
# After all downloads complete, show statistics
Write-Host "`n================= Download Statistics =================" -ForegroundColor Green
# Create custom objects for successful downloads
$successResults = $stats.Successful | ForEach-Object {
[PSCustomObject]@{
Name = $_.Name
Version = $_.Version
Path = $_.Path
}
}
# Display successful downloads in table format
Write-Host "`nSuccessfully downloaded software:" -ForegroundColor Green
$successResults | Format-Table -AutoSize -Wrap
# Display failed downloads if any
if ($stats.Failed.Count -gt 0) {
Write-Host "`nFailed downloads:" -ForegroundColor Red
$stats.Failed | ForEach-Object { Write-Host "- $_" }
}
Write-Host "`nSummary:"
Write-Host "Total successful: $($stats.Successful.Count)"
Write-Host "Total failed: $($stats.Failed.Count)"
Write-Host "`n==================================================" -ForegroundColor Green
# Stop logging at script end
Stop-Transcript
需要帮助
如果此脚本中没有包含你想要的软件安装包,可以联系本人,我可以定制,文末有联系方式。
关注我们,获取更多IT开发运维实用工具与技巧!
github用户名: iamtornado
github个人首页: https://github.com/iamtornado
电子邮箱: 1426693102@qq.com
个人微信:tornadoami(也可以通过下面的二维码加我,之后我将您邀请进入AI技术交流群)
QQ群: 715152187
微信公众号: AI发烧友