· Uwe Janke
Commands / Move-sqmDatabaseFile

Move-sqmDatabaseFile

Maintenance sqmSQLTool v1.9.147+ · Move ✓ -WhatIf supported
Moves the files of a database (MDF, NDF, LDF) to another drive or directory and runs exactly the steps SQL Server requires for it. Pass just the database name to move all its files, -FileType Data or -FileType Log for one kind, or -LogicalFileName to move a single file.

Why this is not a wrapper around Move-DbaDbFile: that cmdlet refuses master, model, msdb and tempdb outright ("System database detected as input"), and tempdb is precisely the database you want to move when a drive runs out of space. It also has no write probe, no space check and no -WhatIf.

tempdb leaves its old files behind. SQL Server does not clean them up on restart; it creates new files at the new location and the old ones simply stay on the old drive. This function removes them, but only after the instance is back and the new path is confirmed.

The three flows

DatabaseSequenceFiles copied
User databaseSET OFFLINE → copy → ALTER DATABASE ... MODIFY FILE → SET ONLINEyes
tempdbMODIFY FILE → instance restart → remove old filesno, tempdb is recreated at startup
model / msdbMODIFY FILE → stop the engine → copy → start the engineyes
masterRefused. Its file paths live in the startup parameters -d/-l/-e, not in ALTER DATABASE. Use Set-DbaStartupParameter.

Parameters

ParameterTypeRequiredDefaultNotes
-SqlInstancestringOptional$env:COMPUTERNAMETarget SQL Server instance.
-SqlCredentialPSCredentialOptional, SQL authentication instead of the current Windows context.
-DatabasestringRequired, Name of the database whose files are moved, for example SalesDB or tempdb.
-FileDestinationstringRequired, Target directory, interpreted from the SQL Server's point of view, not from the machine running the command.
-LogFileDestinationstringOptional-FileDestinationSeparate target directory for log files, so data and log can go to different drives in one call.
-FileTypestringOptionalAllAll, Data (MDF/NDF) or Log (LDF). Ignored when -LogicalFileName is given.
-LogicalFileNamestring[]Optional, Logical names of individual files, for example tempdev or SalesDB_log. Moves just those instead of the whole database.
-CredentialPSCredentialOptional, Windows credential for the file operations and the service control on the target host. Only needed for a remote instance the current context cannot reach.
-KeepOldFilesswitchSwitch$falseLeave the files at the old location instead of removing them after a successful move.
-NoRestartswitchSwitch$falsetempdb only. Writes the new paths but does not restart, so the change takes effect at the next restart (Status PendingRestart) and the old files stay. Refused for model/msdb, where the instance would not come up again.
-SkipWriteProbeswitchSwitch$falseSkip the write probe in the target directory. Only sensible if creating a temporary database is unwanted for audit reasons.
-SkipSpaceCheckswitchSwitch$falseSkip the free-space check at the target.
-SpaceBufferPercentintOptional20Safety margin added to the required size in the space check.
-RestartTimeoutSecondsintOptional300How long to wait for the instance to answer again after a service action.
-ForceswitchSwitch$falseKills open connections when taking a user database offline, and overrides the Always On block.
-EnableExceptionswitchSwitch$falseThrow instead of returning a result row with Status Failed.
-WhatIf / -ConfirmswitchOptional, ShouldProcess with ConfirmImpact = 'High'. All prechecks still run under -WhatIf, so a dry run tells you whether the move would work.

What is checked before anything changes

CheckWhy it matters
Database stateMust be ONLINE or OFFLINE. Snapshots are refused, master is refused.
Always On membershipAn AG database cannot be taken offline; the files have to be moved replica by replica. Resolved through Get-sqmDatabaseAgMembership, which distinguishes "not a member" from "could not be determined" instead of silently treating both as safe. -Force overrides.
Target directory visibleTest-DbaPath asks the instance (xp_fileexist), not the calling machine. A missing directory is created, the ACL of the source directory is copied onto it, and the engine service account is granted full control explicitly, because a fresh folder only inherits the ACL of the drive root.
Write probeAn 8 MB database is created in the target directory and dropped again immediately. Only that proves the service account may create files there; a readable ACL or a visible path does not. For tempdb this is the decisive test: a tempdb path the service cannot write means the instance will not start after the restart. The failure looks like CREATE FILE encountered operating system error 5(Access is denied.).
Free spaceSum of the file sizes plus -SpaceBufferPercent against the free space at the target, via Get-DbaDiskSpace (which knows mount points), falling back to xp_fixeddrives.

