Here is a piece of code that illustrates some of the challenges when writing remotable code:
function Get-Log($LogName='System', $ComputerName=$env:computername) { $code = { Get-EventLog -LogName $LogName -EntryType Error -Newest 5 } $null = $PSBoundParameters.Remove('LogName') Invoke-Command -ScriptBlock $code @PSBoundParameters }
The function Get-Log is supposed to return the latest 5 error events from an event log. It is designed to work both locally and remotely, using PowerShell Remoting as transport.
So it accepts an optional parameter -ComputerName. This parameter gets handed over to Invoke-Command through splatting: @PSBoundParameters binds the parameter -ComputerName to Invoke-Command only when the user really submitted it. Else, Invoke-Command runs the code locally. Note how the function removes the parameter -LogName from the variable $PSBoundParameters because this parameter should not get handed over to Invoke-Command.
Instead, $LogName is used inside the script block to select the event log to read.
And this is the problem: locally, the code runs. Once you submit -ComputerName, the code runs remotely (provided you enabled remoting on the target computer and have proper permissions). However, $LogName is empty because it is a local variable and not defined on the remote system.
In a previous tip you learned about the new prefix “using” to mark local variables in PowerShell v3. So if you changed this line…
$code = { Get-EventLog -LogName $Using:LogName -EntryType Error -Newest 5 }
…the code would run fine remotely, but now it would fail locally. The prefix “using” is allowed only in remote calls or in a workflow inlinescript statement.
One solution is to submit the local variable as argument to the script block. This piece of code works both locally and remotely:
function Get-Log($LogName='System', $ComputerName=$env:computername) { $code = { param($LogName) Get-EventLog -LogName $LogName -EntryType Error -Newest 5 $null = $PSBoundParameters.Remove('LogName') Invoke-Command -ScriptBlock $code.GetNewClosure() @PSBoundParameters -Argument $LogName } PS> Get-Log PS> Get-Log -computername storage1