Behind the PowerShell Pipeline logo

Behind the PowerShell Pipeline

Subscribe
Archives
June 24, 2025

A Prime Scripting Solution

Last month, I left you with what I hope was a fun PowerShell scripting challenge. My goal for the challenge was to provide you with an opportunity to utilize a few common PowerShell scripting constructs. The challenges revolved around prime numbers.

  • Using PowerShell, calculate the first 50 prime numbers.
  • Using the list of prime numbers, create another list of the differences between each prime number and the next.
  • Display the sum of each pair of prime numbers.
  • Get the sum of the first and last prime numbers in your list, then the second and second to last, etc.

You can use the list of prime numbers at https://en.wikipedia.org/wiki/List_of_prime_numbers to verify your results.

How did you do?

Test-IsPrime

The first thing I did was to write a simple function to test if a number is prime. I wanted to use this function to generate a list of prime numbers. The function takes an integer greater than or equal to 2 and returns $true if the number is prime and $false otherwise.

function Test-IsPrime {
    [CmdletBinding()]
    [Alias('tip')]
    [OutputType([bool])]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            HelpMessage = 'Enter an integer greater than 2 to test if it is prime'
        )]
        [ValidateScript({ $_ -ge 2 }, ErrorMessage = 'Expected a number greater than or equal to 2')]
        [int]$Number
    )
    Process {
        for ($i = 2; $i -le [math]::Sqrt($number); $i++) {
            if ($number % $i -eq 0) {
                return $false
            }
        }
        $true
    }
}

The function attempts to divide the number by all integers from 2 up to the square root of the number. If any division results in a remainder of zero, the function returns $false, indicating that the number is not prime. If no such divisor is found, it returns $true. I shouldn't have to test dividing by a number beyond the square root of the number.

The function accepts pipeline input so that I can use it like this:

PS C:\> 2..10 | where {tip $_}
2
3
5
7

Building the List of Primes

Armed with this function, I can create a list of the first 50 prime numbers. I can use a simple loop to do this, starting with the first prime number, 2, and continuing until I have 50 primes in the array.

$count = 50
$i = 2
$primes = @()
do {
    if (Test-IsPrime -Number $i) {
        $primes += $i
    }
    $i++
} Until ($primes.Count -ge $count)

As an alternative to the array, you could also use a generic list.

$count = 50
$i = 2
$primes = [System.Collections.Generic.List[int]]::new()
do {
    if (Test-IsPrime -Number $i) {
        $primes.Add($i)
    }
    $i++
} Until ($primes.Count -ge $count)

This is slightly more efficient than using an array. The results are the same.

PS C:\> $primes.count
50
PS C:\> $primes -join ","
2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229

Prime Differences

To calculate the differences between each prime number and the next, I can use a simple loop that iterates through the list of primes and calculates the difference between each pair of consecutive primes.

$differences = @()
for ($k = 1; $k -lt $primes.Count; $k++) {
    $differences += $primes[$k] - $primes[$k - 1]
}

I am looping through the list of primes and referencing the current and previous prime numbers to calculate the difference using the index number in brackets. Because arrays are zero-based, I start at one and go to the end of the array. The result is a list of differences between each prime number and the next.

PS C:\> $differences -join ","
1,2,2,4,2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,14,4,6,2,10,2,6,6,4,6,6,2,10,2,4,2,12,12,4,2

Prime Sums

Calculating the sums is essentially the same. In this situation, I would like to start counting from zero. Also note that I'm incrementing by two so I can get pairs of primes.

$sumPairs = @()
for ($l = 0; $l -lt $primes.Count; $l += 2) {
    $sumPairs += $primes[$l] + $primes[$l + 1]
}

This syntax, and the one I used for differences, is clear. However, I can assign the output of the For statement directly to a variable, which is a bit more concise.

$sumPairs = for ($l = 0; $l -lt $primes.Count; $l += 2) {
    $primes[$l] + $primes[$l + 1]
}

This is also a little faster because I'm not dealing with the overhead of array concatenation.

PS C:\> $sumpairs -join ","
5,12,24,36,52,68,84,100,120,138,152,172,198,210,222,258,276,300,320,340,360,384,396,434,456

Inward Sums

The sum of the sets heading inward is a little more complex. I need to get the first and last numbers from the list and then work my way inward. This is what it looks like conceptually:

PS C:\> $primes[0]+$primes[-1]
231
PS C:\> $primes[1]+$primes[-2]
230
PS C:\> $primes[2]+$primes[-3]
228

Here's one way to achieve this using a For loop:

$a = for ($i = 0; $i -lt $primes.Count / 2; $i++) {
    $primes[$i] + $primes[$primes.Count-1-$i]
}

Checking the results confirms the process.

PS C:\> $a[0..2]
231
230
228

Another way to do this is with a Do loop. I could write a 'Do/Until` loop.

$x = 50 #the number of primes in the list
$i = 0
$j = $x - 1
$b = do {
    ($primes[$i, $j] | Measure-Object -Sum).sum
    $i++
    $j--
} Until ($i -ge ($x / 2))

This might be a little easier to understand than the For loop. The results are the same.

PS C:\> $b[0..2]
231
230
228
``

Alternatively, instead of using `Measure-Object`, which incurs some overhead, I can simply add the two numbers together directly in the `Do` loop. This is a little more efficient.

```powershell
$x = 50
$i = 0
$j = $x - 1
$c = do {
    $primes[$i] + $primes[$j]
    $i++
    $j--
} Until ($i -ge $x / 25)

If you test, you'll see the results are the same.

Extra Silliness

Since I'm already on a roll, let me share some bonus code.

Get-Divisors

I thought it might be interesting to write a function that returns the divisors of a number. This is a simple function that takes an integer and returns an array of its divisors.

Function Get-Divisors {
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            HelpMessage = 'Enter an integer greater than 2 to get its divisors'
        )]
        [ValidateScript({ $_ -gt 2 }, ErrorMessage = 'Expected a number greater than 2')]
        [int]$Number
    )
    Process {
        for ($i = 1; $i -le $number; $i++) {
            if ($number % $i -eq 0) {
                $i
            }
        }
    } #process
}

Divisors of only one, and the number would indicate a prime number.

PS C:\> Get-Divisors 50
1
2
5
10
25
50
PS C:\> Get-Divisors 11
1
11

Here's a variation that runs a little faster.

Function Get-Divisors {
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            HelpMessage = 'Enter an integer greater than 2 to get its divisors'
        )]
        [ValidateScript({ $_ -gt 2 }, ErrorMessage = 'Expected a number greater than 2')]
        [int]$Number
    )
    Process {
        1..$Number | Where-Object { $Number % $_ -eq 0 }
    } #process
}

Running Get-Divisors 12345 with the original function took about 130ms. The second version, which utilizes the pipeline, takes 52 ms. I can get this down even further by using the Where() method instead of the Where-Object cmdlet.

Function Get-Divisors {
    [CmdletBinding()]
    param (
        [Parameter(
            Mandatory,
            ValueFromPipeline,
            HelpMessage = 'Enter an integer greater than 2 to get its divisors'
        )]
        [ValidateScript({ $_ -gt 2 }, ErrorMessage = 'Expected a number greater than 2')]
        [int]$Number
    )
    Process {
        (1..$Number).Where({ $Number % $_ -eq 0 })
    } #process
}

The same command now takes 19ms.

Measuring Numbers

I could always measure the collection of prime numbers.

PS C:\> $primes | Measure-Object -AllStats

Count             : 50
Average           : 102.34
Sum               : 5117
Maximum           : 229
Minimum           : 2
StandardDeviation : 69.9287129722776
Property          :

Prime Alphabet

For total silliness, I thought about getting prime alphabet characters. In other words, letters of the alphabet at prime number positions. There are only 26 letters in the English alphabet so that I can limit the numbers to 26 or fewer.

$letters = 'abcdefghijklmnopqrstuvwxyz'
$primes.where({ $_ -le 26 }).Foreach({ $letters[($_-1)] }) -join ','
#b,c,e,g,k,m,q,s,w

This gets a little tricky because we don't think of a as being the 0 letter of the alphabet. It is the first.

Summary

The sole purpose of these exercises is to flex your PowerShell scripting muscles. In some cases, the exercise may force you to learn something new. The more you work with the language and syntax, the easier it will be to apply it to your scripts and functions.

(c) 2022-2025 JDH Information Technology Solutions, Inc. - all rights reserved
Don't miss what's next. Subscribe to Behind the PowerShell Pipeline:
Start the conversation:
GitHub Bluesky LinkedIn About Jeff
Powered by Buttondown, the easiest way to start and grow your newsletter.