PowerShell 自动更新Ungoogled-Chromium

Ungoogled-Chromium纯开源,没有自动更新服务器,版本更新又相对频繁,以Windows PowerShell脚本实现自动检查更新。

2024-07-23第一版,2024-09-06第二版修正错误。

第二版尚未解决的问题:

1. 如何适用 Invoke-RestMethod 指令向镜像站点页面填充原始下载链接,还不明白,必须有人先使用镜像站点下载过二进制包才能完成更新。

2. $? 变量不能赋值操作,脚本执行还存在漏洞,有精力再完善。

个人笔记向,新手向,逐行注释。

# Ungoogled-Chromium 路径位于D:\Tools\ungoogled-chromium
Set-Location D:\Tools\

# 读取downloads页面中所有链接,强制以数组形式保存于变量,pwsh按说可以自动变量类型,
# 但后面有一个变量读取后,自动类型生成了数组,但Count为1,把多行换行符分割的数据塞
# 进了数组一个单元内。
[array]$ucghrls = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/").Links.Href

# 查找数组中元素是windows 64位的一项,并以字符串格式存储这一元素内容。使用IndexOf
# 指令时,有可能发生查找结果为“-1”的情况,但检查数组Count,以及用数组元素编号单独
# 检查内容,都没发现异常,不清楚为什么不能在特定数组中筛选出特征内容。
# for语句在查找到所需内容后,即break退出循环,后面有一个数组相对比较大,略微节省一
# 下机器资源。
for ($l = 0; $l -le $ucghrls.Length; $l++) {if ($ucghrls[$l] -match "/ungoogled-chromium-binaries/releases/windows/64bit") {[string]$ucghrls = $ucghrls[($l+1)]; break}}

# TrimStart删除的是变量中符合特征的字符,如果仅描述“64bit”,则前面的
# “releases/windows”等等字符会被保留。
$ucghrls = $ucghrls.TrimStart("/ungoogled-chromium-binaries/releases/windows/64bit/")

# 版本号变量截取字符串没出现换行问题。
[string]$uclastver = $ucghrls.Substring(0, ($ucghrls | Select-String "-").Matches.Index)

# 浏览器目录内包含一个“版本号”.manifest的文件,可以直接以文本形式读到浏览器的版本。
[string]$ucrunningver = Get-Content -Path D:\Tools\ungoogled-chromium\*.manifest | Select-String -Pattern 'version' -CaseSensitive -SimpleMatch | Out-String

# Substring标识起始位置,但不标识终止位置,则从起始位置一直读取到变量末尾。
$ucrunningver = $ucrunningver.Substring(($ucrunningver | Select-String "version").Matches.Index +9)

# 起始位置标0,不可省略,再结合终止位置,丢弃掉终止位置以后的字符。
$ucrunningver = $ucrunningver.Substring(0, ($ucrunningver | Select-String "'").Matches.Index)

# 运行版本与最新版本一致则退出脚本,应注意exit, return指令区别。
if ($uclastver -ceq $ucrunningver) {return}

# 这里就是不能筛选出特征字符所在行的数组,尚不清楚为什么不能使用IndexOf获取反馈,
# 如果知道原因,欢迎留言反馈。
# 截取字符串出现第一版的很严重一个错误,使用管道符查找特征字符组合cmdlet时,字符会
# 适应窗口宽度,出现了一个不是换行符不是回车符的换行。正文后面具体说明。
[array]$uclastverurl = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/releases/windows/64bit/$ucghrls").Links.Href

# 不能使用
# $uclastverurl[([array]::IndexOf($uclastverurl, [string]'_windows_x64.zip'))]
# 筛选出行号,无论[string]写什么,这个数组反馈都是“-1”,这个问题就是上面一句的错误造成。
for ($l = 0; $l -le $uclastverurl.Length; $l++) {if ($uclastverurl[$l] -match "_windows_x64.zip") {[string]$uclastverurl = $uclastverurl[$l]; break}}

