How to persist credentials in a remote Powershell session?

I have an Azure File Share and would like to use this from my Azure VMs - after persisting the credentials on the VMs with cmdkey and mounting with net use. This was tested by running these commands in a local Powershell session on Windows Server 2012 R2 .

But I need to add this step to an Azure deployment script. An Azure Powershell script runs from my laptop, connects to the Azure subscription and builds the VMs from scratch, using a lot of variables.

Figured out to use Invoke-Command to pass the variables from the Azure Powershell script to a remote Powershell session on the newly created VM.

$Session = New-PSSession -ConnectionUri $Uri -Credential $DomainCredential

$ScriptBlockContent = { 
Param ($Arg1,$Arg2,$Arg3)
cmdkey /add:$Arg1 /user:$Arg2 /pass:$Arg3}

Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList ($Share,$AccountName,$Key)

And the error:

PS C:\> Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent -ArgumentList ($Share,$AccountName,$Key)
CMDKEY: Credentials cannot be saved from this logon session.

Replaced with cmdkey /list to check the syntax, and there's no error.

PS C:\> Invoke-Command -Session $Session -ScriptBlock $ScriptBlockContent
Currently stored credentials:
* NONE *

Had a similar issue (and couldn't fix it) with the Windows Update PowerShell Module (Invoke-WUInstall), that runs just fine on a local Powershell session on the VM, but doesn't update when started via remote Powershell.

Any way to get around this one ?


Due to how Windows handles authentication it is not possible to use CMDKEY to set credentials via a remote PowerShell session, it has to be done interactively when using CMDKEY.

To quote Don Jones from a thread looking for an answer similar to yours:

That's a limitation of the Cmdkey command – not really a PowerShell thing. But it's related to the way Remotig handles credentials. The remote session doesn't actually get a credential, it gets a delegated ticket, so there's no token to actually save. That's all by design, and not something you can reconfigure.


You can use Sysinternal's PsExec.exe if you don't want to use the Scheduled Task. Normally, when you start a PowerShell session, it runs in the services process (you can confirm this by running query session command on the remote computer) instead of the local user which fails cmdkey.

To overcome this, we need to run cmdkey.exe in the local user's process which can be done by using PsExec.exe's -i flag which

Run the program so that it interacts with the desktop of the specified session on the remote system. If no session is specified the process runs in the console session.

Now, the challenge is to get the session id of the local user on the remote machine. I achieved this by running query session command which gives a list of sessions active on the machine. One of the possible solutions is -

$processId = Invoke-Command $session -ScriptBlock  {
param($user)
    $sessions = query session $user;
    return $sessions[1].split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)[2];

} -ArgumentList ($user)

Here $user contains the username of the local user on the remote computer.

Once you get the session id, you can simply execute

PsExec \\<computer_name> -u <local_user_name> -p <password> -h -i $processId cmdkey.exe /generic:testtt /user:userr /pass:pass

Note:

  1. There can be better ways to get the session id of a user on the remote machine.
  2. Right now, while running PsExec, I am again making a connection with the remote system which can be avoided (I haven't tested).
  3. The user running the command should have admin access on the remote machine.