I'm working on a script for use in Windows 7 and Windows 10 for a Registry search in HKLM:\Software\Classes. So far my code works, but its extremely slow. It takes about 30 minutes to complete.
Update 1:
Changed $d= Get-Item .
to $d= Get-Item -literalpath $path
.
Need to use Set-Location also to avoid error with Get-ItemProperty, which occurs because the $path is not a valid object
How can I speed this code up? Whats wrong?
Please help to speed up...
#regsearch.ps1
Function Get-RegItems
{
Param(
[Parameter(Mandatory=$true)]
[string]$path,
[string]$match)
#Set Local Path and ignore wildcard (literalpath)
Set-Location -literalpath $path
$d= Get-Item -literalpath $path
# If more then one value -> process
If ($d.Valuecount -gt 0) {
$d |
# Get unkown property
Select-Object -ExpandProperty Property |
ForEach {
$val = (Get-ItemProperty -Path . -Name $_).$_
#if Filter $match found, generate ReturnObject
if (($_ -match $match) -or ($val -match $match ) -or ($path-match $match)) {
New-Object psobject -Property @{ “key”=$path; “property”=$_; “value” = $val ;}
}}
}
} #end function Get-RegItems
Function RegSearch
{
Param(
[Parameter(Mandatory=$true)]
[string]$path,
[string]$match)
# Expand $path if necessary to get a valid object
if ( $path.Indexof("HKEY") -ne "-1" -and $path.Indexof("Registry::") -eq "-1" ) { $path = "Microsoft.PowerShell.Core\Registry::" +$path }
# Retrieve Items of Main Key
Get-RegItems -path $path -match $match
# Retrieve Items of all Childkeys
Get-ChildItem $path -Recurse -ErrorAction SilentlyContinue |
ForEach { Get-RegItems -path $_.PsPath -match $match }
} #end function RegSearch
#$search ="HKCU:\SOFTWARE\Microsoft\Office"
$searchkey =‘HKLM:\SOFTWARE\Microsoft\Office\’
#$searchkey = "HKLM:\Software\Classes\"
$pattern = "EventSystem"
cls
$result = @()
measure-command {$result = Regsearch -path $searchkey -match $pattern }
# TESTING
#$t = @( "Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Classes",
# "HKLM:\Software\Classes\Wow6432Node\CLSID\",
# "HKCU:\SOFTWARE\Microsoft\Office\",
# "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office")
#cls
#$t |ForEach { Get-RegItems -path $_ } | fl
if ($result.Count) {
$result
"Count: {0}" -f ($result.Count-1) }
else { "Path: {0} `nNo Items found" -f $searchkey}
#regsearch.ps1
I accepted the challenge and made it "as fast as possible". Now it is even faster than REGEDIT or any other tool. The below sample lasts 11 seconds to parse the complete OFFICE-key and all subkeys.
In addition, it also searches for string-matches in REG-BINARY etc.
Enjoy!
Here is a faster version of you sample-script. Lasts ca. 1 minute on my machine. If you need it faster, then you need to work with advapi32.dll-Pinvokes, but then it will end quite complex.
Don't use the registry drive provider, if you want it faster.
User function call overhead (scriptblocks included) is extremely big (e.g. 0.1-1ms). This becomes a very serious issue when the function is executed thousands/millions of times. Surprisingly, it's not mentioned in optimization-related articles (at least I've never seen it and I googled this topic a lot).
Unfortunately, the only only real solution to this particular issue is to inline the code at the cost of duplication and reduced readability.
Optimization should include code profiling.
PowerShell doesn't have a code profiler so you'll need to do it manually with Measure-Command.
Use System.Diagnostics.Stopwatch inside loops to display the accumulated time:
The single biggest improvement you can make here is changing:
to
Manipulating the location stack for each key in the hierarchy introduces A LOT of unnecessary overhead