invoke-expression inside scriptblock of invoke-command not working - powershell

I've got the following script
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\User Tool\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
This not working, however, if I move the usertool to c:\pss\, it works fine.
$name = (Invoke-Command -ComputerName "STW111" -Credential $cred -ScriptBlock { Invoke-Expression "C:\PSS\UserTool.exe"} -AsJob).Name
Wait-Job -Name $name
I really need to get to grips with escaping in Powershell.
Any ideas?
TIA

try this:
Invoke-Expression "& 'C:\PSS\User Tool\UserTool.exe'"

Related

Invoke-Command with remote session: Cannot validate argument on parameter

I wrote a script to restart a few ASP.NET websites on a remote server:
$computerName = #...
$password = #...
$secureStringPassword = ConvertTo-SecureString -AsPlainText -Force -String $password
$userName = #...
$credential= New-Object System.Management.Automation.PSCredential ($userName, $secureStringPassword)
$websiteNames = #..., #..., #...
Get-PSSession -ComputerName $computerName -Credential $credential | Remove-PSSession
$psSession = New-PSSession -ComputerName $computerName -Credential $credential
Invoke-Command -Session $psSession -ScriptBlock { $websiteNames | foreach{ Stop-Website -Name $_ } }
Invoke-Command -Session $psSession -ScriptBlock { $websiteNames | foreach{ Start-Website -Name $_ } }
$psSession | Remove-PSSession
For some reasons my Invoke-Command do not run properly, I have the following error message:
Cannot validate argument on parameter 'Name'. The argument is null. Provide a valid value for the argument, and then try running the command again.
When the commands are run after an Enter-PSSession it works fine within a -ScriptBlock it kinda mess up the -Name parameter, any idea how to fix that up?
The remote session cannot access the variables you have defined locally. They can be referenced with $using:variable
Invoke-Command -Session $psSession -ScriptBlock { $using:websiteNames | foreach{ Stop-Website -Name $_ } }
Invoke-Command -Session $psSession -ScriptBlock { $using:websiteNames | foreach{ Start-Website -Name $_ } }
More information in the about_remote_variables help:
get-help about_remote_variables -Full
Actually just needed to pass the arguments to the -ArgumentList of the -ScriptBlock and use $args to reference to it within the function block:
Invoke-Command -Session $psSession -ScriptBlock { $args | foreach{ Stop-Website -Name $_ } } -ArgumentList $websiteNames
Invoke-Command -Session $psSession -ScriptBlock { $args | foreach{ Start-Website -Name $_ } } -ArgumentList $websiteNames

PowerCLI PowerShell Jobs does not finish

I have the problem that a simple PowerShell Job does not complete. It will always be running.
I am trying the following:
$Job = Start-Job -Name "TestJob" -ScriptBlock {param($vcenter,$session) Connect-VIServer -Server $vcenter -Session $session; Get-VM -Name "VMName"} -ArgumentList $global:DefaultVIServer.Name,$global:DefaultVIServer.SessionSecret;
Hopefully some of you have an idea what I am doing wrong.
Thanks in advance.
Found the solution. I cannot explain it but if you write the return of Get-VM in a variable the job will finish normally.
$Job = Start-Job -Name "TestJob" -ScriptBlock {param($vcenter,$session) Connect-VIServer -Server $vcenter -Session $session; $t = Get-VM -Name "VMName"} -ArgumentList $global:DefaultVIServer.Name,$global:DefaultVIServer.SessionSecret;
Best regards

input objects in powershell jobs

I'm trying to implement a job in PowerShell that would look something like this:
$cred = Get-Credential
$job1 = Start-Job -InputObject $cred -ScriptBlock {
Get-ADUser -Credential $cred -Filter *
}
$res1 = Wait-Job -Job $job1 | Receive-Job
But I am receiving an error message:
"Wait-Job : The Wait-Job cmdlet cannot finish working, because one or more jobs are blocked waiting for user interaction. Process interactive job output by using the Receive-Job cmdlet, and then try again.
....
Deadlock detected: (System.Manageme...n.PSRemotingJob:PSRemotingJob) [Wait-J
ob],
....
"
But if I create this seemingly identical job like this:
$job2 = Start-Job -ScriptBlock {
$pass = ConvertTo-SecureString "pass" -AsPlainText -Force
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist "usr",$pass
Get-ADUser -Credential $cred -Filter *
}
$res2 = Wait-Job -Job $job2 | Receive-Job
Everything works perfectly.
Can you please help me understand why?
Thanks!
To pass arguments to the script block, you need to use the -ArgumentList parameter, not -InputObject. Try this:
$cred = Get-Credential
$job1 = Start-Job -ScriptBlock {PARAM($cred)
Get-ADUser -Credential $cred -Filter *
} -ArgumentList $cred
Note that -ArgumentList has to be the last parameter in the Start-Job command.
Well, this would probably be evident if you had but read the Help for Start-Job. If you use the -InputObject argument you then reference it from within the scriptblock with the automatic variable $Input. Since you reference $Cred out of scope like that it's trying to get credentials again. Here's the Help text for that parameter.
-InputObject <PSObject>
Specifies input to the command. Enter a variable that contains the objects, or type a command or expression that generates the objects.
In the value of the ScriptBlock parameter, use the $input automatic variable to represent the input objects.
You could alter your script to look like this and it should work fine:
$cred = Get-Credential
$job1 = Start-Job -InputObject $cred -ScriptBlock {
Get-ADUser -Credential $Input -Filter *
}
$res1 = Wait-Job -Job $job1 | Receive-Job

