Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Scripting for Performance in PowerShell
ms.date: 05/07/2024
ms.date: 12/05/2024
title: PowerShell scripting performance considerations
---

Expand Down Expand Up @@ -627,6 +627,67 @@ Unwrapped = 42.92 ms
The unwrapped example is **372 times faster**. Also, notice that the first implementation requires
the **Append** parameter, which isn't required for the later implementation.

## Object creation

Creating objects using the `New-Object` cmdlet can be slow. The following code compares the
performance of creating objects using the `New-Object` cmdlet to the `[pscustomobject]` type
accelerator.

```powershell
Measure-Command {
$test = 'PSCustomObject'
for ($i = 0; $i -lt 100000; $i++) {
$resultObject = [PSCustomObject]@{
Name = 'Name'
Path = 'FullName'
}
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds

Measure-Command {
$test = 'New-Object'
for ($i = 0; $i -lt 100000; $i++) {
$resultObject = New-Object -TypeName PSObject -Property @{
Name = 'Name'
Path = 'FullName'
}
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
```

```Output
Test TotalSeconds
---- ------------
PSCustomObject 0.48
New-Object 3.37
```

PowerShell 5.0 added the `new()` static method for all .NET types. The following code compares the
performance of creating objects using the `New-Object` cmdlet to the `new()` method.

```powershell
Measure-Command {
$test = 'new() method'
for ($i = 0; $i -lt 100000; $i++) {
$sb = [System.Text.StringBuilder]::new(1000)
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds

Measure-Command {
$test = 'New-Object'
for ($i = 0; $i -lt 100000; $i++) {
$sb = New-Object -TypeName System.Text.StringBuilder -ArgumentList 1000
}
} | Select-Object @{n='Test';e={$test}},TotalSeconds
```

```Output
Test TotalSeconds
---- ------------
new() method 0.59
New-Object 3.17
```

## Use OrderedDictionary to dynamically create new objects

There are situations where we may need to dynamically create objects based on some input, the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: What's New in PowerShell 7.5
description: New features and changes released in PowerShell 7.5
ms.date: 11/18/2024
ms.date: 12/05/2024
---

# What's New in PowerShell 7.5
Expand Down Expand Up @@ -151,6 +151,102 @@ The following experimental features are included in PowerShell 7.5-rc.1:
- [PSSerializeJSONLongEnumAsNumber][06] - `ConvertTo-Json` now treats large enums as numbers
([#20999][20999]) (Thanks @jborean93!)

## Performance improvements

PowerShell 7.5-rc.1 included [PR#23901][23901] from @jborean93 that improves the performance of the
`+=` operation for an array of objects.

The following example measures the performance for different methods of adding elements to an array.

```powershell
$tests = @{
'Direct Assignment' = {
param($count)

$result = foreach($i in 1..$count) {
$i
}
}
'List<T>.Add(T)' = {
param($count)

$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result.Add($i)
}
}
'Array+= Operator' = {
param($count)

$result = @()
foreach($i in 1..$count) {
$result += $i
}
}
}

5kb, 10kb | ForEach-Object {
$groupResult = foreach($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value -Count $_ }).TotalMilliseconds

[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}

[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}

$groupResult = $groupResult | Sort-Object TotalMilliseconds
$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds / $groupResult[0].TotalMilliseconds
$speed = [math]::Round($relativeSpeed, 2).ToString() + 'x'
if ($speed -eq '1x') { $speed } else { $speed + ' slower' }
}
} | Format-Table -AutoSize
}
```

When you run the script in PowerShell 7.4.6, you see that using the `+=` operator is the slowest
method.

```Output
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
5120 Direct Assignment 4.17 1x
5120 List<T>.Add(T) 90.79 21.77x slower
5120 Array+= Operator 342.58 82.15x slower


CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
10240 Direct Assignment 0.64 1x
10240 List<T>.Add(T) 184.10 287.66x slower
10240 Array+= Operator 1668.13 2606.45x slower
```

When you run the script in PowerShell 7.5-rc.1, you see that using the `+=` operator is much faster
than PowerShell 7.4.6. Now, it's also faster than using the `List<T>.Add(T)` method.

```Output
CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
5120 Direct Assignment 4.71 1x
5120 Array+= Operator 40.42 8.58x slower
5120 List<T>.Add(T) 92.17 19.57x slower


CollectionSize Test TotalMilliseconds RelativeSpeed
-------------- ---- ----------------- -------------
10240 Direct Assignment 1.76 1x
10240 Array+= Operator 104.73 59.51x slower
10240 List<T>.Add(T) 173.00 98.3x slower
```

<!-- end of content -->
<!-- reference links -->
[chg]: https://github.com/PowerShell/PowerShell/blob/master/CHANGELOG/preview.md
Expand Down