Mapping a Storage Box as a Windows Network Drive (and Why Windows "Forgets" the Password)
Map an SMB storage box as a persistent Windows drive with PowerShell, and fix the MicrosoftAccount\ prefix that makes Windows lose the saved password.
I keep a few cloud storage boxes mounted as plain drive letters on my Windows machine. One holds scanned receipts, one is the company document archive, one is general dumping ground. Mapping them is a one-liner. Keeping them mapped after a reboot, without Windows popping up a password prompt every morning, took me way longer than it should have.
The short version: Windows was saving the wrong user name for the drive. Not my storage box user. A MicrosoftAccount\... user that the storage box has never heard of. So every reconnect failed, and it looked like Windows had "forgotten" the password.
TL;DR: Map the share with New-SmbMapping -Persistent, store the password yourself in Credential Manager via CredWrite (not cmdkey, which can break special characters), then blank the UserName value under HKCU:\Network\<Letter>. With no user name stored on the mapping, Windows falls back to the saved credential for that host, and the drive reconnects cleanly after reboot.
The script
This is a cleaned-up version of what I actually use. Example account u123456, example drive F:. The host name pattern is the one Hetzner-style storage boxes use; swap it for whatever your provider gives you.
# Map-StorageBox.ps1 -Account u123456 -Letter F
param(
[Parameter(Mandatory)] [string] $Account,
[Parameter(Mandatory)] [string] $Letter
)
$Letter = $Letter.TrimEnd(':').ToUpper()
$hostName = "$Account.your-storagebox.de"
$share = "\\$hostName\$Account"
Add-Type -TypeDefinition @'
using System;
using System.Runtime.InteropServices;
public static class WinCred {
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
struct CREDENTIAL {
public int Flags; public int Type; public string TargetName; public string Comment;
public long LastWritten; public int CredentialBlobSize; public IntPtr CredentialBlob;
public int Persist; public int AttributeCount; public IntPtr Attributes;
public string TargetAlias; public string UserName;
}
[DllImport("advapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool CredWrite(ref CREDENTIAL c, int flags);
// Type 2 = domain password (what cmdkey /add creates), Persist 3 = enterprise (survives reboot)
public static void Save(string target, string user, string pw) {
var c = new CREDENTIAL { Type = 2, TargetName = target, UserName = user, Persist = 3,
CredentialBlobSize = pw.Length * 2, CredentialBlob = Marshal.StringToCoTaskMemUni(pw) };
try { if (!CredWrite(ref c, 0)) throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); }
finally { Marshal.FreeCoTaskMem(c.CredentialBlob); }
}
}
'@
$sec = Read-Host "Password for $Account" -AsSecureString
$pw = [Runtime.InteropServices.Marshal]::PtrToStringAuto(
[Runtime.InteropServices.Marshal]::SecureStringToBSTR($sec))
# remove old mapping + old stored credential
Get-SmbMapping -LocalPath "${Letter}:" -ErrorAction SilentlyContinue |
Remove-SmbMapping -Force -UpdateProfile -ErrorAction SilentlyContinue
cmdkey /delete:$hostName 2>&1 | Out-Null
New-SmbMapping -LocalPath "${Letter}:" -RemotePath $share `
-UserName $Account -Password $pw -Persistent $true -ErrorAction Stop | Out-Null
[WinCred]::Save($hostName, $Account, $pw)
# the actual fix: no user name on the mapping -> Windows uses Credential Manager
Set-ItemProperty "HKCU:\Network\$Letter" -Name UserName -Value '' -ErrorAction SilentlyContinue
$pw = $null
Write-Host "OK: ${Letter}: -> $share"
Run it from a normal (non-elevated) PowerShell:
powershell -ExecutionPolicy Bypass -File .\Map-StorageBox.ps1 -Account u123456 -Letter F
It asks for the password as a SecureString, so nothing ends up in your shell history. Reboot, open Explorer, the drive is just there.
One prerequisite that's easy to miss: on most storage box products SMB/Samba is a per-account toggle in the provider's console. If it's off, you get "network path not found" and you'll waste time on credentials that were fine all along.
What actually goes on with persistent drives
When you map a drive persistently, Windows writes it to the registry under HKCU:\Network\<Letter>. Have a look:
Get-ItemProperty HKCU:\Network\F | Select-Object RemotePath, UserName, ProviderName
At logon Windows walks those keys and reconnects each one. If UserName is set, it tries to authenticate as that user. If it's empty, it looks for a stored credential matching the target host in Credential Manager and uses that.
That second path is what you want for a storage box. The credential lives in one place, Credential Manager, and the mapping only stores where to connect.
Gotcha: the MicrosoftAccount\ prefix
My machine is signed in with a Microsoft account, not a local account. And on that machine, after mapping the drive, the UserName value in HKCU:\Network\<Letter> wasn't the storage box user. It was MicrosoftAccount\<something>.
The storage box has no idea who that is. So at every logon, Windows tried to reconnect as a user that doesn't exist on the other end, the server said no, and Windows showed the drive with the red X and asked for credentials. From the outside it looked exactly like "Windows forgot my password". The password was fine. The user name was garbage.
The fix is the last line of the script: blank the UserName value. With no user on the mapping, Windows grabs the credential for u123456.your-storagebox.de from Credential Manager, which has the right user and the right password.
If you've already got a broken drive and don't want to re-run anything:
Set-ItemProperty HKCU:\Network\F -Name UserName -Value ''
cmdkey /list | Select-String your-storagebox
If the second command shows an entry for your host, you're done after the next logon. If it shows nothing, you need to store the credential first (see the next gotcha for how not to do that).
Gotcha: cmdkey and net use mangle special characters
The obvious approach is cmdkey /add:host /user:u123456 /pass:... or net use F: \\host\share password /user:u123456. Both go through cmd parsing. With a properly random password full of ^, %, &, " and friends, the password that arrives isn't the one you typed. Symptom: net keeps asking for the user name in a loop, or the login just fails.
What does work is letting net prompt for the password itself:
net use F: \\u123456.your-storagebox.de\u123456 /user:u123456 * /persistent:yes
The * makes net ask interactively, so no shell ever sees the password. That's fine for a one-off. For a script I wanted no prompt from net and no parsing at all, which is why the script calls CredWrite from advapi32.dll directly. The password goes from a SecureString into a UTF-16 buffer and into Credential Manager, untouched by any shell.
Type = 2 is a domain password credential, the same kind cmdkey /add creates and the kind the SMB client looks up. Persist = 3 (enterprise) keeps it across reboots.
Gotcha: New-SmbMapping -SaveCredentials
New-SmbMapping has a -SaveCredentials switch, and it sounds like exactly the thing. On my machine it failed with "The parameter is incorrect", with or without -Credential next to it. I didn't dig further; storing the credential separately with CredWrite is more predictable anyway, and you can see exactly what got saved in Credential Manager.
Gotcha: the drive is mapped but Explorer doesn't show it
Drive mappings are per logon session. If you map from an elevated PowerShell, from a scheduled task, or from some automation shell running in the background, the mapping exists in that session, and your normal Explorer session doesn't see it.
The credential, however, is stored for your user. So the clean way out is to run, in a normal non-admin terminal:
net use F: \\u123456.your-storagebox.de\u123456 /persistent:yes
No password needed, it's already in Credential Manager. Explorer picks it up immediately.
Reading the error messages
These two look similar and mean very different things:
| Message | Meaning |
|---|---|
| "The specified network password is not correct" | Login failed. Wrong password (or wrong user, see the MicrosoftAccount\ gotcha). |
| "Access is denied" / System error 5 | Login worked, but the share refused you. Path, share name or permissions on the server side. |
| "The network path was not found" | Wrong host, or SMB not enabled for that account. |
I have one sub-account that returns system error 5 every single time, even after recreating it, while the main account on the same box works. I never figured out why. If you hit error 5, don't keep resetting the password; the password is probably not the problem.
SFTP vs SMB
Storage boxes usually speak SFTP, SCP, rsync over SSH and SMB. Windows can only map SMB natively as a drive letter. For SFTP you need a third-party tool (SSHFS-Win, rclone mount, and so on). For automation on Linux I use SFTP with SSH keys; for clicking around in Explorer, SMB is the path of least resistance.
Do keep in mind what SMB over the internet means: this is SMB3 to a provider's endpoint, not your LAN. Make sure you're not running ancient SMB on the client side; disabling SMBv1 and friends is worth doing on any Windows box that talks SMB to the outside.
FAQ
Do I need admin rights? No. Everything here is per user: HKCU:\Network, Credential Manager, the mapping. Running it elevated actually makes things worse (see the session gotcha).
Where can I see the stored credential? Control Panel → Credential Manager → Windows Credentials, or cmdkey /list. You'll see the host name and user, never the password.
What happens when I change the storage box password? Just re-run the script. It deletes the old mapping and credential first.
Is this safe? As safe as any saved Windows credential, i.e. anyone logged in as you can use the drive. That's the point of a mapped drive. Don't do this on a shared machine.
If you're scripting more Windows chores like this, my PowerShell sysadmin cheatsheet has the basics, and Task Scheduler with PowerShell covers running things at logon. One of these drives is where my receipt-sorting automation drops its output, and for real off-site backups rather than a mapped drive, look at restic to S3.