Running Batch Script on remote Server via PowerShell

I need to connect to some remote servers from a client (same domain as the servers) once connected, I need to run a batch file:
I've done so with this code:
$Username = 'USER'
$Password = 'PASSWORD'
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
try {
Invoke-Command -ComputerName "SERVER1" -Credential $Cred -ScriptBlock -ErrorAction Stop {
Start-Process "C:\Users\nithi.sundar\Desktop\Test.bat"
}
} catch {
Write-Host "error"
}
This script does not give any errors, but it doesn't seem to be executing the batch script.
any input on this would be greatly appreciated.
Try replacing
invoke-command -computername "SERVER1" -credential $Cred -ScriptBlock -ErrorAction stop { Start-Process "C:\Users\nithi.sundar\Desktop\Test.bat" }
with
Invoke-Command -ComputerName "Server1" -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'C:\Users\nithi.sund
ar\Desktop\Test.bat'"}
It's not possible that the code you posted ran without errors, because you messed up the order of the argument to Invoke-Command. This:
Invoke-Command ... -ScriptBlock -ErrorAction Stop { ... }
should actually look like this:
Invoke-Command ... -ErrorAction Stop -ScriptBlock { ... }
Also, DO NOT use Invoke-Expression for this. It's practically always the wrong tool for whatever you need to accomplish. You also don't need Start-Process since PowerShell can run batch scripts directly:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
C:\Users\nithi.sundar\Desktop\Test.bat
} -Credential $Cred -ErrorAction Stop
If the command is a string rather than a bare word you need to use the call operator, though:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
& "C:\Users\nithi.sundar\Desktop\Test.bat"
} -Credential $Cred -ErrorAction Stop
You could also invoke the batch file with cmd.exe:
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
cmd /c "C:\Users\nithi.sundar\Desktop\Test.bat"
} -Credential $Cred -ErrorAction Stop
If for some reason you must use Start-Process you should add the parameters -NoNewWindow and -Wait.
Invoke-Command -ComputerName "SERVER1" -ScriptBlock {
Start-Process 'C:\Users\nithi.sundar\Desktop\Test.bat' -NoNewWindow -Wait
} -Credential $Cred -ErrorAction Stop
By default Start-Process runs the invoked process asynchronously (i.e. the call returns immediately) and in a separate window. That is most likely the reason why your code didn't work as intended.

nested scriptblocks in a powershell remote session

I am trying to run a script block on a remote machine, but i don't to be prompted for credentials, i want to pass them in the script.
Some commands may but the commands i want to run are access denied unless i provide the credential.
for example this command can work:
Invoke-Command -Session $session -ErrorAction Stop -ErrorVariable $Error -Scriptblock {ls }
but this wont work unless -credential is passed (Invoke-Command on target)
Invoke-Command -Session $session -ErrorAction Stop -ErrorVariable $Error -Scriptblock {Invoke-Command -computername $Env:COMPUTERNAME -Credential $Cred -ScriptBlock {ls} }
the same way what i want to achieve causes access denied problem (starting a process)
Invoke-Command -Session $session -ErrorAction Stop -ErrorVariable $Error -Scriptblock {[System.Diagnostics.Process]::Start("C:\Myprocess.exe", $localArgs, "UserName", $credential.Password, "MyDomain")}
Invoke-Command -Session $session -ErrorAction Stop -ErrorVariable $setError -Scriptblock {$Domain = "domain";$PassSec = ConvertTo-SecureString $( "password") -AsPlainText -Force ; $Cred = New-Object -TypeName System.Management.Automation.PSCredential -argumentlist $($domain + "\" + "userName"),$passSec; Invoke-Command -computername $Env:COMPUTERNAME -Credential $Cred -ScriptBlock {C:\Myprocess.exe } }