常用软件安装包下载工具 (1)

常用软件安装包下载工具

作者建议

我将文档发布到了多个平台,不同的平台阅读体验不同,排版也可能有区别,本人强烈建议直接点击下面的链接查看原始文档,因为下面的链接是原始文档,阅读体验极佳,排版美观,有目录结构,您可以很容易找到您想要阅读的章节。另外,文档一直持续更新,不断完善,内容更加准确且与时俱进。原始文档始终是最新版本的,其它平台中的文档可能已经过时了。

单击查看原始文档(持续更新中):《常用软件安装包下载工具》

如果您是在微信上查看此文章的,也可以直接点击文末的“阅读原文”查看原始文档

原创不易,如果对您有帮助,还请您一键三连[抱拳]

有任何问题都可以联系作者,文末有作者联系方式,欢迎交流。

以下是正文

为什么需要这个自动下载软件安装包的脚本

企业用户常用的许多软件,如微信、企业微信、钉钉、飞书、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技术交流群)

lQLPJwkTm2qaAEvNBcDNBDawOy5xMLUjK4AH5hR9heXzAA_1078_1472.png

QQ群: 715152187

微信公众号: AI发烧友

AI发烧友公众号宣传图片.pngimage.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值