1

trying to pass a date from a remote computer to a function in my PS Script. but just gives me junk. from reading i saw that you can not use variables that were declared and intiated inside of a scriptblock on the outside. not sure how to get the date from these PCs. tried to use "$using" and also "$script" but that does not work. get-date works fine directly called to screen

    #Fucntion to manipulate the data
Function writeToServer
{
  param($server,$Time)

  # Data preparation for loading data into SQL table 
  $InsertResults = @"
  INSERT INTO [ServerTimeSync].[dbo].[ServerTimes](SystemName,ShownTimeOnServer)
  VALUES ('$SERVER','$Time')
  "@      
  #call the invoke-sqlcmdlet to execute the query
     Invoke-sqlcmd @params -Query $InsertResults
 }



  foreach ($COMPUTER in $COMPUTERS){ 
  icm $COMPUTER -ScriptBlock {$ENV:COMPUTERNAME

    $computer 
    get-date -Format "MM-dd-yyyy hh:mm:ss tt"

    $script:sdate = get-date -Format "MM-dd-yyyy hh:mm:ss tt"                        
    } 
      writeToServer $computer $script:sdate      
}
Edgar
  • 543
  • 10
  • 20
  • You do not need a format with get-date unless the date is a string. Without the format it will return a DateTime object. Try without Format. – jdweng Aug 22 '23 at 11:49
  • it didnt return anything just a 1900-01-01 date – Edgar Aug 22 '23 at 16:55

2 Answers2

3
  • You can only pass (the values of) local variables TO a remote command, via the $using: scope.

    • $using: references are embedded directly in the remote script block and are an alternative to passing values via arguments (parameters), using -ArgumentList - see this answer for examples. In both cases only the value of a local variable is getting passed, not the variable object itself.
  • The only way to report values FROM a remote command is to have it produce output, which you can capture in a variable on the caller's side ($output = Invoke-Command ...) or process in a pipeline, as shown below.

    • That is, you fundamentally cannot set variables for the caller from a remote script block.

Note that the above applies to all out-of-runspace / cross-process calls, e.g. also to Start-Job - see this answer for details.

You can also streamline your command by using parallel processing:

Invoke-Command -ComputerName $COMPUTERS -ScriptBlock {
  Get-Date -Format "MM-dd-yyyy hh:mm:ss tt"
} | 
  ForEach-Object {
    writeToServer $_.PSComputerName $_      
  }

Note:

  • If you pass multiple computer names to Invoke-Command's -ComputerName parameter, processing occurs in parallel, but the ordering of the outputs isn't guaranteed to match the order in which the names were passed.

  • A ForEach-Object call is used to process each object received from the remote call, which inside the script block you can refer to via the automatic $_ variable.

  • PowerShell automatically decorates all output objects from a remote script block with ETS (Extended Type System) properties that reflect the invocation context; notably, .PSComputerName contains the name of the remote computer.

mklement0
  • 382,024
  • 64
  • 607
  • 775
0

This is how you utilize $using: correctly

$MyString = 'Test 123'
Invoke-Command . -ScriptBlock {Write-Output $MyString} # produces no output because $MyString is empty
Invoke-Command . -ScriptBlock {Write-Output $using:MyString} # produces correct output because $MyString contains the string

Output of the remote session can be captured as follows

$MyString = 'Test 123'
$Capture = Invoke-Command . -ScriptBlock {Write-Output $using:MyString}
Write-Host $Capture
David Trevor
  • 794
  • 1
  • 7
  • 22