I'm learning the powershell. Currently I have a tough requirement. I need to call an powershell script(ps1) in parallel from an powershell module(psm1). The ps1 task is like following
param(
[Parameter(Mandatory=$true)]
[String] $LogMsg,
[Parameter(Mandatory=$true)]
[String] $FilePath
)
Write-Output $LogMsg
$LogMsg | Out-File -FilePath $FilePath -Append
The FilePath is like "C:\Users\user\Documents\log\log1.log" And in the psm1 file, I use the runspacepool to do async task. Like the following demo
$MaxRunspaces = 5
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $MaxRunspaces)
$RunspacePool.Open()
$Jobs = New-Object System.Collections.ArrayList
Write-Host $currentPath
Write-Host $lcmCommonPath
$Filenames = @("log1.log", "log2.log", "log3.log")
foreach ($File in $Filenames) {
Write-Host "Creating runspace for $File"
$PowerShell = [powershell]::Create()
$PowerShell.RunspacePool = $RunspacePool
$FilePath = -Join("C:\Users\user\Documents\log\",$File)
$PowerShell.AddScript("C:\Users\user\Documents\foo.ps1").AddArgument($FilePath) | Out-Null
$JobObj = New-Object -TypeName PSObject -Property @{
Runspace = $PowerShell.BeginInvoke()
PowerShell = $PowerShell
}
$Jobs.Add($JobObj) | Out-Null
}
But there are two serious problem.
If the runspacepool has limitation for passing the parameters to ps1 file, is there any other solution to deal with the async task for powershell script? Thanks.
Can't pass the parameters to ps1 file.
Use AddParameter()
instead of AddArgument()
- this will allow you to bind the argument to a specific parameter by name:
$PowerShell.AddScript("C:\Users\user\Documents\foo.ps1").
AddParameter('FilePath', $FilePath).
AddParameter('LogMsg', 'Log Message goes here') | Out-Null
Can't get write-host information in ps1 file while psm1 is still running
Correct - you cannot get host output from a script not attached to the host application's default runspace - but if you're using PowerShell 5 or newer you can collect the resulting information from the $PowerShell
instance and relay that if you want to:
# Register this event handler after creating `$PowerShell` but _before_ calling BeginInvoke()
Register-ObjectEvent -InputObject $PowerShell.Streams.Information -EventName DataAdded -SourceIdentifier 'WriteHostRecorded' -Action {
$recordIndex = $EventArgs.Index
$data = $PowerShell.Streams.Information[$recordIndex]
Write-Host "async task wrote '$data'"
}