## Microsoft Function Naming Convention: http://msdn.microsoft.com/en-us/library/ms714428(v=vs.85).aspx #region Function Invoke-RegistryHiveAction Function Invoke-RegistryHiveAction { <# .SYNOPSIS A brief overview of what your function does .DESCRIPTION Slightly more detailed description of what your function does .PARAMETER HivePath A valid file path to a valid registry hive. .PARAMETER KeyPath One or more registry key paths that are relative to the specified registry hive. .PARAMETER ValueNameExpression One or more regular expressions that will determine which registry value names will be extracted from the specified registry hive. .EXAMPLE Invoke-RegistryHiveAction -HivePath "$($Env:Userprofile)\Downloads\RegistryHives\SOFTWARE" -KeyPath @('Root\Microsoft\Windows NT\CurrentVersion') -ValueNameExpression @('.*') -Verbose .EXAMPLE $InvokeRegistryHiveActionParameters = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $InvokeRegistryHiveActionParameters.HivePath = "$($Env:Userprofile)\Downloads\RegistryHives\SOFTWARE" $InvokeRegistryHiveActionParameters.KeyPath = New-Object -TypeName 'System.Collections.Generic.List[String]' $InvokeRegistryHiveActionParameters.KeyPath.Add('Root\Microsoft\Windows NT\CurrentVersion') $InvokeRegistryHiveActionParameters.ValueNameExpression = New-Object -TypeName 'System.Collections.Generic.List[Regex]' $InvokeRegistryHiveActionParameters.ValueNameExpression.Add('.*') $InvokeRegistryHiveActionParameters.ContinueOnError = $False $InvokeRegistryHiveActionParameters.Verbose = $True $InvokeRegistryHiveActionResult = Invoke-RegistryHiveAction @InvokeRegistryHiveActionParameters Write-Output -InputObject ($InvokeRegistryHiveActionResult) .NOTES Please ensure that the specified registry hive is not in use! .LINK https://github.com/EricZimmerman/Registry #> [CmdletBinding()] Param ( [Parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [ValidateScript({(Test-Path -Path $_)})] [System.IO.FileInfo]$HivePath, [Parameter(Mandatory=$True)] [ValidateNotNullOrEmpty()] [ValidatePattern('^Root\\.+')] [String[]]$KeyPath, [Parameter(Mandatory=$False)] [Regex[]]$ValueNameExpression, [Parameter(Mandatory=$False)] [Switch]$ContinueOnError ) Begin { Try { $DateTimeLogFormat = 'dddd, MMMM dd, yyyy @ hh:mm:ss.FFF tt' ###Monday, January 01, 2019 @ 10:15:34.000 AM### [ScriptBlock]$GetCurrentDateTimeLogFormat = {(Get-Date).ToString($DateTimeLogFormat)} $DateTimeMessageFormat = 'MM/dd/yyyy HH:mm:ss.FFF' ###03/23/2022 11:12:48.347### [ScriptBlock]$GetCurrentDateTimeMessageFormat = {(Get-Date).ToString($DateTimeMessageFormat)} $DateFileFormat = 'yyyyMMdd' ###20190403### [ScriptBlock]$GetCurrentDateFileFormat = {(Get-Date).ToString($DateFileFormat)} $DateTimeFileFormat = 'yyyyMMdd_HHmmss' ###20190403_115354### [ScriptBlock]$GetCurrentDateTimeFileFormat = {(Get-Date).ToString($DateTimeFileFormat)} $TextInfo = (Get-Culture).TextInfo $LoggingDetails = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $LoggingDetails.Add('LogMessage', $Null) $LoggingDetails.Add('WarningMessage', $Null) $LoggingDetails.Add('ErrorMessage', $Null) $CommonParameterList = New-Object -TypeName 'System.Collections.Generic.List[String]' $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::CommonParameters) $CommonParameterList.AddRange([System.Management.Automation.PSCmdlet]::OptionalCommonParameters) [System.IO.DirectoryInfo]$System32Directory = [System.Environment]::SystemDirectory $RegexOptionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.RegexOptions]' $RegexOptionList.Add([System.Text.RegularExpressions.RegexOptions]::IgnoreCase) $ValueNameExpressionList = New-Object -TypeName 'System.Collections.Generic.List[System.Text.RegularExpressions.Regex]' [ScriptBlock]$ErrorHandlingDefinition = { $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $ErrorMessageList.Add('Message', $_.Exception.Message) $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID) $ErrorMessageList.Add('Script', $_.InvocationInfo.ScriptName) $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber) $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine) $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim()) ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator()) { $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)" Write-Warning -Message ($LoggingDetails.ErrorMessage) } Switch (($ContinueOnError.IsPresent -eq $False) -or ($ContinueOnError -eq $False)) { {($_ -eq $True)} { Throw } } } #Determine the date and time we executed the function $FunctionStartTime = (Get-Date) [String]$FunctionName = $MyInvocation.MyCommand [System.IO.FileInfo]$InvokingScriptPath = $MyInvocation.PSCommandPath [System.IO.DirectoryInfo]$InvokingScriptDirectory = $InvokingScriptPath.Directory.FullName [System.IO.FileInfo]$FunctionPath = "$($InvokingScriptDirectory.FullName)\Functions\$($FunctionName).ps1" [System.IO.DirectoryInfo]$FunctionDirectory = "$($FunctionPath.Directory.FullName)" $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is beginning. Please Wait..." Write-Verbose -Message ($LoggingDetails.LogMessage) #Define Default Action Preferences $ErrorActionPreference = 'Stop' [String[]]$AvailableScriptParameters = (Get-Command -Name ($FunctionName)).Parameters.GetEnumerator() | Where-Object {($_.Value.Name -inotin $CommonParameterList)} | ForEach-Object {"-$($_.Value.Name):$($_.Value.ParameterType.Name)"} $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Available Function Parameter(s) = $($AvailableScriptParameters -Join ', ')" Write-Verbose -Message ($LoggingDetails.LogMessage) [String[]]$SuppliedScriptParameters = $PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key):$($_.Value.GetType().Name)"} $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Supplied Function Parameter(s) = $($SuppliedScriptParameters -Join ', ')" Write-Verbose -Message ($LoggingDetails.LogMessage) $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) began on $($FunctionStartTime.ToString($DateTimeLogFormat))" Write-Verbose -Message ($LoggingDetails.LogMessage) #region Load any required libraries [System.IO.DirectoryInfo]$LibariesDirectory = "$($FunctionDirectory.FullName)\Libraries" Switch ([System.IO.Directory]::Exists($LibariesDirectory.FullName)) { {($_ -eq $True)} { $LibraryPatternList = New-Object -TypeName 'System.Collections.Generic.List[String]' $LibraryPatternList.Add('NFluent.dll') $LibraryPatternList.Add('NLog.dll') $LibraryPatternList.Add('Registry.dll') Switch ($LibraryPatternList.Count -gt 0) { {($_ -eq $True)} { $LibraryList = Get-ChildItem -Path ($LibariesDirectory.FullName) -Include ($LibraryPatternList.ToArray()) -Recurse -Force | Where-Object {($_ -is [System.IO.FileInfo])} $LibraryListCount = ($LibraryList | Measure-Object).Count Switch ($LibraryListCount -gt 0) { {($_ -eq $True)} { For ($LibraryListIndex = 0; $LibraryListIndex -lt $LibraryListCount; $LibraryListIndex++) { $Library = $LibraryList[$LibraryListIndex] [Byte[]]$LibraryBytes = [System.IO.File]::ReadAllBytes($Library.FullName) $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load assembly `"$($Library.FullName)`". Please Wait..." Write-Verbose -Message ($LoggingDetails.LogMessage) $Null = [System.Reflection.Assembly]::Load($LibraryBytes) } } } } } } } #endregion #Create an object that will contain the functions output. $OutputObjectList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' #Set default parameter values Switch ($True) { {($Null -ieq $ValueNameExpression) -or ($ValueNameExpression.Count -eq 0)} { $ValueNameExpression += '.*' } {($Null -ine $ValueNameExpression) -or ($ValueNameExpression.Count -gt 0)} { $ValueNameExpression | ForEach-Object {$ValueNameExpressionList.Add((New-Object -TypeName 'System.Text.RegularExpressions.Regex' -ArgumentList @($_, $RegexOptionList)))} } } } Catch { $ErrorHandlingDefinition.Invoke() } Finally { } } Process { Try { $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to load registry hive `"$($HivePath.FullName)`" on demand. Please Wait..." Write-Verbose -Message ($LoggingDetails.LogMessage) $RegistryHive = New-Object -TypeName 'Registry.RegistryHiveOnDemand' -ArgumentList ($HivePath.FullName) ForEach ($Key In $KeyPath) { Try { $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the details of registry key path `"$($Key)`". Please Wait..." Write-Verbose -Message ($LoggingDetails.LogMessage) $RegistryKeyProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $RegistryKeyProperties.Path = $Key $RegistryKeyProperties.ValueList = New-Object -TypeName 'System.Collections.Generic.List[PSObject]' $RegistryKey = $RegistryHive.GetKey($Key) ForEach ($Item In $RegistryKey.Values) { ForEach ($Expression In $ValueNameExpressionList) { $ExpressionEvaluation = $Expression.Match($Item.ValueName) Switch ($ExpressionEvaluation.Success) { {($_ -eq $True)} { $ValueProperties = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $ValueProperties.Name = $Item.ValueName $ValueProperties.Alias = $ValueProperties.Name -ireplace '(\s+)', '' $ValueProperties.Type = $Item.ValueType $ValueProperties.Value = $Null $ValueProperties.ValueAsDecimal = $Null $ValueProperties.ValueAsHex = $Null #$LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Attempting to retrieve the registry key value of `"$($ValueProperties.Name)`" because the value name matches the regular expression of `"$($Expression.ToString())`". Please Wait..." #Write-Verbose -Message ($LoggingDetails.LogMessage) Switch ($Null -ine $Item.ValueData) { {($_ -eq $True)} { $ValueProperties.Value = $Item.ValueData Switch ($ValueProperties.Type) { {($_ -iin @('RegDword', 'RegQword'))} { $ValueProperties.ValueAsDecimal = Try {[System.Convert]::ToString($ValueProperties.Value, 10)} Catch {} $ValueProperties.ValueAsHex = Try {'0x' + [System.Convert]::ToString($ValueProperties.Value, 16).PadLeft(8, '0').ToUpper()} Catch {} } {($_ -iin @('RegBinary'))} { #$ValueProperties.ValueAsDecimal = Try {} Catch {} #$ValueProperties.ValueAsHex = Try {} Catch {} } } } } $ValueObject = New-Object -TypeName 'PSObject' -Property ($ValueProperties) $RegistryKeyProperties.ValueList.Add($ValueObject) } } } } $RegistryKeyObject = New-Object -TypeName 'PSObject' -Property ($RegistryKeyProperties) $OutputObjectList.Add($RegistryKeyObject) } Catch { $ErrorMessageList = New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' $ErrorMessageList.Add('Message', $_.Exception.Message) $ErrorMessageList.Add('Category', $_.Exception.ErrorRecord.FullyQualifiedErrorID) $ErrorMessageList.Add('LineNumber', $_.InvocationInfo.ScriptLineNumber) $ErrorMessageList.Add('LinePosition', $_.InvocationInfo.OffsetInLine) $ErrorMessageList.Add('Code', $_.InvocationInfo.Line.Trim()) ForEach ($ErrorMessage In $ErrorMessageList.GetEnumerator()) { $LoggingDetails.ErrorMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - ERROR: $($ErrorMessage.Key): $($ErrorMessage.Value)" Write-Warning -Message ($LoggingDetails.ErrorMessage) } } Finally { } } } Catch { $ErrorHandlingDefinition.Invoke() } Finally { } } End { Try { #Determine the date and time the function completed execution $FunctionEndTime = (Get-Date) $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Execution of $($FunctionName) ended on $($FunctionEndTime.ToString($DateTimeLogFormat))" Write-Verbose -Message ($LoggingDetails.LogMessage) #Log the total script execution time $FunctionExecutionTimespan = New-TimeSpan -Start ($FunctionStartTime) -End ($FunctionEndTime) $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function execution took $($FunctionExecutionTimespan.Hours.ToString()) hour(s), $($FunctionExecutionTimespan.Minutes.ToString()) minute(s), $($FunctionExecutionTimespan.Seconds.ToString()) second(s), and $($FunctionExecutionTimespan.Milliseconds.ToString()) millisecond(s)" Write-Verbose -Message ($LoggingDetails.LogMessage) $LoggingDetails.LogMessage = "$($GetCurrentDateTimeMessageFormat.Invoke()) - Function `'$($FunctionName)`' is completed." Write-Verbose -Message ($LoggingDetails.LogMessage) } Catch { $ErrorHandlingDefinition.Invoke() } Finally { #Write the object to the powershell pipeline $OutputObjectList = $OutputObjectList.ToArray() Write-Output -InputObject ($OutputObjectList) } } } #endregion