Mounting Registry Hive Functions

I have found myself needing fully featured functions for mounting and dismounting registry hives and accounting for all the variables that come with that. This is usually when needing to get information from mounting Windows Images. This way, you can get details like the Image Release ID (1709, 1803, 1809, etc) and more from your imagination

  Function Mount-RegistryHive
{
    [CmdletBinding(SupportsShouldProcess=$True)]
   
      Param
        (
            [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
            [ValidateNotNullOrEmpty()]
            [ValidateScript({(Test-Path -Path $_)})]
            [String]$Path,
            
            [Parameter(Mandatory=$False, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
            [ValidateNotNullOrEmpty()]
            [ValidateScript({($_ -ilike "HKU\*") -or ($_ -ilike "HKLM\*")})]
            [String]$MountPath,
            
            [Parameter(Mandatory=$False)]
            [Switch]$CopyHive
        )
                
    Begin
      {
          [String]$CmdletName = $MyInvocation.MyCommand.Name 
          Write-FunctionHeaderOrFooter -CmdletName "$($CmdletName)" -CmdletBoundParameters $PSBoundParameters -Header
          Write-Log -Message "Function `'$($CmdletName)`' is beginning. Please Wait..." -Severity 2 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
      }

    Process
      {                   
          Try
            {
                [System.IO.FileInfo]$PathProperties = $Path
            
                $RandomGUID = "$([System.GUID]::NewGuid().ToString().ToUpper())"
            
                If ($CopyHive.IsPresent -eq $True)
                  {
                      $HiveDestination = "$($EnvTemp.TrimEnd('\'))\$($RandomGUID)"
                      If (!(Test-Path -Path $HiveDestination)) {New-Folder -Path $HiveDestination -Verbose -ContinueOnError:$False}
                      Copy-File -Path "$($Path)" -Destination "$($HiveDestination)"
                      $Path = "$($HiveDestination)\$($PathProperties.Name)"
                      [System.IO.FileInfo]$PathProperties = $Path
                  }
            
                If ((!($PSBoundParameters.ContainsKey('MountPath'))) -and ([String]::IsNullOrEmpty($MountPath)))
                  {
                      $MountPath = "HKLM\$($RandomGUID)"
                  }
                  
                $LogMessage = "Mount Path: `'$($MountPath)`'"
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                
                $MountPathConverted = Convert-RegistryPath -Key "$($MountPath)"
                $LogMessage = "Mount Path Converted: `'$($MountPathConverted)`'"
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
            
                $LogMessage = "Attempting to mount registry hive `'$($PathProperties.FullName)`' into the following mount path `'$($MountPath)`'. Please Wait..."
                
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                
                $MountRegistryHive = Execute-Process -Path "reg.exe" -Parameters "Load `"$($MountPath)`" `"$($PathProperties.FullName)`"" -CreateNoWindow -PassThru
                                    
                If ($MountRegistryHive.ExitCode -iin @('0'))
                  {
                      $LogMessage = "Mounting of registry hive `'$($PathProperties.FullName)`' into the following mount path `'$($MountPath)`' was successful"
                      Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                  }
                Else
                  {
                      $ErrorMessage = "Failed to mount registry hive `'$($PathProperties.FullName)`' into the following mount path `'$($MountPath)`'"
                      Write-Log -Message $ErrorMessage -Severity 3 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                      Throw "$($ErrorMessage)"
                  }
                  
                $ResultantProperties = New-Object -TypeName 'PSObject'
                $ResultantProperties | Add-Member -Name "ParentPath" -Value "$($PathProperties.Directory)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "Path" -Value "$($PathProperties.FullName)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "FileName" -Value "$($PathProperties.Name)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "MountPath" -Value "$($MountPath)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "MountPathConverted" -Value "$($MountPathConverted)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "GUID" -Value "$($RandomGUID)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "ExitCode" -Value "$($MountRegistryHive.ExitCode)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "StdOut" -Value "$($MountRegistryHive.StdOut)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "StdErr" -Value "$($MountRegistryHive.StdErr)" -MemberType NoteProperty
            }
          Catch
            {
                $ErrorMessage = "$($_.Exception.Message)"
                Write-Log -Message $ErrorMessage -Severity 3 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True    
            }
            
          Write-Output -InputObject $ResultantProperties
      }
    
    End
      {                                        
            Write-Log -Message "Function `'$($CmdletName)`' is completed." -Severity 2 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True            
            Write-FunctionHeaderOrFooter -CmdletName "$($CmdletName)" -Footer
      }
}


Function Dismount-RegistryHive
{
    [CmdletBinding(SupportsShouldProcess=$True)]
   
      Param
        (        
            [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
            [ValidateNotNullOrEmpty()]
            [ValidateScript({($_ -ilike "HKU\*") -or ($_ -ilike "HKLM\*")})]
            [String]$MountPath,
            
            [Parameter(Mandatory=$False)]
            [Switch]$RemoveHive,
            
            [Parameter(Mandatory=$True, ValueFromPipeline=$True, ValueFromPipelineByPropertyName=$True)]
            [ValidateNotNullOrEmpty()]
            [ValidateScript({(Test-Path -Path $_)})]
            [String]$Path,
            
            [Parameter(Mandatory=$False)]
            [Switch]$Recurse
        )
                
    Begin
      {
          [String]$CmdletName = $MyInvocation.MyCommand.Name 
          Write-FunctionHeaderOrFooter -CmdletName "$($CmdletName)" -CmdletBoundParameters $PSBoundParameters -Header
          Write-Log -Message "Function `'$($CmdletName)`' is beginning. Please Wait..." -Severity 2 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
      }

    Process
      {           
          Try
            {  
                $LogMessage = "Mount Path: `'$($MountPath)`'"
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                
                $MountPathConverted = Convert-RegistryPath -Key "$($MountPath)"
                $LogMessage = "Mount Path Converted: `'$($MountPathConverted)`'"
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
            
                $LogMessage = "Attempting to dismount the associated registry hive from the following mount path `'$($MountPath)`'. Please Wait..." 
                Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                                                              
                [Void][GC]::Collect()
                
                [Void][GC]::WaitForPendingFinalizers()
                
                $DismountRegistryHive = Execute-Process -Path "reg.exe" -Parameters "Unload `"$($MountPath)`"" -CreateNoWindow -PassThru     
                
                If ($DismountRegistryHive.ExitCode -iin @('0'))
                  {
                      $LogMessage = "Dismounting of the associated registry hive from the following mount path `'$($MountPath)`' was successful"
                      Write-Log -Message $LogMessage -Severity 1 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                  }
                Else
                  {
                      $ErrorMessage = "Failed to dismount registry hive: $($DismountRegistryHive.StdErr)"
                      Write-Log -Message $ErrorMessage -Severity 3 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True
                      Throw ""
                  }
                  
                If ($RemoveHive.IsPresent -eq $True)
                  {
                      If ((!([String]::IsNullOrEmpty($Path))))
                        {
                            $PathProperties = Get-Item -Path $Path -Force
                        
                            If (($Recurse.IsPresent -eq $True) -and ($PathProperties.GetType().Name -ieq 'DirectoryInfo'))
                              {
                                  Remove-Folder -Path "$($PathProperties.FullName)" -Verbose -ContinueOnError:$False
                              }
                            ElseIf (($PathProperties.GetType().Name -ieq 'FileInfo'))
                              {
                                  Remove-File -Path "$($PathProperties.FullName)" -Verbose -ContinueOnError:$False
                              }      
                        }
                  }
                  
                $ResultantProperties = New-Object -TypeName 'PSObject'
                $ResultantProperties | Add-Member -Name "MountPath" -Value "$($MountPath)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "MountPathConverted" -Value "$($MountPathConverted)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "ExitCode" -Value "$($DismountRegistryHive.ExitCode)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "StdOut" -Value "$($DismountRegistryHive.StdOut)" -MemberType NoteProperty
                $ResultantProperties | Add-Member -Name "StdErr" -Value "$($DismountRegistryHive.StdErr)" -MemberType NoteProperty 
            }
          Catch
            {
                $ErrorMessage = "$($_.Exception.Message)"
                Write-Log -Message $ErrorMessage -Severity 3 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True 
            }
            
          Write-Output -InputObject $ResultantProperties
      }
    
    End
      {                                        
            Write-Log -Message "Function `'$($CmdletName)`' is completed." -Severity 2 -LogType CMTrace -Source "$($CmdletName)" -ContinueOnError:$True            
            Write-FunctionHeaderOrFooter -CmdletName "$($CmdletName)" -Footer
      }
}

$HivePath = “C:\Users\Default\NTUser.dat”
MountPathProperties = Mount-RegistryHive -Path "($HivePath)" -CopyHive

$RegistryKeyPath = “Microsoft\Windows NT\CurrentVersion”
$RegistryKeyValue = “ReleaseID”
[String]ReleaseID = Get-RegistryKey -Key "($MountPathProperties.MountPathConverted)$(RegistryKeyPath)" -Value "($RegistryKeyValue)" -DoNotExpandEnvironmentNames

Test = Dismount-RegistryHive -MountPath "(MountPathProperties.MountPath)" -RemoveHive -Path "($MountPathProperties.ParentPath)" -Recurse