Test-FastLookup.ps1
function Test-FastLookup { <# .SYNOPSIS Designed to optimize the speed of searching an array. .DESCRIPTION Improve the speed of looking up a value in an array by creating a hashtable index. Good for looping through very large arrays or CSV files .NOTES Version: 1.2 Author: Miles Gratz Creation Date: April 20, 2017 Purpose/Change: Improve examples .OUTPUTS 1. Creates a sample array 2. Measures speed of searching array with Where-Object, Foreach/If, and Get-FastLookup .EXAMPLE PS> Test-FastLookup -ArraySize 100000 -SearchSize 10000 Creating 'speedtest' array (total array size: 100000; search size: 10000) Example object: DeviceName : DeviceName9475 Type : Security Camera IP : 10.10.128.62 VLAN : VLAN86 Location : Los Angeles Patch Window : Saturday Warranty Service Level : 24x7 Warranty Days Left : 124 Primary Technical Contact : Chris Application Manager : Doug Severity Level : Harry Technical Emergency Contact Number : P1 Manager Emergency Contact Number : 515-249-1602 --------------------------------------------------------------- Measuring speed of Where-Object lookup: $Results = $Array | Where-Object { $_.DeviceName -in $Search } Days : 0 Hours : 0 Minutes : 4 Seconds : 18 Milliseconds : 366 --------------------------------------------------------------- Measuring speed of Foreach/If lookup: [System.Collections.ArrayList]$Results = @() foreach ($Item in $Array) { If ($Item.DeviceName -in $Search) { [void]$Results.Add($Item) } } Days : 0 Hours : 0 Minutes : 4 Seconds : 14 Milliseconds : 148 --------------------------------------------------------------- Measuring speed of Get-FastLookup lookup: $Hashtable = New-FastLookup -Array $Array -Header "DeviceName" [System.Collections.ArrayList]$Results = @() foreach ($Item in $Search) { [void]$Results.Add((Get-FastLookup -Value $Item -Array $Array -Table $Hashtable)) } Days : 0 Hours : 0 Minutes : 0 Seconds : 52 Milliseconds : 773 -------------------------------------------------------------- [NOTE] Performance test on Windows 10 x64 (i5-6200U/8GB/SSD) #> param( # Default sample size of 100K, searching for 10K objects [int]$ArraySize = 100000, [int]$SearchSize = 10000 ) # Define empty ArrayList for sample array [System.Collections.ArrayList]$csvLines = @() # Create array based on quantity $Index = 0 Write-Output "Creating 'speedtest' array (total array size: $ArraySize; search size: $SearchSize)" while ($Index -lt $ArraySize) { # Calculate percentage $PercentageIndex = $Percentage $Percentage = [math]::Round((($Index / $ArraySize)*100)) # Announce percentage If ($Percentage -gt $PercentageIndex) { Write-Output "Creating 'speedtest' array ($Percentage%)" } # Example template $DeviceNumber = Get-Random -Maximum $($ArraySize*5) $Type = Get-Random 'Laptop','Workstation','Network Switch','Wireless Access Point','Security Camera','Server' $IP = "10.10.128." + (Get-Random (1..254)) $VLAN = "VLAN" + (Get-Random (1..100)) $Location = Get-Random 'Chicago','New York','Los Angeles' $PatchWindow = Get-Random 'Sunday','Saturday' $WarrantyServiceLevel = Get-Random '24x7','Next Business Day','Parts Only' $WarrantyDaysLeft = Get-Random -Minimum -100 -Maximum 1095 $PrimaryTech = Get-Random 'Angela','Bob','Chris' $SecondaryTech = Get-Random 'Doug','Eileen','Francis' $AppManager = Get-Random 'Grace','Harry','Isabel' $SeverityLevel = Get-Random 'P1','P2','P3','P4' $TechEmergencyNum = "515-249-" + (0..9 | Get-Random) + (0..9 | Get-Random) + (0..9 | Get-Random) + (0..9 | Get-Random) $MgrEmergencyNum = "515-249-" + (0..9 | Get-Random) + (0..9 | Get-Random) + (0..9 | Get-Random) + (0..9 | Get-Random) # Create custom object to add to array $csvLine = (('"DeviceName' + $DeviceNumber), $Type, $IP, $VLAN, $Location, $PatchWindow, $WarrantyServiceLevel, $WarrantyDaysLeft, $PrimaryTech, $SecondaryTech, $AppManager, $SeverityLevel, $TechEmergencyNum, ($MgrEmergencyNum + '"')) -join '","' # Add object to array [void]$csvLines.Add($csvLine) # Increment loop $Index++ } # Convert lines to CSV [string[]]$stringArray += '"DeviceName","Type","IP","VLAN","Location","Patch Window","Warranty Service Level","Warranty Days Left","Primary Technical Contact","Application Manager","Severity Level","Technical Emergency Contact Number","Manager Emergency Contact Number"' $stringArray += $csvLines [array]$Array = $stringArray | ConvertFrom-Csv # Create list of random server names $Index = 0 [System.Collections.ArrayList]$Search = @() while ($Index -lt $SearchSize) { $RandomIndex = Get-Random -Minimum 0 -Maximum ($Array.Count-1) $Random = $Array[$RandomIndex] [void]$Search.Add($Random.DeviceName) $Index++ } # Example object Write-Output "" Write-Output "Example object:" Write-Output $Array[0] # Measuring speed of Where-Object lookup Write-Output "" Write-Output ('-'*80) Write-Output 'Measuring speed of Where-Object lookup:' Write-Output "" Write-Output ('$Results = $Array | Where-Object { $_.DeviceName -in $Search }') $MeasureWhereObject = Measure-Command { $Results = $Array | Where-Object { $_.DeviceName -in $Search } } | Select-Object Days,Hours,Minutes,Seconds,Milliseconds Write-Output $MeasureWhereObject Write-Output "" Write-Output "Number of results: $($Results.Count)" Write-Output "First result:" Write-Output "" Write-Output $Results[0] # Measuring speed of ForEach lookup Write-Output "" Write-Output ('-'*80) Write-Output 'Measuring speed of Foreach/If lookup:' Write-Output "" Write-Output '[System.Collections.ArrayList]$Results = @()' Write-Output 'foreach ($Item in $Array)' Write-Output '{' Write-Output ' If ($Item.DeviceName -in $Search)' Write-Output ' {' Write-Output ' [void]$Results.Add($Item)' Write-Output ' }' Write-Output '}' $MeasureForeachIf = Measure-Command { [System.Collections.ArrayList]$Results = @() foreach ($Item in $Array) { If ($Item.DeviceName -in $Search) { [void]$Results.Add($Item) } } } | Select-Object Days,Hours,Minutes,Seconds,Milliseconds Write-Output $MeasureForeachIf Write-Output "" Write-Output "Number of results: $($Results.Count)" Write-Output "First result:" Write-Output "" Write-Output $Results[0] # Measuring speed of Get-FastLookup Write-Output "" Write-Output ('-'*80) Write-Output 'Measuring speed of Get-FastLookup lookup:' Write-Output "" Write-Output '$Hashtable = New-FastLookup -Array $Array -Header "DeviceName"' Write-Output '[System.Collections.ArrayList]$Results = @()' Write-Output 'foreach ($Item in $Search)' Write-Output '{' Write-Output ' [void]$Results.Add((Get-FastLookup -Value $Item -Array $Array -Table $Hashtable))' Write-Output '}' $MeasureFastLookup = Measure-Command { $Hashtable = New-FastLookup -Array $Array -Header "DeviceName" [System.Collections.ArrayList]$Results = @() foreach ($Item in $Search) { [void]$Results.Add((Get-FastLookup -Value $Item -Array $Array -Table $Hashtable)) } } | Select-Object Days,Hours,Minutes,Seconds,Milliseconds Write-Output "" Write-Output $MeasureFastLookup Write-Output "" Write-Output "Number of results: $($Results.Count)" Write-Output "First result:" Write-Output "" Write-Output $Results[0] } |