Powershell/Private/RegistryKey/Set-RegistryExe.ps1

function Set-RegistryExe {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateSet("Unload", "Load")]
        [System.String]$op,

        [ValidateSet("classes", "root")]
        [System.String]$hive,

        [Parameter(Mandatory = $true)]
        [ValidateScript( { Test-Path $_ })]
        [System.String]$ProfilePath,

        # User Security Identifier
        [Parameter(Mandatory = $true)]
        [ValidatePattern("^S-\d-\d+-(\d+-){1,14}\d+$")]
        [System.String]$UserSid
    )
    begin {
        # Ensure the RestartManager C# class is loaded into the session for file lock detection
        if (-not ("RestartManager" -as [type])) {
            $csharpCode = @"
            using System;
            using System.Runtime.InteropServices;
 
            public class RestartManager
            {
                [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
                private static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey);
 
                [DllImport("rstrtmgr.dll")]
                private static extern int RmEndSession(uint pSessionHandle);
 
                [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)]
                private static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, IntPtr rgApplications, uint nServices, IntPtr rgsServiceNames);
 
                [DllImport("rstrtmgr.dll")]
                private static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, out uint lpdwRebootReasons);
 
                [StructLayout(LayoutKind.Sequential)]
                private struct RM_UNIQUE_PROCESS
                {
                    public int dwProcessId;
                    public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime;
                }
 
                [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
                private struct RM_PROCESS_INFO
                {
                    public RM_UNIQUE_PROCESS Process;
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                    public string strAppName;
                    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)]
                    public string strServiceShortName;
                    public int ApplicationType;
                    public int AppStatus;
                    public uint TSSessionId;
                    [MarshalAs(UnmanagedType.Bool)]
                    public bool bRestartable;
                }
 
                public static int[] GetLockingProcessIds(string filePath)
                {
                    uint handle;
                    string key = Guid.NewGuid().ToString();
 
                    if (RmStartSession(out handle, 0, key) != 0) return new int[0];
 
                    try
                    {
                        string[] resources = new string[] { filePath };
                        if (RmRegisterResources(handle, (uint)resources.Length, resources, 0, IntPtr.Zero, 0, IntPtr.Zero) != 0) return new int[0];
 
                        uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = 0;
                        int res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, out lpdwRebootReasons);
 
                        if (res == 234)
                        {
                            RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                            pnProcInfo = pnProcInfoNeeded;
                            res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, out lpdwRebootReasons);
 
                            if (res == 0)
                            {
                                int[] pids = new int[pnProcInfo];
                                for (int i = 0; i < pnProcInfo; i++)
                                {
                                    pids[i] = processInfo[i].Process.dwProcessId;
                                }
                                return pids;
                            }
                        }
                    }
                    finally
                    {
                        RmEndSession(handle);
                    }
                    return new int[0];
                }
            }
"@

            Add-Type -TypeDefinition $csharpCode -Language CSharp
        }

        switch ($hive) {
            "classes" {
                $key = "HKU\$($UserSid)_Classes_admu"
                $hiveFile = "$ProfilePath\AppData\Local\Microsoft\Windows\UsrClass.dat.bak"
            }
            "root" {
                $key = "HKU\$($UserSid)_admu"
                $hiveFile = "$ProfilePath\NTUSER.DAT.BAK"
            }
        }
    }
    process {
        switch ($op) {
            "Load" {
                Write-ToLog "REG LOAD $key $hiveFile" -Level Verbose -Step "Set-RegistryExe"
                $results = REG LOAD $key $hiveFile *>&1
            }
            "Unload" {
                Write-ToLog "REG UNLOAD $key" -Level Verbose -Step "Set-RegistryExe"
                $results = REG UNLOAD $key *>&1
            }
        }

        $status = Get-RegistryExeStatus $results

        # If the REG command failed, check for file locks and log them
        if (-not $status) {
            Write-ToLog "REG $op failed. Checking for file locks on $hiveFile..." -Level Warning -Step "Set-RegistryExe"

            # Check if the file actually exists before asking RestartManager to scan it
            if (Test-Path $hiveFile -PathType Leaf) {
                $lockingPids = [RestartManager]::GetLockingProcessIds($hiveFile)

                if ($null -ne $lockingPids -and $lockingPids.Count -gt 0) {
                    $processDetails = foreach ($lockPid in $lockingPids) {
                        $proc = Get-Process -Id $lockPid -ErrorAction SilentlyContinue
                        if ($proc) {
                            "$($proc.ProcessName) (PID $lockPid)"
                        } else {
                            "UnknownProcess (PID $lockPid)"
                        }
                    }
                    Write-ToLog "Lock detected! $hiveFile is currently held by: $($processDetails -join ', ')" -Level Warning -Step "Set-RegistryExe"
                } else {
                    Write-ToLog "No active file locks found by RestartManager. The file may be physically corrupt, or locked by the System Kernel." -Level Warning -Step "Set-RegistryExe"
                }
            } else {
                Write-ToLog "Cannot check for locks because the file $hiveFile does not exist." -Level Warning -Step "Set-RegistryExe"
            }
        }
    }
    end {
        return $status
    }
}