Powershell Invoke-Command not working in script - powershell

I'm a beginner with Powershell and while working on a script I ran into a very weird issue.
I have the following code which works as expected:
$deploymentMachine = Read-Host "Please enter the name of the machine on which you want to deploy: "
$deploymentMachineUsername = Read-Host "Please enter the username: "
$deploymentMachinePassword = Read-Host "Please enter your password: " -AsSecureString
$credentials = New-Object System.Management.Automation.PSCredential ($deploymentMachineUsername, $deploymentMachinePassword)
$remoteSession = New-PSSession -ComputerName $deploymentMachine -Credential $credentials -ErrorAction Stop
and then I'm trying to check for the existence of a folder on the remote machine using:
if(Invoke-Command -Session $remoteSession { Test-Path "C:\Test" })
which throws the following error:
Cannot bind argument to parameter 'Path' because it is null.
If I run the same code line by line in the Powershell everything works as expected and get true or false depending on what folder I test.
Can somebody tell me why the code fails in the script, but works in the command prompt? What am I missing?
Thank you!

After some more digging I managed to find answer: I need to pass local variables used by the script block using the -ArgumentList (in my script the "C:\Test" was stored in a variable)
So the code looks like this now:
if(Invoke-Command -Session $remoteSession -ScriptBlock { Test-Path -Path $args[0] } -ArgumentList $tmp)
Thanks for the help!

Related

Powershell Invoke-Command with file share

I have a Powershell script like this:
param([string]$zipFileLocation)
if([string]::IsNullOrEmpty($zipFileLocation))
{
write-host "No location provided"
return $false
}
write-host "Location of zip: $zipFileLocation"
write-host "Test-path result: $(test-path($zipFileLocation))"
write-host "END OF SCRIPT"
When I run this script locally, with as argument '\Server\Share', Test-Path returns true and all works fine. I.e. when I run '.\TestScript.ps1 -zipFileLocation '\\Server\Share' it works as expected.
However, if I run the command like this:
$remsession1 = New-PSSession -credential $credential -ComputerName $ServerName
$UnzipPackageResult= Invoke-Command -session $remsession1 -FilePath C:\Test\TestScript.ps1 -ArgumentList '\\Server\Share'
Then the 'test-path' in the script comes back with $false and an UnauthorizedAccessException error. I do not see why.
The provided credentials do have administrator rights on the server.
Any thoughts?

pssession, invoke-command not getting variable

