使用以下代码尝试从受保护的 HTTP 源下载文件会返回 401 Unauthorized:
$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
名称 MemberType 定义
---- ---------- ---------- Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetNetworkCredential Method System.Net.NetworkCredential GetNetworkCredential() GetType 方法类型 GetType() ToString 方法字符串 ToString()
密码属性 System.Security.SecureString 密码 {get;}
是什么赋予了?