【问题标题】:Powershell webclient trailing dot in URL bugURL错误中的Powershell webclient尾随点
【发布时间】:2013-12-29 09:36:11
【问题描述】:

所以,我有一个下载文件的 Powershell 脚本,例如

$mech = new-object System.Net.WebClient
$mech.DownloadFile('http://www.example.com/folder./index.html', 'out.html')
                      Note the trailing dot here ^

这不起作用(给出 404),查看发送的实际请求,结果发现尾随点被取出,这似乎源于此错误:https://connect.microsoft.com/VisualStudio/feedback/details/386695/

这似乎在 一些 版本的 .Net 中得到修复,但 Powershell 不使用这些版本(我在 Win7 中使用 PS2.0,它使用 .Net 2.0.50727.5472,也在 PS3 中尝试过.0 使用 .Net 4.0.30319.17929,两者都没有打补丁说明 .Net 4.5.something 已安装)

所以,这可能是一个简单的问题,但是,上面的链接中列出了一种解决方法,我将如何在 Powershell 中应用它?

或者,我如何让 Powershell 使用已修补的 .Net 版本(以及哪些版本已修补?)

我宁愿不使用 wget 等外部程序,否则我可能不会在 Powershell 中编写它,但是如果必须,它需要在 url 中支持 UTF8

另外,服务器对 .替换为 %2e

【问题讨论】:

  • Invoke-WebRequest(仅限 v3+)是否正常工作?
  • 不是刚刚在 Win8.1 机器上测试过(由于某种原因,我无法在 Win 7 上获得 PS4,安装了更新但它仍然是 V3...)并且也不起作用,我可能是错的,但所有涉及 URI 的命令行开关都由包含错误的 System.Uri 解析。

标签: .net powershell webclient


【解决方案1】:

采用低级方法并使用WinInetP/Invoke 怎么样? P/Invoke 的介绍在MSDN。不过,使用 .Net 类需要做更多的工作。

另一种选择是使用第三方工具包,如cURL。 Libcurl 有一个 .Net 包装器,因此在 Powershell 中使用它应该比 P/Invoke 方式更容易。

【讨论】:

  • 无法弄清楚 WinInet 的基础是什么,它是在 .Net 上编写的方式,谢谢,但这对我来说有点太深入了
  • @user3143516 WinInet 是本机非托管 Win32 代码。我相当确定它没有相同的错误,以免您遇到类似的行为,例如 IE。
【解决方案2】:

好吧,以防万一其他人需要一个解决方案,虽然我不能确切地说这是一个优雅的解决方案,但它仍然是一个。事实证明,您可以在 PS >=3.0

中将 C# 直接推入 PS
$source = @"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Net;


public class FixedWebClient
{
    public static System.Net.WebClient NewWebClient()
    {
        MethodInfo getSyntax = typeof(UriParser).GetMethod("GetSyntax", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
        FieldInfo flagsField = typeof(UriParser).GetField("m_Flags", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic);
        if (getSyntax != null && flagsField != null)
        {
            foreach (string scheme in new[] { "http", "https" })
            {
                UriParser parser = (UriParser)getSyntax.Invoke(null, new object[] { scheme });
                if (parser != null)
                {
                    int flagsValue = (int)flagsField.GetValue(parser);
                    // Clear the CanonicalizeAsFilePath attribute
                    if ((flagsValue & 0x1000000) != 0)
                        flagsField.SetValue(parser, flagsValue & ~0x1000000);
                }
            }
        }
        return new System.Net.WebClient();
    }
}
"@

#Remove-TypeData 'FixedWebClient'
Add-Type -TypeDefinition $source
$mech = [FixedWebClient]::NewWebClient()
$mech.DownloadFile('http://www.example.com/folder./index.html', 'out.html')

我不确定使用这种方法的效果范围是什么,所以我在其中创建了 WebClient 对象以防万一,如果在 PS/.Net 方面更有经验的人可以澄清一下,那就太好了(这是我的第一个 PS 脚本,我会使用 Perl,但由于我更像是一个 Windows 人,所以我想我不妨学习一些 PS)。

如果有人把它翻译成纯 PS 也很好,因为看看它是如何工作的会很有趣......

【讨论】:

  • 你也可以在 PS 2.0 中做到这一点。要获得更优雅的解决方案,请将 C# 编译为 DLL 并将其添加为类型。这是a sample。通过预编译 DLL,您可以确定它使用的是框架的预期版本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多