If a check fails, nothing is changed at all. If the copy fails halfway through, every MODIFY FILE already issued is reverted and the database goes back online on its old paths. After a service action the SQL Server Agent is put back into the state it was in before, because Start-DbaService -Type Engine does not bring it along and a silently stopped agent is only noticed when the nightly backup fails to run.

Execution Flow

START dbatools installed? NO throw: dbatools not found YES Connect, resolve the host name local paths, or \\HOST\X$ when the instance is remote Database = master? YES Blocked startup parameters -d/-l/-e NO Prechecks, nothing has been changed yet State ONLINE/OFFLINE, no snapshot · AG member? (Get-sqmDatabaseAgMembership) Target dir visible to the INSTANCE (Test-DbaPath)? missing -> create, copy ACL, grant service account Write probe: CREATE an 8 MB database there, then DROP · free space vs size + buffer All prechecks passed? NO Aborted nothing was changed YES ShouldProcess? (ConfirmImpact: High) NO WhatIf the plan only, Status = WhatIfSkipped YES System database? (tempdb / model / msdb) NO YES User database SET OFFLINE (-Force kills sessions) Copy the file to the target Compare the byte size ALTER DATABASE ... MODIFY FILE Copy fails? revert MODIFY FILE, old paths SET ONLINE again tempdb / model / msdb ALTER DATABASE ... MODIFY FILE Service action tempdb: Restart-DbaService -Force model/msdb: stop, copy, start Wait for the instance to return restore the SQL Agent state Verify new path (Test-DbaPath) Remove the old files only where the new path is confirmed · -KeepOldFiles keeps them Return one object per step DONE

Result status

One object per step, each carrying SqlInstance, Database, Step (Precheck, Move, Restart, Cleanup), LogicalName, OldPath, NewPath, SizeMB, Status and Message.

StatusMeaning
SuccessThe step completed.
AlreadyInPlaceThe file already sits in the target directory. Nothing was done for it.
BlockedRefused before any change: master, a snapshot, an AG database without -Force, -NoRestart for model/msdb, or an unanswerable Always On question.
AbortedA precheck failed. Nothing was changed.
FailedThe step failed. The message names the reason.
RolledBackA MODIFY FILE that had already been issued was set back to the old path after a later file failed.
PendingRestarttempdb with -NoRestart: the paths are written, the change takes effect at the next restart, the old files were left in place.
NotFoundThe database, or a name given via -LogicalFileName, does not exist.
WarningWorth knowing but not blocking, for example a failover cluster instance or free space that could not be determined.
SkippedA check was switched off, or the old files were kept via -KeepOldFiles.
WhatIfSkipped-WhatIf: this is what would have happened.

Examples

Move tempdb to its own drive, restart, clean up the leftovers
Move-sqmDatabaseFile -SqlInstance "SQL01" -Database "tempdb" -FileDestination "G:\MSSQL\TempDB"
Dry run first: all prechecks run, nothing is changed
Move-sqmDatabaseFile -SqlInstance "SQL01" -Database "tempdb" -FileDestination "G:\MSSQL\TempDB" -WhatIf |
    Format-Table Step, LogicalName, NewPath, Status, Message -Wrap
Move only the log file of one user database
Move-sqmDatabaseFile -SqlInstance "SQL01" -Database "SalesDB" `
    -LogicalFileName "SalesDB_log" -FileDestination "H:\MSSQL\Log"
Split data and log onto separate drives, killing open sessions
Move-sqmDatabaseFile -SqlInstance "SQL01" -Database "SalesDB" `
    -FileDestination "G:\MSSQL\Data" -LogFileDestination "H:\MSSQL\Log" -Force
Write the paths now, restart in the next maintenance window
Move-sqmDatabaseFile -SqlInstance "SQL01" -Database "tempdb" `
    -FileDestination "G:\MSSQL\TempDB" -NoRestart -Confirm:$false
Remote instance, separate Windows credential for files and service
$win = Get-Credential
Move-sqmDatabaseFile -SqlInstance "SQL01\INST01" -Database "tempdb" `
    -FileDestination "G:\MSSQL\TempDB" -Credential $win