# 这里需要读取的是网页body部分,但不明白为什么带有回车符的多行字符会被塞进一个元素
# 变量赋值以后,运行 $ucghhash.Count 反馈是 “1”
[array]$ucghhash = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/releases/windows/64bit/$ucghrls").Content

# 没办法,以换行符分割元素,重新对数组赋值。
$ucghhash = $ucghhash -split"`n"

# 查找windows x64压缩包链接所在行,下面的HASH,三行依次是MD5、SHA1、SHA256。
for ($l = 0; $l -le $ucghhash.Length; $l++) {if ($ucghhash[$l] -match "_windows_x64.zip") {[string]$ucghhash = $ucghhash[$l +2]; break}}

# 其实也可以用TrimStart,但是要写全前面不参与碰撞的html字符。
$ucghhash = $ucghhash.Substring(($ucghhash | Select-String "<code>").Matches.Index +6)

# 同理也可以用TrimEnd,也得写全,但是有可能造成变量中仍包含多余的换行符。
$ucghhash = $ucghhash.Substring(0, ($ucghhash | Select-String "</code>").Matches.Index)

# 完整的release包名称是“ungoogle-chromium_'版本号'-'不知道是个什么含义的数字'_'对应系统'.zip”
$ucorgpkg = $uclastverurl.Substring(($uclastverurl | Select-String "/ungoogled-chromium_").Matches.Index +1)

# 读取国内可下载github镜像的链接列表,但是这个站点并非是镜像了全部github上的数据,
# 需要手动填写github链接,它下载以后,再从它这里下载。
[array]$ucinfwurl += (Invoke-WebRequest -Uri "https://d.serctl.com/?dl_list=13").Links.Href

# 原始二进制文件名在这里派上用场,镜像站点会在原始文件名前添加时间和项目名称之类。
for ($l = 0; $l -le ($ucinfwurl.Length +1); $l++) {if ($ucinfwurl[$l] -match $ucorgpkg) {[string]$ucinfwurl = $ucinfwurl[$l]; break} elseif ($l -gt $ucinfwurl.Length) {Clear-Variable -Name ucinfwurl}}

# 检查本地是否存在Ungoogled-Chromium下载文件。
if (Get-Item -Path ungoogled-chromium_*.zip) {

    # 以文件写入时间排序,对pkglist赋值,但是这么做不太科学,镜像站点会修改文件时间。
    # 造成高版本的文件时间有可能早于低版本,按说应该以版本号作为排序依据,但是懒得那么干了。
    $pkglist = (Get-ChildItem -Path ungoogled-chromium_*.zip | Sort-Object -Property LastWriteTime -Descending)

    # 保留修改时间最新的文件,删除其余,否则在文件名中查找版本号语句会获取一个空值。
    for ($f = 1; $f -lt $pkglist.Length ; $f++) {Remove-Item -Force -Path $pkglist[$f]}

    # 在文件名中获取版本号,这办法相当偷懒,如果有下一个版本的脚本再修改。
    $ucpkgver = (Get-ChildItem -Path ungoogled-chromium_*.zip).Name
    $ucpkgver = $ucpkgver.TrimStart("ungoogled-chromium_")
    $ucpkgver = $ucpkgver.Substring(0, ($ucpkgver | Select-String "-").Matches.Index)
}

