Once in awhile, you need to do brain surgery on files locked by the system. This is a common problem run into by patches and hotfixes, so Windows has a special mechanism that lets it move files before any process has the chance to get its grubby little hands on it. This can only be done during a reboot, leading to the dire warning given to you by many installers.
The Win32 API that enables this is MoveFileEx. Calling this API with the MOVEFILE_DELAY_UNTIL_REBOOT flag tells Windows to move (or delete) your file at the next boot.
Here’s how to do it from PowerShell:
| 001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 | function Move-LockedFile { param($path, $destination) $path = (Resolve-Path $path).Path $destination = $executionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath($destination) $MOVEFILE_DELAY_UNTIL_REBOOT = 0x00000004 $memberDefinition = @' [DllImport("kernel32.dll", SetLastError=true, CharSet=CharSet.Auto)] public static extern bool MoveFileEx(string lpExistingFileName, string lpNewFileName, int dwFlags); '@ $type = Add-Type -Name MoveFileUtils -MemberDefinition $memberDefinition -PassThru $type::MoveFileEx($path, $destination, $MOVEFILE_DELAY_UNTIL_REBOOT) } [C:\Windows\system32\config\txr] PS:181 > dir -force | % { Move-LockedFile $_.Name (Join-Path c:\temp\txr ($_.Name + ".Bak")) } [C:\Users\leeholm] PS:182 > dir -Filter "NTUser.DAT{*" -force | % { Move-LockedFile $_.Name (Join-Path c:\temp\txr ($_.Name + ".Bak")) } |