none
Add/Edit Saved Password in Credential Manager (Windows 7)

    Question

  • Greetings!

    I have a network storage device that requires a login each time the user logs on to the computer. I have multiple users that I need to give access (working various shifts), but I don't want to share the login information with them in an effort to keep it more secure. Ideally, I would like a VBScript or command line option that will allow me to add the credentials to their credential manager vault. I would add this to our existing logon script.

    I have already tried "net use x: \\server\share /user:USERNAME PASSWORD /persistent" but it doesn't seem to produce consistent results with this device. I noticed that there is a /savecred parameter, but it can't be used in conjunction with the /user parameter.

    Is there any way to accomplish this?

    Thursday, January 06, 2011 8:58 PM

Answers

  • Sorry, beat you to it!  It looks like the code on pinvoke.net was a bit wrong.  I wound up porting the pinvoke sig and code found here.

    Here's the link to the pinvoke page for CredWrite - I've been toying with putting the PowerShell code up there for a while, but I always held back.  I think it's time we start adding our stuff there.  I've up'd the following code there.

    Here's the final code that works - well, I didn't test the credential so it's very possible that the password section may need more work.  Let us know if it works for you.

    $sig = @"
    [DllImport("Advapi32.dll", SetLastError=true, EntryPoint="CredWriteW", CharSet=CharSet.Unicode)]
    public static extern bool CredWrite([In] ref Credential userCredential, [In] UInt32 flags);
    
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct Credential
    {
       public UInt32 flags;
       public UInt32 type;
       public IntPtr targetName;
       public IntPtr comment;
       public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten;
       public UInt32 credentialBlobSize;
       public IntPtr credentialBlob;
       public UInt32 persist;
       public UInt32 attributeCount;
       public IntPtr Attributes;
       public IntPtr targetAlias;
       public IntPtr userName;
    }
    
    "@
    Add-Type -MemberDefinition $sig -Namespace "ADVAPI32" -Name 'Util'
    
    $cred = New-Object ADVAPI32.Util+Credential
    $cred.flags = 0
    $cred.type = 2
    $cred.targetName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('server2')
    $cred.userName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('home\tome')
    $cred.attributeCount = 0
    $cred.persist = 2
    $password = "password"
    $cred.credentialBlobSize = [System.Text.Encoding]::Unicode.GetBytes($password).length
    $cred.credentialBlob = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni($password)
    [ADVAPI32.Util]::CredWrite([ref]$cred,0)
    


    http://twitter.com/toenuff
    write-host ((0..56)|%{if (($_+1)%3 -eq 0){[char][int]("116111101110117102102064103109097105108046099111109"[($_-2)..$_] -join "")}}) -separator ""
    Friday, January 07, 2011 6:18 AM