# 版本号包含多个以小数点表达的分隔符,数学运算符有可能无法判别主版本号大小。
# 检查已下载压缩包版本与github是否不符,且包版本不为空,两条件都成立则下载。
if (($uclastver -cne $ucpkgver) -and ($ucpkgver -ne $null)) {

    # 删除掉版本不符的本地文件。
    if (Get-Item -Path ungoogled-chromium_*.zip) {Remove-Item -Path (Get-Item -Path ungoogled-chromium_*.zip).Name}

    # 先判断国内可用镜像连接是否存在,如存在优先从镜像下载。使用-ErrorAction SilentlyContinue
    # 参数,可以让cmdlet返回一个布尔值,而不是难以使用脚本分析的错误提示。
    # 这里保持第一版使用 Start-BitsTransfer 指令,如采取 Invoke-WebRequest 指令,格式是:
    # Invoke-WebRequest -Uri $ucinfwurl -OutFile $ucorgpkg 后面erroraction参数自行添加。
    # 这两个指令在下载时,区别不仅仅在于是不是必须指定目的文件名,Start-BitsTransfer直接写盘
    # Invoke-WebRequest 是写入内存,下载期间目标文件长度为0,下载完成后才填充至磁盘。
    # 可用于下载的指令还有 Invoke-RestMethod,
    # 和 (new-object System.Net.WebClient).DownloadFile('src_url', 'dst_file'))
    # 具体区别自行查找网页。
    if ($ucinfwurl -ne $null) {Start-BitsTransfer -TransferType Download -Source $ucinfwurl -Destination $ucorgpkg -ErrorAction SilentlyContinue}

    # 国内镜像不存在,下载github站内新版本的压缩包,如使用代理服务器,需自行搭建。
    # Start-BitsTransfer 指令加上 -ProxyUsage Override -ProxyList 127.0.0.1:1080
    # 参数,结合自己环境,自行修改吧。
    else {Start-BitsTransfer -TransferType Download -Source $uclastverurl -ErrorAction SilentlyContinue}

    # '$?'就是前一条指令的返回值,计算已下载文件哈希,碰撞失败则删除压缩包。
    # 第一版中 ($programrun.ExitCode -eq 0) 的办法只适用于shell外部的exec程序,读取返回码。
    if ($?) {$filehash = (Get-FileHash -Path $ucorgpkg -Algorithm SHA1).Hash}

    # pwsh计算的HASH用的是大写字母表达,linux是小写字母表达,碰撞的时候要忽略大小写。
    # 碰撞不符时,删除已下载文件。
    if ($filehash -ine $ucghhash) {Remove-Item -Path $ucorgpkg}
}

# 判断Ungoogled-Chromium未运行,没找到更好的办法,chrome这个系列的浏览器,内存进程名称
# 都叫chrome.exe,没办法,只好从程序所在路径上判断。
# 并检查项目上当前版本压缩包是否存在,且本地压缩包版本与本地运行版本不符,三条件是否都成立。
if (((Get-Process -Name chrome).Path -notmatch "ungoogled-chromium") -and (Get-Item -Path $ucorgpkg) -and ($uclastver -cne $ucpkgver)) {

    # 重命名主程序文件,避免更新时占用,导致更新失败。
    Rename-item -Path ".\ungoogled-chromium\chrome.exe" -NewName ".\ungoogled-chromium\chrome.exe.bak"

    # 哈希碰撞通过才解压缩。
    if ($filehash -ieq $ucghhash) {Expand-Archive -Path $ucorgpkg -DestinationPath .\ -ErrorAction SilentlyContinue}

    # 解压缩成功则递归删除旧版本整个目录,将新版本路径重命名。
    if ($?) {
        Remove-item -Force -Relastse -Path "ungoogled-chromium"
        Rename-Item -Path (Get-ChildItem -Path ungoogled-chromium_* -Directory).Name -NewName "ungoogled-chromium"

    # 解压缩失败,主程序文件名恢复使用状态,并递归删除解压缩失败的压缩包及目录。
    } else {
        Rename-item -Path ".\ungoogled-chromium\chrome.exe.bak" -NewName ".\ungoogled-chromium\chrome.exe"
        Remove-item -Force -Relastse -Path "ungoogled-chromium_*"
    }
}

第一版运行时发生的问题:

$uccurverurl 变量中“ungoogled”和“window”两个词后面都有一个换行,这个应该跟我这里配置窗口宽度100字符有关,但是这个换行最诡异的地方,删除空格、制表符、换行符、回车符都不能把内容转换成单行。在后面执行 Start-BitsTransfer 指令时,会提示:“找不到的驱动器。名为 “https: ”的驱动器不存在”

非要以第一版指令运行,需要增加:把变量转换成数组,以换行符拆分数组,数组拼接以后再转换回字符串,四个动作完成以后,才能单行显示。

拖动窗口宽度时发现,这个问题不是 Invoke-WebRequest 造成, Invoke-WebRequest的反馈结果不分行。是 Select-String 的输出结果分行了。

且第一版语句不加最后的Out-String,变量类型是MatchInfo,后面没法进行字符串截取动作。

PS C:\> $uccurverurl = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/releases/windows/64bit/$uccurverpath").Links | Select-String -Pattern '_windows_x64.zip' -Context 0,0 -CaseSensitive -SimpleMatch | Out-String

PS C:\> $uccurverurl = $uccurverurl.Substring((($uccurverurl | Select-String "<A href=").Matches.Index +9), (($uccurverurl | Select-String "`">").Matches.Index - ($uccurverurl | Select-String "<A href=").Matches.Index -9))

PS C:\> $uccurverurl
https://github.com/ungoogled-software/ungoogled
-chromium-windows/releases/download/128.0.6613.119-1.1/ungoogled-chromium_128.0.6613.119-1.1_window
s_x64.zip

PS C:\> $uccurverurl.trim()
https://github.com/ungoogled-software/ungoogled
-chromium-windows/releases/download/128.0.6613.119-1.1/ungoogled-chromium_128.0.6613.119-1.1_window
s_x64.zip

PS C:\> $uccurverurl.trim("`t`n`r")
https://github.com/ungoogled-software/ungoogled
-chromium-windows/releases/download/128.0.6613.119-1.1/ungoogled-chromium_128.0.6613.119-1.1_window
s_x64.zip

PS C:\> $uccurverurl.gettype()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     True     String                                   System.Object


PS C:\> $uccurverurl[0]
h

这里是第一版脚本,有错误,不要使用:

# 在binaries页面上查找Windows x64当前版本,页面内容只截取包含关键字的行,包含前后0行内容。
$uccurverpath = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/").Links | Select-String -Pattern '/ungoogled-chromium-binaries/releases/windows/64bit' -Context 0,0 -CaseSensitive -SimpleMatch
 
# 把变量类型转换为字符串,只保留第2行内容,第1行内容是指向x64所有版本号的链接,没什么用。
$uccurverpath = $uccurverpath[1].ToString()
 
# 截取网页内容部分的版本号,但是这个版本号后面带一个“-N”,不一定N=1,老版本时出现过2和3。
$uccurverpath = $uccurverpath.Substring((($uccurverpath | Select-String "innerHTML=").Matches.Index +10), (($uccurverpath | Select-String "; innerText").Matches.Index - ($uccurverpath | Select-String "innerHTML=").Matches.Index -10))
 
# 将网页版本号后面的“-N”去掉,这个变量在后面比较版本号使用。
$uccurver = $uccurverpath.Substring(0, ($uccurverpath | Select-String "-").Matches.Index)
 
# 在当前版本页面上截取ZIP包的行,并以字符串赋值,不加最后的Out-String,变量类型是MatchInfo,后面没法进行字符串截取动作。
# 我这里设置下载绿色版,而且我不希望ungoogled-chromium写入注册表以后被其他程序调用,就不下载exec安装程序。
# 为了和binaries页面上保持一致,这里使用带有“-N”的版本号描述页面路径。
$uccurverurl = (Invoke-WebRequest -Uri "https://ungoogled-software.github.io/ungoogled-chromium-binaries/releases/windows/64bit/$uccurverpath").Links | Select-String -Pattern '_windows_x64.zip' -Context 0,0 -CaseSensitive -SimpleMatch | Out-String
 
# 截取变量中<A href=" ... ">引号中间的部分,单双引号在pwsh中都有含义定义,结尾处特征是转义双引号+大于号。
$uccurverurl = $uccurverurl.Substring((($uccurverurl | Select-String "<A href=").Matches.Index +9), (($uccurverurl | Select-String "`">").Matches.Index - ($uccurverurl | Select-String "<A href=").Matches.Index -9))
 
# 查找本地硬盘上ungoogled-chromium所在路径内,一个“版本号.manifest”文件,并读取其中version所在行,前后涵盖0行,out-string指令作用与上面一样。
$ucrunningver = Get-Content -Path D:\Tools\ungoogled-chromium\*.manifest | Select-String -Pattern 'version' -Context 0,0 -CaseSensitive -SimpleMatch | Out-String
 
# 丢弃变量内"version="和第一个单引号,以及之前的字符。
$ucrunningver = $ucrunningver.Substring(($ucrunningver | Select-String "version").Matches.Index +9)
 
# 丢弃变量内的另一个单引号,以及后面的字符,注意单引号后有不可见字符,字符串长度并非到单引号为止。
$ucrunningver = $ucrunningver.Substring(0, ($ucrunningver | Select-String "'").Matches.Index)
 
# 变换当前目录,没什么可说明的。
Set-Location D:\Tools\
 
# 版本号包含多个以小数点表达的分隔符,数学运算符有可能无法判别版本号大小,比如产生123.1.001小于120.5.005的错误。
if ($uccurver -cne $ucrunningver) {
 
    # 如果旧版本软件包存在则删除。
    if (Get-Item -Path ungoogled-chromium_*) {Remove-Item -Path (Get-Item -Path ungoogled-chromium_*).Name}
 
    # 注意Start-BitsTransfer是Windows自带的那个pwsh版本带的指令,后装的v7没这个指令,需要其他工具执行下载任务,
    # -TransferType是个说明用的参数,不加这个参数,默认就是Download。至于为什么不用Invoke-WebRequest指令,
    # 单纯是懒得指定下载到本地文件名,保持网站上原有名称。
    Start-BitsTransfer -TransferType Download -Source $uccurverurl
 
    # pwsh的Expand-Archive指令只能解压缩ZIP,不能测试,这里先测试一下压缩包,避免网络中断,造成只下载了一半压缩包,
    # 展开时造成错误,原因你懂的。7z.exe我放在D:\Tools目录下,路径不同的话需要文件名前加路径。-Wait参数限制7z执行完毕后才执行下一条指令。
    $programrun = (Start-Process -FilePath "7z.exe" -ArgumentList "t (Get-Item -Path ungoogled-chromium_*).Name" -PassThru -Wait)
    if ($programrun.ExitCode -eq 0) {
 
        # 展开ZIP压缩包确认成功了,再进行删除动作,没成功还删除就没得用了。
        $programrun = (Start-Process -FilePath "7z.exe" -ArgumentList "x (Get-Item -Path ungoogled-chromium_*).Name" -PassThru -Wait)
        if ($programrun.ExitCode -eq 0) {
 
            # 递归删除ungoogled-chromium下所有的文件、文件夹。
            Remove-item -Force -Recurse -Path "ungoogled-chromium"
 
            # 找准子目录改名,Get-Item指令会定位到刚下载的压缩包,和已经展开的子目录。
            Rename-Item -Path (Get-ChildItem -Path ungoogled-chromium* -Directory).Name -NewName "ungoogled-chromium"
        }
    } else {
 
        # 压缩包测试失败的文件就别捣乱了,删掉,下次执行更新的时候自然就重新下载了。
        Remove-Item -Path (Get-Item -Path ungoogled-chromium_*).Name
    }
    
}

转载还请指回我这里。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值