The Get-NetFirewallRule method checks the status for about half second. This is a very long time when I need to check more than a hundred names in the firewall.
# About a minute checked this
0..100 | % { Get-NetFirewallRule -DisplayName $_ }
Can I speed up this method? Thanks
It is faster to get all rules first. Then query the retrieved rules based on your criteria.
# Storing Rules in Variable First
$rules = Get-NetFirewallRule
$rules | Where DisplayName -in 0..100
# Using the pipeline only
Get-NetFirewallRule | Where DisplayName -in 0..100
Performance Test:
# One Rule At a Time
Measure-Command {0..10 |% { get-netfirewallrule -displayname $_ }}
Days : 0
Hours : 0
Minutes : 0
Seconds : 9
Milliseconds : 877
Ticks : 98770423
TotalDays : 0.000114317619212963
TotalHours : 0.00274362286111111
TotalMinutes : 0.164617371666667
TotalSeconds : 9.8770423
TotalMilliseconds : 9877.0423
# Get All Rules First
Measure-Command {$rules = Get-netfirewallrule; $rules | where displayname -in 0..10}
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 44
Ticks : 10440671
TotalDays : 1.20841099537037E-05
TotalHours : 0.000290018638888889
TotalMinutes : 0.0174011183333333
TotalSeconds : 1.0440671
TotalMilliseconds : 1044.0671
Hmm, I guess it's not indexed by name or displayname? This is the wmi class it uses. I'm not sure it's worth delving into, but fyi.
Get-WmiObject MSFT_NetFirewallRule -Namespace Root\StandardCimv2 -filter 'creationclassname="MSFT|FW|FirewallRule|vm-monitoring-dcom"'
The firewall rules are stored in the registry, btw.
There's various get-netfirewall*filter commands that make accessing certain info faster, but not name or displayname.
You can try making your own hashtable of the displaynames.
Try putting this in a job, it will get way faster:
$job = Start-Job -ScriptBlock {
0..100 | % { Get-NetFirewallRule -DisplayName $_ }
}
$job | Wait-Job | Receive-Job
I have a huge array which contains dates. The date has the following form: tt.mm.yyyy. I know how to sort the array with Sort-Object, but the sorting takes a lot of time. I found another way of sorting arrays, but it doesn't work as expected.
My former code to sort the array was like this.
$data | Sort-Object { [System.DateTime]::ParseExact($_, "dd.MM.yyyy", $null) }
But as I siad before: this way of sorting is too slow. The Sort() method from System.Array seems to be much faster.
[Array]::Sort([array]$array)
This code sorts an array containing strings much faster than Sort-Object. Is there a way how I can change the above sorting method like the Sort-Object method?
The .NET method will work for dates if you make sure that the array is of type DateTime.
Meaning you should use
[DateTime[]]$dateArray
instead of
[Array]$dateArray
when you create it. Then you can use
[Array]::Sort($dateArray)
to perform the sort it self...
Your input data are date strings with a date format that doesn't allow sorting in "date" order. You must convert the strings either to actual dates
Get-Date $_
[DateTime]::ParseExact($_, "dd.MM.yyyy", $null)
or change the format of the string dates to ISO format, which does allow sorting in date order.
'{2}-{1}-{0}' -f ($_ -split '.')
'{0}-{1}-{2}' -f $_.Substring(6,4), $_.Substring(3,2), $_.Substring(0,2)
$_ -replace '(\d+)\.(\d+).(\d+)', '$3-$2-$1'
At some point you must do one of these conversions, either when creating the data or when sorting.
I ran some tests WRT performance of each conversion, and string transformation using the Substring() method seems to be the fastest way:
PS C:\> $dates = 1..10000 | % {
>> $day = Get-Random -Min 1 -Max 28
>> $month = (Get-Random -Min 1 -Max 12
>> $year = Get-Random -Min 1900 -Max 2014
>> '{0:d2}.{1:d2}.{2}' -f $day, $month, $year
>> }
>>
PS C:\> Measure-Command { $dates | sort {Get-Date $_} }
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 520
Ticks : 15200396
TotalDays : 1,75930509259259E-05
TotalHours : 0,000422233222222222
TotalMinutes : 0,0253339933333333
TotalSeconds : 1,5200396
TotalMilliseconds : 1520,0396
PS C:\> Measure-Command { $dates | sort {'{2}-{1}-{0}' -f ($_ -split '.')} }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 413
Ticks : 4139027
TotalDays : 4,79054050925926E-06
TotalHours : 0,000114972972222222
TotalMinutes : 0,00689837833333333
TotalSeconds : 0,4139027
TotalMilliseconds : 413,9027
PS C:\> Measure-Command { $dates | sort {$_ -replace '(\d+)\.(\d+).(\d+)', '$3-$2-$1'} }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 348
Ticks : 3488962
TotalDays : 4,03815046296296E-06
TotalHours : 9,69156111111111E-05
TotalMinutes : 0,00581493666666667
TotalSeconds : 0,3488962
TotalMilliseconds : 348,8962
PS C:\> Measure-Command { $dates | sort {[DateTime]::ParseExact($_, "dd.MM.yyyy", $null)} }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 340
Ticks : 3408966
TotalDays : 3,9455625E-06
TotalHours : 9,46935E-05
TotalMinutes : 0,00568161
TotalSeconds : 0,3408966
TotalMilliseconds : 340,8966
PS C:\> Measure-Command { $dates | sort {'{0}-{1}-{2}' -f $_.Substring(6,4), $_.Substring(3,2), $_.Substring(0,2)} }
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 292
Ticks : 2926835
TotalDays : 3,38754050925926E-06
TotalHours : 8,13009722222222E-05
TotalMinutes : 0,00487805833333333
TotalSeconds : 0,2926835
TotalMilliseconds : 292,6835
Here is one example, but there must be a more efficient way:
1..100|%{$temp=$_;$temp%=3;if ($temp -eq 0){$_} }
1..100 | Where-Object {$_ % 3 -eq 0}
I would guess that the "most efficient" way would be to use a plain old for loop:
for($i=3; $i -le 100; $i +=3){$i}
Though that's not very elegant. You could create a function:
function range($start,$end,$interval) {for($i=$start; $i -le $end; $i +=$interval){$i}}
Timing this against your method (using more pithy version of other answer):
# ~> measure-command {1..100 | Where-Object {$_ % 3 -eq 0}}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 7
Ticks : 76020
TotalDays : 8.79861111111111E-08
TotalHours : 2.11166666666667E-06
TotalMinutes : 0.0001267
TotalSeconds : 0.007602
TotalMilliseconds : 7.602
# ~> measure-command{range 3 100 3}
Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 6197
TotalDays : 7.1724537037037E-09
TotalHours : 1.72138888888889E-07
TotalMinutes : 1.03283333333333E-05
TotalSeconds : 0.0006197
TotalMilliseconds : 0.6197
How can i use New-Timespan cmdlet to calculate the total time taken for script execution.I tried a sample like this.
$val=Get-Date
$start=New-TimeSpan -Start $val
$val2=Get-Date
$end=New-TimeSpan -End $val2
$diff=New-TimeSpan -Start $start -End $end
But ended up with following error: New-TimeSpan : Cannot bind parameter 'Start'. Cannot convert the "00:00:08.7110000" value of type "System.TimeSpan" to
type "System.DateTime".
You don't need to use New-TimeSpan just subtract the DateTime objects:
$script_start = Get-Date
Start-Sleep -Seconds 5
$script_end = Get-Date
$script_end - $script_start
This will create a TimeSpan object.
You could use Measure-Command. It returns a timespan object. Example:
PS C:\> Measure-Command -Expression {1..10000000}
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 714
Ticks : 17149279
TotalDays : 1.98487025462963E-05
TotalHours : 0.000476368861111111
TotalMinutes : 0.0285821316666667
TotalSeconds : 1.7149279
TotalMilliseconds : 1714.9279
I'd like to calculate the time my script runs, but my result from get-date is in totalseconds.
How can I convert this to 31:14:12 behing hours:minutes:seconds?
PS> $ts = New-TimeSpan -Seconds 1234567
PS> '{0:00}:{1:00}:{2:00}' -f $ts.Hours,$ts.Minutes,$ts.Seconds
06:56:07
or
PS> "$ts" -replace '^\d+?\.'
06:56:07
All you have to do is use the Measure-Command cmdlet to get the time:
PS > measure-command { sleep 5}
Days : 0
Hours : 0
Minutes : 0
Seconds : 5
Milliseconds : 13
Ticks : 50137481
TotalDays : 5.80294918981481E-05
TotalHours : 0.00139270780555556
TotalMinutes : 0.0835624683333333
TotalSeconds : 5.0137481
TotalMilliseconds : 5013.7481
The above output itself might be good enough for you, or you can format it appropriately as the the output of Measure-Command is a TimeSpan object. Or you can use ToString:
PS > (measure-command { sleep 125}).tostring()
00:02:05.0017446