Powershell System.Net.WebClient Authentication

14,936

You are probably using the System.Net.NetworkCredential from an earlier version of the .Net Framework. The constructor overload that accepts a SecureString was introduced in .Net 4.0. If you pass a SecureString to a constructor that accepts a string, powershell will convert the SecureString to a string, which renders that value of the string "System.Security.SecureString". You can test a few things:

  1. Call the constructor, then view it's password property to see what the value is. If my assumption is correct, it will be "System.Security.SecureString".

  2. See what version of the .Net Framework you are using:

    $PSVersionTable.CLRVersion

  3. Query the object to see what constructors it has:

    a. Copy and paste this function from Jeffrey Snover.

    b. Call the function:

    get-Constructor system.net.networkcredential

As you can see from the below output (I am using .net 2.0) - there is no overload that accepts a SecureString:

NetworkCredential(
)
NetworkCredential(
    String userName,
    String password,
)
NetworkCredential(
    String userName,
    String password,
    String domain,
)
Share:
14,936

Related videos on Youtube

Yevgeniy
Author by

Yevgeniy

Updated on September 14, 2022

Comments

  • Yevgeniy
    Yevgeniy over 1 year

    Using below code in attempt to download file from protected HTTP source returns a 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)
    

    So does skipping the step of writing the password file like so:

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

    However, skipping securestring creation works just fine:

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

    Above code does not return any other errors. I verified existence and apparent structural validity of the target password file when testing original code version at the top. The entire code is within single script, so convertto and convertfrom have identical environment during execution. I tried this in both x86 and 64bit powershell.

    In fact, I can even convert the secure string back to the correct basic string with and use it with 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)
    

    Thus, the problem must be with using SecureString with System.Net.NetworkCredential class, however http://msdn.microsoft.com/en-us/library/system.net.networkcredential.aspx, as well as some only examples i found indicate SecureString should work as second argument.

    While writing this post, I have in fact found a solution:

    $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)
    

    But not an explanation as to why SecureString type doesn't work, while PSCredential.Password does. Executing $creds|gm clearly indicates that $creds.Password is also in fact a SecureString:

    TypeName: System.Management.Automation.PSCredential

    Name MemberType Definition

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

    What gives?

    • Yevgeniy
      Yevgeniy over 11 years
      I guess $Creds.GetNetworkCredential().Password works because it returns a plain string. So why doesn't secure string work?
  • Yevgeniy
    Yevgeniy over 11 years
    Thanks for the answer! I am indeed running .NET2 in this environment.