4

Good evening.

I'm trying to use parallelism for the first time but I don't understand how to call a function within foreach loop.

I get a series of this error: Cannot bind argument to parameter 'Path' because it is null.

This is what I've done so far:


$FolderPath = "C:\myfolder\"

function AppendLog ($client) {
    $so = New-CimSessionOption -Protocol 'DCOM'
    $s = New-CimSession -ComputerName $client -SessionOption $so
    Add-Content -Path (join-path $folderpath "LOGS.txt") -Value ( (get-date -Format "[yyyy.MM.dd HH:mm:ss]").tostring() + $client + " -PING: OK")
    $arch = Get-CimInstance –query "select * from win32_operatingsystem" -CimSession $s | select -expandproperty osarchitecture
    Add-Content -Path (join-path $folderpath "LOGS.txt") -Value ( (get-date -Format "[yyyy.MM.dd HH:mm:ss]").tostring() + $client + " -ARCH:" + $arch )   
    $lastboot = Get-CimInstance –query "select * from win32_operatingsystem" -CimSession $s | select -expandproperty lastbootuptime
    Add-Content -Path (join-path $folderpath "LOGS.txt") -Value ( (get-date -Format "[yyyy.MM.dd HH:mm:ss]").tostring() + $client + " -BOOT:" + $lastboot )   

}



$funcDef = $function:AppendLog.ToString()

$clients = get-content -path (join-path $folderPath "client.txt")
$clients | ForEach-Object -parallel  {

    if (test-connection $_ -count 2 -Quiet) 
            {                              
                $function:AppendLog = $using:funcDef
                AppendLog ($_)
            }
     }       -throttlelimit 3

Could you explain me how to pass my path?
2
  • 2
    Try with $using:_. By the way, you can establish a CimSession with multiple computers as well as query multiple computers at the same time with CimInstace which is far more efficient than ForEach -Parallel. Commented Jun 19, 2021 at 21:18
  • 1
    You should be able to just use AppendLog $_ without the parenthesis around the psitem ($_). To include attempting to expand it Commented Jun 19, 2021 at 21:27

1 Answer 1

4

My bad on the comment, the error you're getting is most likely coming from your function. The error is being thrown by Join-Path:

PS /> Join-Path $null 'Logs.txt'
Join-Path : Cannot bind argument to parameter 'Path' because it is null.
At line:1 char:11
+ Join-Path $null 'Logs.txt'
+           ~~~~~
    + CategoryInfo          : InvalidData: (:) [Join-Path], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.JoinPathCommand

The reason is because $FolderPath doesn't exist in the scope of your parallel loop. $folderpath should be replace with $using:folderpath inside your function.


As a side note, adding information to the same file on a parallel execution doesn't seem to be a good idea.


Last edit, I understand if this is meant to test how ForEach-Object -Parallel works but again, if the cmdlet allows remote querying / remote execution with multiple hosts at the same time, let the cmdlet handle that for you, it is more efficient.

As for the code, this is what I would use with what you already have:

$FolderPath = "C:\myfolder\"
$sessionOption = New-CimSessionOption -Protocol 'DCOM'

$clients = Get-Content -Path (Join-Path $FolderPath -ChildPath "Client.txt")
$results = $clients | ForEach-Object -Parallel {

    $out = @{
        Time = [datetime]::Now.ToString('[yyyy.MM.dd HH:mm:ss]')
        ComputerName = $_
    }

    if ($ping = Test-Connection $_ -Count 2 -Quiet)
    {
        $session = New-CimSession -ComputerName $_ -SessionOption $using:sessionOption
        $OSInfo = Get-CimInstance -CimSession $session -ClassName win32_operatingSystem
        Remove-CimSession $session
    }

    $out.Ping = $ping
    $out.Arch = $OSInfo.OSArchitecture
    $out.LastBoot = $OSInfo.LastBootUpTime

    [pscustomobject]$out

} -ThrottleLimit 3

$results | Export-Csv "$myFolder\LOGS.csv" -NoTypeInformation

This will output an object like this below:

Time                  ComputerName   Ping   OSArchitecture LastBoot             
----                  ------------   ----   -------------- --------             
[2021.06.19 20:06:00] ComputerName01 True   64-bit         6/16/2021 11:47:16 AM
[2021.06.19 20:07:00] ComputerName02 False
[2021.06.19 20:08:00] ComputerName03 True   64-bit         6/13/2021 11:47:16 AM
[2021.06.19 20:09:00] ComputerName04 True   64-bit         6/14/2021 11:47:16 AM
[2021.06.19 20:10:00] ComputerName05 True   64-bit         6/15/2021 11:47:16 AM

Which can be exported nicely to a CSV instead of a text file. P.D.: sorry for the syntax highlighting :(

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Santiago both for the alternative code that for the advice of $using. You wrote that is a bad idea but my code was just a simple example. I have a script with a lot of functions that has to copy file to several clients and has to do a lot of operations. The script works but I'd like to speed up it and this is the reason why I want to use parallelism calling those functions.
Thanks again Santiago for you kindness. Have a nice Sunday.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.