logo

ddadaal.me

使用PowerShell脚本让UWP应用使用localhost上的系统代理

2020-04-25 23:40:00 UTC+8
1420 字
8 分钟阅读

问题

众所周知,国内微软服务的连接性很成问题,并且这个问题越来越严重了,所以必须要让这些应用通过梯子才能正常使用微软服务。

梯子一般都会设置系统代理,其原理是在本机localhost的某个端口上监听网络请求,并将请求发送到服务器。绝大部分普通的Win32应用都会遵循系统代理的设置,包括OneDrive桌面应用等,所以这些以Win32应用形式存在的应用程序可以很简单的解决。

但是微软的很多应用,例如自带的Windows商店、邮件、照片等,都是UWP应用,而UWP应用禁止了将网络流量发送到本机(localhost),所以UWP应用是不能直接使用这种系统代理的。

手动解决方案

微软同样自带了一个工具CheckNetIsolation.exe(可以直接在powershell里运行),可以允许选定的UWP应用解除网络隔离,使用localhost的系统代理。

听起来问题解决了?

如果查看这个工具的帮助界面的话,会发现这个工具需要应用的名称(-n)或者ID(-p),但是这些信息需要从注册表中获取,非常的麻烦。想要这样进行操作的用户可以尝试少数派的这篇文章

➜ CheckNetIsolation.exe LoopbackExempt -?

用法:
   CheckNetIsolation LoopbackExempt [operation] [-n=] [-p=]
      操作列表:
          -a  -  向环回免除列表中添加 AppContainer 或程序包系列。
          -d  -  从环回免除列表中删除 AppContainer 或程序包系列。
          -c  -  清除环回免除的 AppContainer 和程序包系列的列表。
          -s  -  显示环回免除的 AppContainer 和程序包系列的列表。

      参数列表:
          -n= - AppContainer 名称或程序包系列名称。
          -p= - AppContainer 或程序包系列安全标识符(SID)。
          -?  - 显示 LoopbackExempt 模块的此帮助消息。

完成。

自动化方案

巨人的肩膀

我们作为一个合格的程序员,看到这种事情的第一反应,应该是:我太懒了,我们需要自动化!

所以第一件事就是去网上找,果不其然找到一个dalao的文章,里面给出了一个Python脚本,可以自动做这个事情。

但是反正这个工具都是在Windows上用,为什么要用Python?用PowerShell,什么依赖都不要,它不香嘛?

进入这个大佬的GitHub,可以在它的这个仓库中发现原来这个大佬也写了一份PowerShell脚本用来做这个事情。

但是当我尝试使用这个PowerShell时,发现了一些问题:

  • 没有系统自带的应用
  • 选择应用后会报错误: 参数无效错误

站在巨人的肩膀上

不能就这么放弃了!

于是我检查了一下这个PowerShell工具,解决了这两个问题:

  • 没有系统自带的应用是因为dalao过滤了以${开头的应用,而这些应用正好就是邮箱、商店等系统应用
  • 选择应用后报错应该是因为工具在后期改了API,所以原来直接使用Moniker键值的方法不能使用了

针对这两个问题,我对脚本做出了改进,并加入了一个根据名字进行筛选应用的功能,以方便让用户应用列表中中快速找到想要设置的应用。

改进后的脚本如下:

param(
    [string] $Contain
)
 
$BASE_PATH = 'HKCU:\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Mappings\'
# 获取相关注册表信息,并进行筛选和排序
$mapping = Get-ChildItem -Pat $BASE_PATH | Where-Object {$Contain -Eq "" -or $_.GetValue('DisplayName').Contains($Contain)} | Sort-Object {$_.GetValue('DisplayName')}
 
if ($mapping.Length -eq 0) {
    Write-Output "没有包含字符 $Contain 的软件包,请重试。"
    exit
}
# 格式化打印 APP List
$mapping | Format-Table @{label='Num'; expression={$mapping.IndexOf($_)}}, @{label='DisplayName'; expression={$_.GetValue('DisplayName')}}
$input = Read-Host '回复序号并回车提交(若只有一项,输入0),添加指定应用到排除列表中'
$id = $mapping[$input].Name.Split("\") | Select-Object -Last 1
Write-Output $id
CheckNetIsolation LoopbackExempt -a -p="$id"

将这段代码复制粘贴到本地一个以ps1为扩展名的文件中,假设这个文件名字为check.ps1

  • 使用PowerShell直接运行这个脚本,不需要管理员权限。系统将会列出系统中所有的UWP应用的名称,输入编号,系统将会输入应用的ID,然后调用CheckNetIsolation.exe工具将这个应用解除网络隔离,允许使用系统代理。
-> .\check.ps1

Num DisplayName
--- -----------
 ...
 54 @{microsoft.windowscommunicationsapps_16005.12624.20368.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommun…
 ...

回复序号并回车提交(若只有一项,输入0),添加指定应用到排除列表中: 54
S-1-15-2-...(剩下的ID)
完成。
  • 使用PowerShell运行这个脚本,并加入参数-Contain {字符串},工具将会筛选名称中含有这个字符串的应用。之后,和上面一样,输入编号回车即可。
-> .\check.ps1 -Contain communicationsapps

Num DisplayName
--- -----------
    @{microsoft.windowscommunicationsapps_16005.12624.20368.0_x64__8wekyb3d8bbwe?ms-resource://microsoft.windowscommun…

回复序号并回车提交(若只有一项,输入0),添加指定应用到排除列表中: 0
S-1-15-2-...(剩下的ID)
完成。

另外,这里给出可以用来筛选几个常见的需要进行代理的MS自带应用的筛选参数,方便大家直接复制运行(直接作为-Contain参数的值,运行脚本时输入0回车即可):

软件筛选参数
应用商店WindowsStore
邮件communicationsapps
OneNoteOneNote
照片Windows.Photos (注意不要选择后面有DLC的那一项)

运行完脚本之后,关闭重启对应应用即可。

终于可以愉快地使用MS应用和服务了!

最后非常感谢这份PowerShell脚本的原作者!

评论