All replies

  • When you say it doesn't produce consistent results, what do you mean?  I'm wondering if it already has a connection to the share or something.  You may want to try net use /delete \\server\share before running the one w/ the username and password.
    http://twitter.com/toenuff
    write-host ((0..56)|%{if (($_+1)%3 -eq 0){[char][int]("116111101110117102102064103109097105108046099111109"[($_-2)..$_] -join "")}}) -separator ""
    Thursday, January 06, 2011 9:08 PM
  • Yeah, it's really weird, but after a reboot it will essentially say that the account doesn't have access from this computer.

    When I try using a delete command first, followed by the net use without the persistent tag, you're right... it does seem to work more consistently that way. So that may be what I have to live with as a solution. I very much appreciate that! :)

    I would, however, still like to know if there's a command-line/scriptable way to add a credential to the credential manager vault.

    Thursday, January 06, 2011 9:20 PM
  • Well, the answer is to use advapi32.dll.  Here's a porting of the CredWrite function, but it doesn't yet work.  Looks like I'm goofing the strings used in the targetname and username, but it does add something to credential manager.  It's just a matter of struggling through it.  Unfortunately, I don't have any more time to look at this now, but I'll try to get back to it at some point:

     

    $sig = @"
    [DllImport("Advapi32.dll", SetLastError=true, EntryPoint="CredWriteW", CharSet=CharSet.Unicode)]
    public static extern bool CredWrite([In] Credential userCredential, [In] UInt32 flags);
    enum CRED_TYPE : uint
    {
       CRED_TYPE_GENERIC = 1,
       CRED_TYPE_DOMAIN_PASSWORD = 2,
       CRED_TYPE_DOMAIN_CERTIFICATE = 3,
       CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4
    }
    
    enum CRED_PERSIST : uint
    {
       CRED_PERSIST_SESSION = 1,
       CRED_PERSIST_LOCAL_MACHINE = 2,
       CRED_PERSIST_ENTERPRISE = 3
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct Credential
    {
       public UInt32 flags;
       public UInt32 type;
       public string targetName;
       public string comment;
       //public System.Runtime.InteropServices.FILETIME lastWritten; // .NET 1.1
       public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten; // .NET 2.0
       public UInt32 credentialBlobSize;
       public IntPtr credentialBlob;
       public UInt32 persist;
       public UInt32 attributeCount;
       public IntPtr credAttribute;
       public string targetAlias;
       public string userName;
    }
    "@
    $type = Add-Type -MemberDefinition $sig -Namespace "ADVAPI32" -Name 'Util' -PassThru
    
    $cred = New-Object ADVAPI32.Util+Credential
    $cred.targetName = "blah"
    $cred.type = 2
    $cred.userName = 'home\blah'
    $cred.attributeCount = 0
    $cred.persist = 1
    $password = 
    $cred.credentialBlobSize = [System.Text.Encoding]::Unicode.GetBytes("password").length
    $cred.credentialBlob = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni("password")
    [ADVAPI32.Util]::CredWrite($cred,0)
    


    http://twitter.com/toenuff
    write-host ((0..56)|%{if (($_+1)%3 -eq 0){[char][int]("116111101110117102102064103109097105108046099111109"[($_-2)..$_] -join "")}}) -separator ""
    Friday, January 07, 2011 12:13 AM
  • Awesome! I will take a closer look at it tomorrow and see if I can work it out. I'll post back here if I solve it before you get a chance to follow-up.

    Thank you very much for looking into it! :)

    Friday, January 07, 2011 12:27 AM
  • Sorry, beat you to it!  It looks like the code on pinvoke.net was a bit wrong.  I wound up porting the pinvoke sig and code found here.

    Here's the link to the pinvoke page for CredWrite - I've been toying with putting the PowerShell code up there for a while, but I always held back.  I think it's time we start adding our stuff there.  I've up'd the following code there.

    Here's the final code that works - well, I didn't test the credential so it's very possible that the password section may need more work.  Let us know if it works for you.

    $sig = @"
    [DllImport("Advapi32.dll", SetLastError=true, EntryPoint="CredWriteW", CharSet=CharSet.Unicode)]
    public static extern bool CredWrite([In] ref Credential userCredential, [In] UInt32 flags);
    
    [StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
    public struct Credential
    {
       public UInt32 flags;
       public UInt32 type;
       public IntPtr targetName;
       public IntPtr comment;
       public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten;
       public UInt32 credentialBlobSize;
       public IntPtr credentialBlob;
       public UInt32 persist;
       public UInt32 attributeCount;
       public IntPtr Attributes;
       public IntPtr targetAlias;
       public IntPtr userName;
    }
    
    "@
    Add-Type -MemberDefinition $sig -Namespace "ADVAPI32" -Name 'Util'
    
    $cred = New-Object ADVAPI32.Util+Credential
    $cred.flags = 0
    $cred.type = 2
    $cred.targetName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('server2')
    $cred.userName = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni('home\tome')
    $cred.attributeCount = 0
    $cred.persist = 2
    $password = "password"
    $cred.credentialBlobSize = [System.Text.Encoding]::Unicode.GetBytes($password).length
    $cred.credentialBlob = [System.Runtime.InteropServices.Marshal]::StringToCoTaskMemUni($password)
    [ADVAPI32.Util]::CredWrite([ref]$cred,0)
    


    http://twitter.com/toenuff
    write-host ((0..56)|%{if (($_+1)%3 -eq 0){[char][int]("116111101110117102102064103109097105108046099111109"[($_-2)..$_] -join "")}}) -separator ""
    Friday, January 07, 2011 6:18 AM
  • This did, indeed, work perfectly! Thank you very much! :)
    Thursday, January 13, 2011 7:49 PM
  • Hi, 

    Is there a possibility to use this script to add a certificate based credential ? 

    Thank you. 

    Thursday, January 17, 2013 3:13 AM
  • Hi,

    This question is already marked as answered. If you still need help, please start a new question.

    Bill

    Thursday, January 17, 2013 3:34 PM
    Moderator
  • Maybe you can use cmdkey (command line utility) to make a script:

    cmdkey /add:TERMSRV/myremoteServer.mydomain.com /user:myDomain\username /pass:zPa$$w0rd!

    This will store the credentials on control->panel->users->password vault and they will be used if you launch from an RDP file

    See also: http://technet.microsoft.com/en-us/library/ff393699(v=ws.10).aspx



    Wednesday, April 10, 2013 1:16 PM