Let me brief out what all methods I tried.
Here is the Start_TestTalk.ps1 script
$RN = $env:RName
$TestV = "Local_Variable"
Write-Host $TestV
Write-Host $RName
Write-Host $RN
Write-Host $env:RName
I've declared the below variables
$Name="myname"
$CPU= 100
First Method:
PS C:\Users\Administrator> Invoke-Command -Session $s -Scriptblock{ & "C:\Users\Administrator\Desktop\Start_TestTalk.ps1
" -RName $args[0] -RCPU $args[1]}-argumentlist $Name,$CPU
Local_Variable
Second Method
PS C:\Users\Administrator> Invoke-Command -Session $s -Scriptblock{ & "C:\Users\Administrator\Desktop\Start_TestTalk.ps1
" -RName $using:Name -RCPU $using:CPU}
Local_Variable
Third Method
PS C:\Users\Administrator> Invoke-Command -Session $s -Scriptblock{ Param($Name, $CPU) & "C:\Users\Administrator\Desktop
\Start_TestTalk.ps1" -RName $Name -RCPU $CPU}-argumentlist $Name ,$CPU
Local_Variable
All the above three methods just prints the 'Local_Variable' which is local to the remote machine and doesn't print the variable that I pass from my local machine(here $Name).
You can use the :using variable prefix:
Invoke-Command -Session $s -Scriptblock{ & "C:\Users\Administrator\Desktop\Test.ps1" -RName $using:Name -RCPU $using:CPU}
I figured out the way on how this feature works with the help of a Senior Architect here in our company. The variables sent from the local(source machine) are not actually made local on the remote machine and these just get dumped as values on the remote machine and not as variables(you can't use variables). A simple example on how the above script which I had mentioned works
Start_TestTalk.ps1 script
$RN = $args[0]
$CPU= $args[1]
Write-Host $RN
Write-Host $CPU
Now use the same old Invoke Command with slight changes removing the variables earlier used to hold the values from local machine
Invoking the remote script using argument list
I've declared the below variables
$Name="myname"
$CPU= 100
PS C:\Users\Administrator\ Invoke-Command -Session $s -Scriptblock{ &
"C:\Users\Administrator\Desktop\Start_TestTalk.ps1" $args[0] $args[1] }-
argumentlist $Name,$CPU
myname
100
Now you see that you get the required output on the remote machine, so it conveys that the values are directly getting dumped and not with the variables and hence I was earlier not able to use those variables on the remote machine.
Related
$remoteinst = "\Windows\Temp\MyFolder"
$remotecomp = ComputerName
$remotesess = New-PSSession $remotecomp
$remotedir = "C:" + $remoteinst + "\Install.cmd"
Invoke-Command -Session $remotesess -ScriptBlock {$remotedir}
I'm trying to run the Install.cmd file on a remote computer. I realised I can't pass commands through Enter-PSSession but I'm struggling to solve this issue.
There's no need for creating an explicit session: you can pass the target computer name directly to Invoke-Command -ComputerName <computerName>.
Invoking a command whose name / path is stored in a variable requires &, the call operator.
The script block passed to Invoke-Command -ComputerName ... is executed remotely, so you cannot directly use local variables in it; in PSv3+, the simplest way to solve this problem is to use the using scope: $using:<localVarName>
Keeping all these points in mind, we get:
$remoteinst = "\Windows\Temp\MyFolder"
$remotecomp = ComputerName # Note: This syntax assumes that `ComputerName` is a *command*
$remotedir = "C:" + $remoteinst + "\Install.cmd"
Invoke-Command -ComputerName $remoteComp -ScriptBlock { & $using:remotedir }
Add cmd /c to the front of the path to the batch file.
I am trying to redirect the output of a .bat script to a file. The script is run on another machine.
The commented line works. The t.txt file is produced in the expected location. I cannot convince PowerShell to produce the output file when the ScriptBlock is used.
The current result is that the $sb text is printed to the PowerShell console running this script. No file is produced on SERVER2. What do I need to get the output written to the file specified in the scriptblock?
$cn = 'SERVER2'
$Logfile = "D:\DBA\Scripts\monlogs\monlog_$(Get-Date -Format 'yyyy-MM-ddTHH-mm-ss').txt"
$sb = [scriptblock]::Create("{ & cmd.exe /C D:\DBA\Scripts\mon_test_001.bat >`"$Logfile`" }")
### Invoke-Command -ComputerName $cn -ScriptBlock { & D:\DBA\Scripts\mon_test_001.bat >D:\DBA\Scripts\monlogs\t.txt 2>&1 }
Invoke-Command -ComputerName $cn -ScriptBlock $sb
EDIT
After BenH's comment, I found the following to work as expected. Note that the parameter needed to have the $ escaped.
$sb = [scriptblock]::Create("param(`$Logfile) & cmd.exe /C D:\DBA\Scripts\mon_test_001.bat >`"$Logfile`"")
Rather than class create method, maybe casting would work? Then because you're running the scriptblock on a remote machine, use the "$using:" scope on the local variable. (PSv3+ onwards)
$cn = 'SERVER2'
$Logfile = "c:\temp\$(Get-Date -Format 'yyyy-MM-ddTHH-mm-ss').txt"
[scriptblock]$sb = { & cmd.exe /C c:\temp\test.bat > "$using:Logfile" }
Invoke-Command -ComputerName $cn -ScriptBlock $sb
Otherwise for earlier versions, you will need to use a param block and -ArgumentList:
[scriptblock]$sb = {param($logpath) & cmd.exe /C c:\temp\test.bat > "$logpath" }
Invoke-Command -ComputerName $cn -ScriptBlock $sb -ArgumentList $Logfile
I am trying to create a script that will take input (hardcoded values for now) and call an install PS script and run it on multiple servers. I am using a PSSession and Invoke-Command(see below). The below runs, but does nothing. It doesn't seem to call the other script. Beyond getting it to actually install, I need to know if it was successful or not. I'm pretty novice at Powershell, so any hints/help/suggestions would be great. The below is wrapped in a ForEach to loop the servers with $Computer
Try
{
$session = New-PSSession -ComputerName App02 -Credential $cred
$sourceInstall = $sourceFolder + 'Install\Install.ps1'
Invoke-Command -Session $session -ScriptBlock{param($serviceName, $installFolder, $sourceFolder, $Action, $username, $password) $sourceInstall} -ArgumentList ($ServiceName, $installFolder, $sourceFolder, $Action, $username, $password)
}
Catch
{
$Filename = "Error.txt"
Write-Output "ERROR: Partial Service Deployment. See error log file(s)"
Add-Content $Filename $_.Exception.Message
}
Get-PSSession | Remove-PSSession
You can use it without $Using statement in any version of PowerShell.But pass that too as an argument.
Eg:-
Invoke-Command -ScriptBlock
param($Name)
& $Command $Name
} -ArgumentList 'Get-Process','Notepad'
But you have to pass the arguments positional when using the call operator '&'
Get-Help About_Parameters
https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.core/about/about_parameters
Regards,
Kvprasoon
My powershell script is as below. I try to zip a folder at remote machine. I don't want to put Zip function inside ScriptBlock because it will be used in other parts of the script.
function Zip{
param([string]$sourceFolder, [string]$targetFile)
#zipping
}
$backupScript = {
param([string]$appPath,[string]$backupFile)
If (Test-Path $backupFile){ Remove-Item $backupFile }
#do other tasks
$function:Zip $appPath $backupFile
}
Invoke-Command -ComputerName $machineName -ScriptBlock $backupScript -Args $appPath,$backupFile
In $backupScript, it is giving error in $function:Zip line:
+ $function:Zip $appPath $backupFile
+ ~~~~~~~~
Unexpected token '$appPath' in expression or statement.
You have to refer to arguments in a scriptblock like:
$backupScript = {
param([string]$appPath,[string]$backupFile)
If (Test-Path $backupFile){ Remove-Item $backupFile }
#do other tasks
$function:Zip $args[0] $args[1]
}
Invoke-Command -ComputerName $machineName -ScriptBlock $backupScript -Args $appPath,$backupFile
Also, the function will not be known by the target machine, you'll have to define it within the script-block or pass it to the machine.
Here is an example:
How do I include a locally defined function when using PowerShell's Invoke-Command for remoting?
This example puts it in your perspective:
PowerShell ScriptBlock and multiple functions
I would find some way of getting your shared functions onto your server. We have a standard share on all our servers where we deploy common code. When we run code remotely, that code can then reference and use the shared code.
I have written the following code
$sb = {
. .\Myfunctions.ps1
$x = MyFunction1
$y = MyFunction2
$x + $y
}
$cred = Get-Credential "domain\user"
Invoke-Command -Computer localhost -Credentials $cred -ScriptBlock $sb
This does not work because it says The term .\MyFunctions.ps1 is not recognized as commandlet
Why can't I include a file inside a script block?
The problem is that the $pwd (current directory) in the script block is different from the actual console path casued this because you are using invoke-command with -computer parameter is like you are do it in a remoting session. Try to put full path to your script to call it or just use ( if locally) & $sb