Extract columns from text based table output - powershell

qfarm /load command shows me the load from my servers.
Output:
PS> qfarm /load
Server Name Server Load Load Throttling Load Logon Mode
-------------------- ----------- -------------------- ------------------
SERVER-01 400 0 AllowLogons
SERVER-02 1364 OFF AllowLogons
SERVER-03 1364 OFF AllowLogons
SERVER-04 1000 0 AllowLogons
SERVER-05 700 0 AllowLogons
SERVER-06 1200 0 AllowLogons
I need to display only first column (Server Name) and the second one (Server Load) and loop through them, in order to make some logic later, but it seems the powershell doesn't see it as object with properties:
PS> qfarm /load | Select -ExpandProperty "Server Name"
Select-Object : Property "Server Name" cannot be found.
Is there any other possibility, like a table or something?

One way to do this is to build objects out of the command's output. Tested the following:
#requires -version 3
# sample data output from command
$sampleData = #"
Server Name Server Load Load Throttling Load Logon Mode
-------------------- ----------- -------------------- ------------------
SERVER-01 400 0 AllowLogons
SERVER-02 1364 OFF AllowLogons
SERVER-03 1364 OFF AllowLogons
SERVER-04 1000 0 AllowLogons
SERVER-05 700 0 AllowLogons
SERVER-06 1200 0 AllowLogons
"# -split "`n"
$sampleData | Select-Object -Skip 2 | ForEach-Object {
$len = $_.Length
[PSCustomObject] #{
"ServerName" = $_.Substring(0, 22).Trim()
"ServerLoad" = $_.Substring(22, 13).Trim() -as [Int]
"LoadThrottlingLoad" = $_.Substring(35, 22).Trim()
"LogonMode" = $_.Substring(57, $len - 57).Trim()
}
}
In your case, you should be able to replace $sampleData with your qfarm load command; e.g.:
qfarm /load | Select-Object -Skip 2 | ForEach-Object {
...
Of course, this is assuming no blank lines in the output and that my column positions for the start of each item is correct.
PowerShell version 2 equivalent:
#requires -version 2
function Out-Object {
param(
[Collections.Hashtable[]] $hashData
)
$order = #()
$result = #{}
$hashData | ForEach-Object {
$order += ($_.Keys -as [Array])[0]
$result += $_
}
New-Object PSObject -Property $result | Select-Object $order
}
# sample data output from command
$sampleData = #"
Server Name Server Load Load Throttling Load Logon Mode
-------------------- ----------- -------------------- ------------------
SERVER-01 400 0 AllowLogons
SERVER-02 1364 OFF AllowLogons
SERVER-03 1364 OFF AllowLogons
SERVER-04 1000 0 AllowLogons
SERVER-05 700 0 AllowLogons
SERVER-06 1200 0 AllowLogons
"# -split "`n"
$sampleData | Select-Object -Skip 2 | ForEach-Object {
$len = $_.Length
Out-Object `
#{"ServerName" = $_.Substring(0, 22).Trim()},
#{"ServerLoad" = $_.Substring(22, 13).Trim() -as [Int]},
#{"LoadThrottlingLoad" = $_.Substring(35, 22).Trim()},
#{"LogonMode" = $_.Substring(57, $len - 57).Trim()}
}

You can easily convert your table to PowerShell objects using the ConvertFrom-SourceTable cmdlet from the PowerShell Gallery:
$sampleData = ConvertFrom-SourceTable #"
Server Name Server Load Load Throttling Load Logon Mode
-------------------- ----------- -------------------- ------------------
SERVER-01 400 0 AllowLogons
SERVER-02 1364 OFF AllowLogons
SERVER-03 1364 OFF AllowLogons
SERVER-04 1000 0 AllowLogons
SERVER-05 700 0 AllowLogons
SERVER-06 1200 0 AllowLogons
"#
And than select your columns like:
PS C:\> $SampleData | Select-Object "Server Name", "Server Load"
Server Name Server Load
----------- -----------
SERVER-01 400
SERVER-02 1364
SERVER-03 1364
SERVER-04 1000
SERVER-05 700
SERVER-06 1200
For details see: ConvertFrom-SourceTable -?
The ConvertFrom-SourceTable cmdlet is available for download at the PowerShell Gallery and the source code from the GitHub iRon7/ConvertFrom-SourceTable repository.

Command-line utilities return their outputs as a string array. This should work:
qfarm /load | ForEach-Object { $_.Substring(0,33) }

I have answered something very similar to this in the past. I have a larger function for this but a simplified on work on left aligned string table just as you have shown in you example. See the linked answer for more explanation.
function ConvertFrom-LeftAlignedStringData{
param (
[string[]]$data
)
$headerString = $data[0]
$headerElements = $headerString -split "\s{2,}" | Where-Object{$_}
$headerIndexes = $headerElements | ForEach-Object{$headerString.IndexOf($_)}
$results = $data | Select-Object -Skip 2 | ForEach-Object{
$props = #{}
$line = $_
For($indexStep = 0; $indexStep -le $headerIndexes.Count - 1; $indexStep++){
$value = $null # Assume a null value
$valueLength = $headerIndexes[$indexStep + 1] - $headerIndexes[$indexStep]
$valueStart = $headerIndexes[$indexStep]
If(($valueLength -gt 0) -and (($valueStart + $valueLength) -lt $line.Length)){
$value = ($line.Substring($valueStart,$valueLength)).Trim()
} ElseIf ($valueStart -lt $line.Length){
$value = ($line.Substring($valueStart)).Trim()
}
$props.($headerElements[$indexStep]) = $value
}
New-Object -TypeName PsCustomObject -Property $props
}
return $results
}
$qfarmOutput = qfarm /load
ConvertFrom-LeftAlignedStringData $qfarmOutput | select "Server Name","Server Load"
This approach is based on the position of the header fields. Nothing is hardcoded and it is all custom built based on those indexes and field names. Using those $headerIndexes we carve up every line and place the results, if present, into its respective column. There is logic to ensure that we don't try and grab any part of the string that might not exist and treat the last field special.
Results
Server Name Server Load
----------- -----------
SERVER-01 400
SERVER-02 1364
SERVER-03 1364
SERVER-04 1000
SERVER-05 700
SERVER-06 1200

Related

Powershell - Group and count unique values from CSV file based on a column

I am trying to get total completed and failed job for each days. If a job failed for any specific VM (Name field) for any specific day, it will retry the operation.If it complete in second attempt, I want o ignore the failed count for that and reduce the total count accordingly
Example:
My code
$csv =ConvertFrom-Csv #"
Name,Start_time,Status
vm1,20-03-2022,Completed
vm2,20-03-2022,Completed
vm1,21-03-2022,Failed
vm1,21-03-2022,Completed
vm2,21-03-2022,Completed
vm1,22-03-2022,Completed
vm2,22-03-2022,Failed
vm2,22-03-2022,Failed
"#
$Results = #()
foreach ($group in $csv | Group Start_time)
{
$Completed = ($group.Group | group status | ? Name -eq Completed).Count
$Failed = ($group.Group | group status | ? Name -eq Failed).Count
$row = "" | Select Date,Total,Completed,Failed,"Success %"
$row.Date = $group.Name
$row.Total = $group.Count
$row.Completed = $Completed
$row.Failed = $Failed
$row."Success %" = [math]::Round($Completed / $row.Total * 100,2)
$Results += $row
}
Above code will give me output as :
Date Total Completed Failed Success %
20-03-2022 2 2 0 100
21-03-2022 3 2 1 66.67
22-03-2022 3 1 2 33.33
But I am looking for the unique value for each VM for each day and ignore the failure, any retry shows as completed
Date Total Completed Failed Success %
20-03-2022 2 2 0 100 -> Job completed for vm1 and vm2
21-03-2022 2 2 0 100 -> job failed for vm1 first, but in second try it completed. same day 2 entries for vm1(Failed and Completed. Ignore failure and take only completed)
22-03-2022 2 1 1 50 -> vm2 failed on both attempt. so it has to take as 1 entry. ignore the duplicate run.
This seems to work, needless to say, you're displaying the information in an quite unorthodox way. I believe the code you currently have is how the information should be displayed.
Using this CSV for demonstration:
$csv = ConvertFrom-Csv #"
Name,Start_time,Status
vm1,20-03-2022,Completed
vm2,20-03-2022,Completed
vm1,21-03-2022,Failed
vm1,21-03-2022,Completed
vm2,21-03-2022,Completed
vm1,22-03-2022,Completed
vm2,22-03-2022,Failed
vm2,22-03-2022,Failed
vm1,23-03-2022,Failed
vm1,23-03-2022,Failed
vm2,23-03-2022,Failed
vm2,23-03-2022,Failed
"#
Code:
$csv | Group-Object Start_Time | ForEach-Object {
$completed = 0; $failed = 0
$thisGroup = $_.Group | Group-Object Name
foreach($group in $thisGroup) {
if('Completed' -in $group.Group.Status) {
$completed++
continue
}
$failed++
}
$total = $completed + $failed
[pscustomobject]#{
Start_Date = $_.Name
Total = $total
Completed = $completed
Failed = $failed
Success = ($completed / $total).ToString('P0')
}
} | Format-Table
Result:
Start_Date Total Completed Failed Success
---------- ----- --------- ------ -------
20-03-2022 2 2 0 100%
21-03-2022 2 2 0 100%
22-03-2022 2 1 1 50%
23-03-2022 2 0 2 0%

Powershell - Group and count from CSV file

In my CSV file, I have two columns with header Start_date and Status. I am trying to find out the success percentage for each Start_date
Start_date Status
------------------------------------------
02-03-2022 Completed
02-03-2022 Completed
03-03-2022 Failed
03-03-2022 Completed
I am looking for a final output like below which I export CSV
Start_date Total Completed Failed Success %
02-03-2022 2 2 0 100
03-03-2022 2 1 1 50
As a first step, I am trying to get the count of each day job using below code.
$data = Import-Csv "C:\file.csv"
$data | group {$_.Start_date} | Sort-Object {$_.Start_date} | Select-Object {$_.Status}, Count
Above code will give me output like
$_.Status Count
--------- -----
1
1
it is not showing the date value. what will be the correct approach for this issue ?
You can use Group-Object to group the objects by the date column, then it's just math:
$csv = #'
Start_date,Status
02-03-2022,Completed
02-03-2022,Completed
03-03-2022,Failed
03-03-2022,Completed
'# | ConvertFrom-Csv
# This from your side should be:
# Import-Csv path/to/csv.csv | Group-Object ....
$csv | Group-Object Start_date | ForEach-Object {
$completed, $failed = $_.Group.Status.where({ $_ -eq 'Completed' }, 'Split')
$totalc = $_.Group.Count
$complc = $completed.Count
$failc = $failed.Count
$success = $complc / $totalc
[pscustomobject]#{
Start_Date = $_.Name
Total = $totalc
Completed = $complc
Failed = $failc
Success = $success.ToString('P0')
}
}
Here's another one:
$csv = Import-Csv C:\Temp\tmp.csv
$Results = #()
foreach ($group in $csv | Group Start_date)
{
$Completed = ($group.Group | group status | ? Name -eq Completed).Count
$Failed = ($group.Group | group status | ? Name -eq Failed).Count
$row = "" | Select Start_date,Total,Completed,Failed,"Success %"
$row.Start_date = $group.Name
$row.Total = $group.Count
$row.Completed = $Completed
$row.Failed = $Failed
$row."Success %" = $Completed / 2 * 100
$Results += $row
}
$results
Start_date Total Completed Failed Success %
---------- ----- --------- ------ ---------
02-03-2022 2 2 0 100
03-03-2022 2 1 1 50

Powershell Get-Random with Constraints

I'm currently using the Get-Random function of Powershell to randomly pull a set number of rows from a csv. I need to create a constraint that says if one id is pulled, find the other ids that match it and pull their value.
Here is what I currently have:
$chosenOnes = Import-CSV C:\Temp\pk2.csv | sort{Get-Random} | Select -first 6
$i = 1
$count = $chosenOnes | Group-Object householdID
foreach ($row in $count)
{
if ($row.count -gt 1)
{
$students = $row.Group.Student
foreach ($student in $students)
{
$name = $student.tostring()
#...do something
$i = $i + 1
}
}
else
{
$name = $row.Group.Student
if($i -le 5)
{
#...do something
}
else
{
#...do something
}
$i = $i + 1
}
}
Example dataset
ID,name
165,Ernest Hemingway
1204,Mark Twain
1578,Stephen King
1634,Charles Dickens
1726,George Orwell
7751,John Doe
7751,Tim Doe
In this example, there are 7 rows but I'm randomly selecting 6 in my code. What needs to happen is when ID=7751 then I must return both rows where ID=7751. The IDs cannot not be statically set in the code.
Use Get-Random directly, with -Count, to extract a given number of random elements from a collection.
$allRows = Import-CSV C:\Temp\pk2.csv
$chosenHouseholdIDs = ($allRows | Get-Random -Count 6).householdID
Then filter all rows by whether their householdID column contains one of the 6 randomly selected rows' householdID values (PSv3+ syntax), using the -in array-containment operator:
$allRows | Where-Object householdID -in $chosenHouseholdIDs
Optional reading: performance considerations:
$allRows | Get-Random -Count 6 is not only conceptually simpler, but also much faster than $allRows | Sort-Object { Get-Random } | Select-Object -First 6
Using the Time-Command function to compare the performance of two approaches, using a 1000-row test file with 10 columns yields the following sample timings on my Windows 10 VM in Windows PowerShell - note that the Sort-Object { Get-Random }-based solution is more than 15(!) times slower:
Factor Secs (100-run avg.) Command TimeSpan
------ ------------------- ------- --------
1.00 0.007 $allRows | Get-Random -Count 6 00:00:00.0072520
15.65 0.113 $allRows | Sort-Object { Get-Random } | Select-Object -First 6 00:00:00.1134909
Similarly, a single pass through all rows to find matching IDs via array-containment operator -in performs much better than looping over the randomly selected IDs and searching all rows for each.
I tried sticking with your beginning and came up with this.
$Array = Import-CSV C:\test\StudtentTest.csv
$Array | Sort{Get-Random} | select -first 2 | %{
$id = $_.id
$Array | ?{$_.id -eq $id} | %{
$_
}
}
$Array will be your parsed CSV
We pipe in and sort by random select -first 2 (in this case)
Save the ID of the object into $id and then search the array for that ID and dispaly each that matches
If same ID does match you end up with something like
ID name
-- ----
7751 John Doe
7751 Tim Doe
1634 Charles Dickens

Aggregating tasks by duration for each day in a week/month? (PoSH)

I am parsing JSON from a web service to get my tasks (using a TimeFlip). Right now, I get back each task, when it occurred, and duration, so the data looks like this:
(taskname, start, durationinSec)
TaskA,"6/5/2018 12:16:36 PM",312
TaskB,"6/5/2018 12:30:36 PM",200
TaskA,"6/6/2018 08:00:00 AM",150
TaskA,"6/6/2018 03:00:00 PM",150
(etc etc)
I would like to generate a rollup report, showing by day which tasks had how much time.
While the data will span weeks, I'm just trying to do a weekly report that I can easily transcribe into our time app (since they won't give me an API key). So I'll do something like where {$_.start -gt (? {$_.start -gt (get-date -Hour 0 -Minute 00 -Second 00).adddays(-7)} first.
6/5/2018 6/6/2018
TaskA 312 300
TaskB 200
How can I do that? I assume group-object, but unclear how you'd do either the pivot or even the grouping.
The following doesn't output a pivot table, but performs the desired grouping and aggregation:
$rows = #'
taskname,start,durationinSec
TaskA,"6/5/2018 12:16:36 PM",312
TaskB,"6/5/2018 12:30:36 PM",200
TaskA,"6/6/2018 08:00:00 AM",150
TaskA,"6/6/2018 03:00:00 PM",150
'# | ConvertFrom-Csv
$rows | Group-Object { (-split $_.start)[0] }, taskname | ForEach-Object {
$_ | Select-Object #{ n='Date'; e={$_.Values[0]} },
#{ n='Task'; e={$_.Values[1]} },
#{ n='Duration'; e={ ($_.Group | Measure-Object durationInSec -Sum).Sum } }
}
(-split $_.start)[0] splits each start value by whitespace and returns the first token ([0]), which is the date portion of the time stamp; e.g., 6/5/2018 is returned for 6/5/2018 12:16:36 PM; passing this operation as a script block ({ ... }) to Group-Object means that grouping happens by date only, not also time (in addition to grouping by taskname).
This yields:
Date Task Duration
---- ---- --------
6/5/2018 TaskA 312
6/5/2018 TaskB 200
6/6/2018 TaskA 300
To construct pivot-table-like output requires substantially more effort, and it won't be fast:
Assume that $objs contains the objects created above ($objs = $rows | Group-Object ...).
# Get all distinct dates.
$dates = $objs | Select-Object -Unique -ExpandProperty Date
# Get all distinct tasks.
$tasks = $objs | Select-Object -Unique -ExpandProperty Task
# Create an ordered hashtable that contains an entry for each task that
# holds a nested hashtable with (empty-for-now) entries for all dates.
$ohtPivot = [ordered] #{}
$tasks | ForEach-Object {
$ohtDates = [ordered] #{}
$dates | ForEach-Object { $ohtDates[$_] = $null }
$ohtPivot[$_] = $ohtDates
}
# Fill the hashtable from the grouped objects with the task- and
# date-specific durations.
$objs | ForEach-Object { $ohtPivot[$_.Task][$_.Date] = $_.Duration }
# Output the resulting hashtable in pivot-table-like form by transforming
# each entry into a custom object
$ohtPivot.GetEnumerator() | ForEach-Object {
[pscustomobject] #{ Task = $_.Key } | Add-Member -PassThru -NotePropertyMembers $_.Value
}
The above yields:
Task 6/5/2018 6/6/2018
---- -------- --------
TaskA 312 300
TaskB 200
Googling for PowerShell and Pivot I found this gist.github.com with a more universal way to create the PivotTable.
To transpose (swap x,y) you simply change the variables $rotate, $keep
It has the additional benefit of calculating a row Total
## Q:\Test\2018\06\09\PivotTable.ps1
## Source https://gist.github.com/andyoakley/1651859
# #############################################################################
# Rotates a vertical set similar to an Excel PivotTable
# #############################################################################
$OutputFile = "MyPivot.csv"
$data = #'
taskname,start,duration
TaskA,"6/5/2018 12:16:36 PM",312
TaskB,"6/5/2018 12:30:36 PM",200
TaskA,"6/6/2018 08:00:00 AM",150
TaskA,"6/6/2018 03:00:00 PM",150
'# | ConvertFrom-Csv |Select-Object taskname, duration, #{n='start';e={($_.start -split ' ')[0]}}
# Fields of interest
$rotate = "taskname" # Bits along the top
$keep = "start" # Those along the side
$value = "duration" # What to total
#-------------------- No need to change anything below ------------------------
# Creatre variable to store the output
$rows = #()
# Find the unique "Rotate" [top row of the pivot] values and sort ascending
$pivots = $data | select -unique $rotate | foreach { $_.$rotate} | Sort-Object
# Step through the original data...
# for each of the "Keep" [left hand side] find the Sum of the "Value" for each "Rotate"
$data |
group $keep |
foreach {
$group = $_.Group
# Create the data row and name it as per the "Keep"
$row = new-object psobject
$row | add-member NoteProperty $keep $_.Name
# Cycle through the unique "Rotate" values and get the sum
foreach ($pivot in $pivots) {
$row | add-member NoteProperty $pivot ($group | where { $_.$rotate -eq $pivot } | measure -sum $value).Sum
}
# Add the total to the row
$row | add-member NoteProperty Total ($group | measure -sum $value).Sum
# Add the row to the collection
$rows += $row
}
# Do something with the pivot rows
$rows | Format-Table
$rows | Export-Csv $OutputFile -NoTypeInformation
Sample output:
start TaskA TaskB Total
----- ----- ----- -----
6/5/2018 312 200 512
6/6/2018 300 300
Or x/y swapped
taskname 6/5/2018 6/6/2018 Total
-------- -------- -------- -----
TaskA 312 300 612
TaskB 200 200

Partial/near match for name and/or username in Active Directory / Powershell

Our users sometimes gives us misspelled names/usernames and I would like to be able to search active directory for a near match, sorting by closest (any algorithm would be fine).
For example, if I try
Get-Aduser -Filter {GivenName -like "Jack"}
I can find the user Jack, but not if I use "Jacck" or "ack"
Is there a simple way to do this?
You can calculate the Levenshtein distance between the two strings and make sure it's under a certain threshold (probably 1 or 2). There is a powershell example here:
Levenshtein distance in powershell
Examples:
Jack and Jacck have an LD of 1.
Jack and ack have an LD of 1.
Palle and Havnefoged have an LD of 8.
Interesting question and answers. But a possible simpler solution is to search by more than one attribute as I would hope most people would spell one of their names properly :)
Get-ADUser -Filter {GivenName -like "FirstName" -or SurName -Like "SecondName"}
The Soundex algorithm is designed for just this situation. Here is some PowerShell code that might help:
Get-Soundex.ps1
OK, based on the great answers that I got (thanks #boxdog and #Palle Due) I am posting a more complete one.
Major source: https://github.com/gravejester/Communary.PASM - PowerShell Approximate String Matching. Great Module for this topic.
1) FuzzyMatchScore function
source: https://github.com/gravejester/Communary.PASM/tree/master/Functions
# download functions to the temp folder
$urls =
"https://raw.githubusercontent.com/gravejester/Communary.PASM/master/Functions/Get-CommonPrefix.ps1" ,
"https://raw.githubusercontent.com/gravejester/Communary.PASM/master/Functions/Get-LevenshteinDistance.ps1" ,
"https://raw.githubusercontent.com/gravejester/Communary.PASM/master/Functions/Get-LongestCommonSubstring.ps1" ,
"https://raw.githubusercontent.com/gravejester/Communary.PASM/master/Functions/Get-FuzzyMatchScore.ps1"
$paths = $urls | %{$_.split("\/")|select -last 1| %{"$env:TEMP\$_"}}
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
for($i=0;$i -lt $urls.count;$i++){
Invoke-WebRequest -Uri $urls[$i] -OutFile $paths[$i]
}
# concatenating the functions so we don't have to deal with source permissions
foreach($path in $paths){
cat $path | Add-Content "$env:TEMP\Fuzzy_score_functions.ps1"
}
# to save for later, open the temp folder with: Invoke-Item $env:TEMP
# then copy "Fuzzy_score_functions.ps1" somewhere else
# source Fuzzy_score_functions.ps1
. "$env:TEMP\Fuzzy_score_functions.ps1"
Simple test:
Get-FuzzyMatchScore "a" "abc" # 98
Create a score function:
## start function
function get_score{
param($searchQuery,$searchData,$nlist,[switch]$levd)
if($nlist -eq $null){$nlist = 10}
$scores = foreach($string in $searchData){
Try{
if($levd){
$score = Get-LevenshteinDistance $searchQuery $string }
else{
$score = Get-FuzzyMatchScore -Search $searchQuery -String $string }
Write-Output (,([PSCustomObject][Ordered] #{
Score = $score
Result = $string
}))
$I = $searchData.indexof($string)/$searchData.count*100
$I = [math]::Round($I)
Write-Progress -Activity "Search in Progress" -Status "$I% Complete:" -PercentComplete $I
}Catch{Continue}
}
if($levd) { $scores | Sort-Object Score,Result |select -First $nlist }
else {$scores | Sort-Object Score,Result -Descending |select -First $nlist }
} ## end function
Examples
get_score "Karolin" #("Kathrin","Jane","John","Cameron")
# check the difference between Fuzzy and LevenshteinDistance mode
$names = "Ferris","Cameron","Sloane","Jeanie","Edward","Tom","Katie","Grace"
"Fuzzy"; get_score "Cam" $names
"Levenshtein"; get_score "Cam" $names -levd
Test the performance on a big dataset
## donload baby-names
$url = "https://github.com/hadley/data-baby-names/raw/master/baby-names.csv"
$output = "$env:TEMP\baby-names.csv"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Invoke-WebRequest -Uri $url -OutFile $output
$babynames = import-csv "$env:TEMP\baby-names.csv"
$babynames.count # 258000 lines
$babynames[0..3] # year, name, percent, sex
$searchdata = $babynames.name[0..499]
$query = "Waren" # missing letter
"Fuzzy"; get_score $query $searchdata
"Levenshtein"; get_score $query $searchdata -levd
$query = "Jon" # missing letter
"Fuzzy"; get_score $query $searchdata
"Levenshtein"; get_score $query $searchdata -levd
$query = "Howie" # lookalike
"Fuzzy"; get_score $query $searchdata;
"Levenshtein"; get_score $query $searchdata -levd
Test
$query = "John"
$res = for($i=1;$i -le 10;$i++){
$searchdata = $babynames.name[0..($i*100-1)]
$meas = measure-command{$res = get_score $query $searchdata}
write-host $i
Write-Output (,([PSCustomObject][Ordered] #{
N = $i*100
MS = $meas.Milliseconds
MS_per_line = [math]::Round($meas.Milliseconds/$searchdata.Count,2)
}))
}
$res
+------+-----+-------------+
| N | MS | MS_per_line |
| - | -- | ----------- |
| 100 | 696 | 6.96 |
| 200 | 544 | 2.72 |
| 300 | 336 | 1.12 |
| 400 | 6 | 0.02 |
| 500 | 718 | 1.44 |
| 600 | 452 | 0.75 |
| 700 | 224 | 0.32 |
| 800 | 912 | 1.14 |
| 900 | 718 | 0.8 |
| 1000 | 417 | 0.42 |
+------+-----+-------------+
These times are quite crazy, if anyone understand why please comment on it.
2) Generate a table of Names from Active Directory
The best way to do this depends on the organization of the AD. Here we have many OUs, but common users will be in Users and DisabledUsers. Also Domain and DC will be different (I'm changing ours here to <domain> and <DC>).
# One way to get a List of OUs
Get-ADOrganizationalUnit -Filter * -Properties CanonicalName |
Select-Object -Property CanonicalName
then you can use Where-Object -FilterScript {} to filter per OU
# example, saving on the temp folder
Get-ADUser -f * |
Where-Object -FilterScript {
($_.DistinguishedName -match "CN=\w*,OU=DisabledUsers,DC=<domain>,DC=<DC>" -or
$_.DistinguishedName -match "CN=\w*,OU=Users,DC=<domain>,DC=<DC>") -and
$_.GivenName -ne $null #remove users without givenname, like test users
} |
select #{n="Fullname";e={$_.GivenName+" "+$_.Surname}},
GivenName,Surname,SamAccountName |
Export-CSV -Path "$env:TEMP\all_Users.csv" -NoTypeInformation
# you can open the file to inspect
Invoke-Item "$env:TEMP\all_Users.csv"
# import
$allusers = Import-Csv "$env:TEMP\all_Users.csv"
$allusers.Count # number of lines
Usage:
get_score "Jane Done" $allusers.fullname 15 # return the 15 first
get_score "jdoe" $allusers.samaccountname 15