So here's the code I have so far:
$computerName = read-host "Enter Computer Name"
$IPCName = read-host "Enter IPC Profile name"
$uName = read-Host "Enter SU account"
$pw = read-host "Password"
$pwe = convertto-securestring -AsPlainText -Force -String $pw
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "CHILDRENS\$uName",$pwe
[string]$ipcdevcmd="FREEFORMDEVICENAME=`"$IPCName`""
[string]$tftp1='TFTP1="10.200.254.69"'
[string]$tftp2='TFTP2="172.16.90.205"'
$arrayofargs= ('/i','C:\IPCommunicator\CiscoIPCommunicatorSetup.msi','/qn',$ipcdevcmd,$tftp1,$tftp2)
$rtn = Test-Connection -CN $computerName -Count 1 -BufferSize 16 -Quiet
IF($rtn -match 'TRUE'){
echo 'machine Pings'
$session = New-PSSession -ComputerName $computerName -credential $cred
echo 'Testing Path'
$path = Invoke-Command -Session $session {Test-Path C:\IPCommunicator}
IF($path -match "False"){
echo "Need to make Directory"
Invoke-Command -Session $session {mkdir C:\IPCommunicator}
robocopy C:\IPCommunicator \\$computername\C$\IPCommunicator /MIR
echo 'Files Copied to New Directory'
}
ELSE {
robocopy C:\IPCommunicator \\$computername\C$\IPCommunicator /MIR
echo 'Files Copied to Existing Directory'
}
echo 'invoking install'
Invoke-Command -Session $session {Start-Process msiexec.exe -argumentlist $arrayofargs}
echo 'install invoked'
}
ELSE {
echo 'unable to ping system'
}
read-host "Press enter"
What I get back is:
invoking install(for reference)
"Cannot validate argument on parameter 'ArgumentList'. The argument is null or empty. Provide an argument that is not null or empty and then try the command again."
install invoked(for reference)
What I think is happening is that it is trying to use the machine local variables instead of the user supplied variables on the originating box.
The whole aim is to trigger an install that pre-sets certain variables thru the MSI arguments. Those are valid and from a batch with i can do it on the local pc just fine. When I try to pass those variables from MY computer running the script to the user's pc via invoke-command it is not seeing my locally set variables. How the heck do I pass them through.
Broken down by itself...
...returns my inputs for each of the arguments correctly, in a valid stringy form. Somehow that is getting lost in the invoke command. :/ not sure how to pass those variable over? Should I write to text and then move the file over and load it from the local pssession? There has to be a better way!
Because your are executing the command in another session, unless you define the variable in that other session it has no idea what you're talking about. To get around that use the $using: scope. That line then look like:
Invoke-Command -Session $session {Start-Process msiexec.exe -argumentlist $using:arrayofargs}

Call a remote script from another with multiple parameters not working

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

Include a PowerShell file inside a ScriptBlock

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

Powershell Invoke-Command executing on local, rather than remote server

I have a script that copies another script to a remote server then executes the 2nd script. This was working ok last week but today execution of the first script failed saying the 2nd script couldn't be found. As part of troubleshooting I created a simple version of the 2nd script (containing only Write-Host "Wrong Server!) on the local server. Now when I run the 1st script, the dummy 2nd script is executed on the local server!
I have pasted by test-harness script below:
$DeploymentFolderOnTargetServer = "c:\biztalkdeployment"
$TargetServer = "d-vasbiz01"
$Username = "TFS_Service"
$Password = "x"
$SecPass = ConvertTo-SecureString $Password -AsPlainText -Force
$Cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $Username,$SecPass
$Session = New-PSSession -ComputerName $TargetServer -Authentication CredSSP -Credential $Cred
$Environment = "Dev"
$ExecuteScriptFilePath = join-path "$DeploymentFolderOnTargetServer" "ExecuteBizTalkAppMSI.ps1"
$MSI = "bin\debug\x.int.mis-3.0.0.msi"
$InstallFolderOnTargetServer = "C:\Program Files (x86)\x.Int.MIS for BizTalk 2010\3.0"
Write-Host "Session = $Session"
Write-Host "ExecuteScriptFilePath = $ExecuteScriptFilePath"
Write-Host "MSI = $MSI"
Write-Host "InstallFolderOnTargetServer = $InstallFolderOnTargetServer"
Write-Host "Environment = $Environment"
Write-Host "DeploymentFolderOnTargetServer = $DeploymentFolderOnTargetServer"
Invoke-Command -Session $Session -FilePath $ExecuteScriptFilePath -argumentlist $MSI, $InstallFolderOnTargetServer, $Environment, $DeploymentFolderOnTargetServer
The output from the test is as follows:
Session = System.Management.Automation.Runspaces.PSSession
ExecuteScriptFilePath = c:\biztalkdeployment\ExecuteBizTalkAppMSI.ps1
MSI = bin\debug\x.int.mis-3.0.0.msi
InstallFolderOnTargetServer = C:\Program Files (x86)\Vasanta.Int.MIS for BizTalk 2010\3.0
Environment = Dev
DeploymentFolderOnTargetServer = c:\biztalkdeployment
Wrong Server!
If I run get-session then the Computer Name for the session is correctly pointing at the 2nd Server.
Any ideas?
The -FilePath parameter to Invoke-Command is specifying a local path to a script - not a path on the target computer. Invoke-Command will take care of getting the local script file over to the target computer so that it can execute there.