PowerShell 7 - Create New PowerShell Instances

Introduction

PowerShell allows you to create multiple script instances using Start-Process and background jobs. This helps run tasks at the same time, making your script more efficient. Running long tasks can use a lot of memory and CPU, but by splitting tasks, you can manage them better.

Suppose we need to retrieve details from 10,000 SharePoint sites and update an SQL database table with this information. Fetching the complete list and library data from each site will take at least 10 minutes per site. This process is very time-consuming, and running such a lengthy PowerShell script would consume a lot of memory and likely result in an exception.

Here is a straightforward example of using Start-Process and scriptblock to execute tasks sequentially, ensuring one instance runs at a time.

Solution

Iterate through a loop of SharePoint sites to retrieve the details and send the required parameters as base64 string to the Start-Process cmdlet.

# Loop
{
    $Serialized = [System.Management.Automation.PSSerializer]::Serialize($SiteArguments)
    $Bytes = [System.Text.Encoding]::Unicode.GetBytes($Serialized)
    $Base64 = [Convert]::ToBase64String($Bytes)
    
    $scriptBlock = {
        param([String]$Base64)

        $Serialized = [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($Base64))
        $Arguments = [System.Management.Automation.PSSerializer]::Deserialize($Serialized)

        # script to connect to SharePoint (using app authentication), fetch details, and update the database
    }

    $command = "Invoke-Command -ScriptBlock {$scriptBlock} -ArgumentList $Base64"

    # Start a new PowerShell 7 process and pass the script block as an argument
    $process = Start-Process -Filepath $pwshPath -ArgumentList "-command ( $command )" -PassThru
    $processId = $process.Id

    while ($true) {
        try {
            # Get the process information
            $proc = Get-Process -Id $processId -ErrorAction Stop

            # Output the process status
            Write-Host "Process $($proc.Id) is running. CPU: $($proc.CPU), Memory: $($proc.WorkingSet / 1MB) MB"

        } catch [System.Management.Automation.ItemNotFoundException] {
            # If the process is not found, break the loop
            Write-Host "Process $processId is no longer running."
            break
        }

        # Wait for 800 seconds before the next check
        Start-Sleep -Seconds 800
    }
}

The result returned from Start-Process provides the process ID of the PowerShell session, which we can use to continuously monitor whether the task has been completed. Once it is completed, we can start executing the next site. This will ensure that only one new PowerShell instance is currently running.


Similar Articles