PowerShell System.Net.WebClient 身份验证

3

尝试使用以下代码从受保护的HTTP源下载文件会返回401未经授权:

$pfile = "\\some\local\leaf\path"
$user = "MyUserName"

$pwdIn = read-host -assecurestring | convertfrom-securestring | out-file $pfile
$pwdOut = get-content $pFile| convertto-securestring

$url="http://path.to/file"
$file = "\\localpath\to\file"
$webclient = new-object System.Net.WebClient
$webclient.Credentials = new-object System.Net.NetworkCredential($user, $pwdOut)
$webclient.DownloadFile($url,$file)

那么,跳过编写密码文件的步骤会怎样呢?
$pwd = read-host -assecurestring 
...
$webclient.Credentials = new-object System.Net.NetworkCredential($user, $pwd)

然而,跳过安全字符串的创建也可以正常工作:

 $pwd = read-host
 ...
 $webclient.Credentials = new-object System.Net.NetworkCredential($user, $pwd)

上述代码没有返回任何其他错误。在测试原始代码版本时,我验证了目标密码文件的存在和明显的结构有效性。整个代码都在单个脚本中,因此在执行期间convertto和convertfrom具有相同的环境。我在x86和64位powershell中尝试过这种方法。
事实上,我甚至可以将安全字符串转换回正确的基本字符串,并使用WebClient。
$pwdtmp = get-content $pFile| convertto-securestring
$pwdOut = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($pwdtmp))
$webclient.Credentials = new-object System.Net.NetworkCredential($user, $pwdOut)

因此,问题必须在使用SecureString与System.Net.NetworkCredential类上,然而http://msdn.microsoft.com/en-us/library/system.net.networkcredential.aspx,以及我发现的一些示例表明SecureString应该作为第二个参数工作。
在撰写本文时,事实上我已经找到了解决方案:
$user = "user"
$pwd = read-host -assecurestring
$creds = New-Object System.Management.Automation.PSCredential `
     -ArgumentList $user, $pwd  
$webclient.Credentials = new-object System.Net.NetworkCredential($user, $Creds.GetNetworkCredential().Password)
$webclient.DownloadFile($url,$file)

但是没有解释为什么SecureString类型不起作用,而PSCredential.Password可以。执行$creds|gm清楚地表明$creds.Password实际上也是SecureString:

类型名称:System.Management.Automation.PSCredential

名称 成员类型 定义

---- ---------- ---------- Equals 方法 bool Equals(System.Object obj)
GetHashCode 方法 int GetHashCode()
GetNetworkCredential 方法 System.Net.NetworkCredential GetNetworkCredential() GetType 方法 type GetType() ToString 方法 string ToString()
Password 属性 System.Security.SecureString Password {get;}

这是怎么回事?


1
我猜 $Creds.GetNetworkCredential().Password 起作用是因为它返回的是一个明文字符串。那么为什么安全字符串不起作用呢? - Yevgeniy
1个回答

7
您可能正在使用早期版本的.NET Framework中的System.Net.NetworkCredential。接受SecureString的构造函数重载是在.NET 4.0中引入的。如果将SecureString传递给接受字符串的构造函数,PowerShell会将SecureString转换为字符串,这将使该字符串的值为"System.Security.SecureString"。您可以测试一些东西:
1. 调用构造函数,然后查看其密码属性以查看值是什么。如果我的假设是正确的,它将是"System.Security.SecureString"。 2. 查看您正在使用的.NET Framework的版本: $PSVersionTable.CLRVersion 3. 查询对象以查看它有哪些构造函数: a. 从Jeffrey Snover复制并粘贴此链接:function。 b. 调用该函数: get-Constructor system.net.networkcredential
如您从下面的输出中所见(我正在使用.NET 2.0)-没有接受SecureString的重载。
NetworkCredential(
)
NetworkCredential(
    String userName,
    String password,
)
NetworkCredential(
    String userName,
    String password,
    String domain,
)

谢谢你的回答!我确实在这个环境中运行.NET2。 - Yevgeniy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接