I have very simple powershell script that starts service remotely.
Invoke-Command -Session $session -ScriptBlock { Start-Service "My test service v1" }
works fine but
$myval="My test service v1"
Invoke-Command -Session $session -ScriptBlock { Start-Service $myval }
fails with
Cannot validate argument on parameter 'InputObject'. The argument is
null or empty. Supply an argument that is not null or empty and then
try the command again.
+ CategoryInfo : InvalidData: (:) [Start-Service], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.StartServiceCommand
+ PSComputerName : mdfiletest
To me they are the same. Why is this not working? thanks
It does not work because when the scriptblock is executed on the remote server, the variable $myval does not exist in session state; it only exists on the local (client) side. The powershell v2/v3 compatible way to do this is:
invoke-command -session $session -scriptblock {
param($val); start-service $val } -args $myval
Another powershell v3 (only) way is like this:
invoke-command -session $session -scriptblock { start-service $using:myval }
The $using prefix is a special pseudo-scope which will capture the local variable and try to serialize it and send it remotely. Strings are always serializable (remotable.)
Related
hi i' m trying to retrieve the vhdx of specified vmname from the remote host server
here part of the script
$pth="C:\path\resize-vm"
$list=gc $pth\list-host.txt
foreach ($hostserver in $list) {
$vm=(Invoke-Command -ComputerName $hostserver -ScriptBlock {Get-VM}).VMName
Write-Host -NoNewline " here the vm installed in " $hostserver `r`n $vm
$vmname=Read-Host -Prompt "please chose a vmname to resize "
#the issue in the last line
$pathvhd=Invoke-Command -ComputerName $hostserver -ScriptBlock {(Get-VMHardDiskDrive -VMName $vmname).path}
When I launch this command $vmname="dc-kozhan"
I am getting this error
Cannot validate argument on parameter 'VMName'. The argument is null
or empty. Provide an argument that is not null or empty, and then try
the command again.
+ CategoryInfo : InvalidData: (:) [Get-VMHardDiskDrive], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.HyperV.PowerShell.Commands.GetVMHardDiskDrive
Command
+ PSComputerName : h-uludag-3
But when I specified dc-kozhan literally it work
PS C:\Users> Invoke-Command -ComputerName $hostserver -ScriptBlock {(Get-VMHardDiskDrive -VMName "DC-KOZAHAN")
.path}
V:\DC-KOZAHAN\DC-KOZAHAN-SYSTEM.vhdx
V:\DC-KOZAHAN\DC-KOZAHAN-DIRECTORY.vhdx
V:\DC-KOZAHAN\DC-KOZAHAN-SYSVOL.vhdx
V:\DC-KOZAHAN\DC-KOZAHAN-BACKUP.vhdx
does anyone have an idea why it does not work when it's specified in a variable
You need to understand how to pass arguments inside the scriptblock. The scope is different when you try to pass the value inside the scriptblock. As a result, $VMname is becoming null in your first statement.
Kindly change your existing Invoke-command statement to the below one:
Invoke-Command -ComputerName $hostserver -ScriptBlock {Param([string]$vmname)(Get-VMHardDiskDrive -VMName $vmname)} -ArgumentList $vmname
Also, my suggestion for you to read about the argumentlist in powershell in case invoke-command
Hope it helps.
I have something like this:
workflow WF {
foreach -Parallel ($computer in $computers) {
$results = InlineScript {
$session = New-PSSession -ComputerName $Using:computer
return Invoke-Command -Session $session -ScriptBlock {
Write-Host "Test"
}
}
}
}
When I run this, I'll get an error:
A command that prompts the user failed because the host program or the command
type does not support user interaction. Try a host program that supports user
interaction, such as the Windows PowerShell Console or Windows PowerShell ISE,
and remove prompt-related commands from command types that do not support user
interaction, such as Windows PowerShell workflows.
+ CategoryInfo : NotImplemented: (:) [Write-Host], HostException
+ FullyQualifiedErrorId : HostFunctionNotImplemented,Microsoft.PowerShell.Commands.WriteHostCommand
+ PSComputerName : [localhost]
How can I get the Write-Host output to the computer running the script? Note that I'm returning something else inside the ScriptBlock so I cannot just return the string and Write-Host it.
You can use Inline
inlineScript
{
Write-Host "Allow"
}
I am able to do
Invoke-Command -ScriptBlock { Z:\prog.bat }
However, when I do
Invoke-Command -ScriptBlock { Z:\prog.bat } -AsJob
I keep getting
Invoke-Command : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
+ Invoke-Command -ScriptBlock { z:\prog.bat } - ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-Command], ParameterBindingException
+ FullyQualifiedErrorId : AmbiguousParameterSet,Microsoft.PowerShell.Commands.InvokeCommandCommand
My intention is to run Z:\Prog.bat in the background since I will be executing this thru Ansible
Per the comments, this error message is telling you that it's not possible for PowerShell to know which Parameter Set you are trying to use. A Parameter Set is a collection of Parameters that are used together, some mandatory and some optional. Some cmdlets have a single set, some cmdlets have different combinations allowing them to be used in different ways.
You are using -ScriptBlock and -AsJob. Invoke-Command has quite a large number of Parameter Sets and to make your call of these parameters unique you need to use them with one of these parameters:
-Session
-ComputerName
-ConnectionUri
-VMId
-VMName
-ContainerID
E.g:
Invoke-Command -ScriptBlock { Z:\prog.bat } -AsJob -Computername SomeComputer
Alternatively if you're just attempting to run a script block as a background job on your local machine, don't use Invoke-Command instead consider using Start-Job:
Start-Job { Z:\prog.bat }
I'm trying to get the Invoke-Command cmdlet working with a CredSsp session by passing a locally defined function.
I have two local functions:
MyCopy which just invokes Copy-Item cmdlet on passed params with additional switches
MyCopyReturn which is the same as above, but in addition has return statement at the end
Now when I pass those functions to Invoke-Command without -Session parameter, they both succeed.
However, when specifying -Session for Invoke-Command, MyCopy fails with following exception (2. case):
Cannot bind argument to parameter 'Path' because it is null.
+ CategoryInfo : InvalidData: (:) [Copy-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand
+ PSComputerName : localhost
Could someone please explain why result of passing MyCopyReturn is different from passing MyCopy?
function MyCopy ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
}
function MyCopyReturn ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
return
}
$credential = Get-Credential
$computerName = 'localhost'
$session = New-PSSession -ComputerName $computerName -Credential $credential -Authentication Credssp
# src is a file
$src = "c:\sandbox\a\test"
# dest is a directory
$dest = "c:\sandbox\b"
# 1.
# MyCopy works fine without giving session
Invoke-Command -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 2.
# MyCopy DOESN'T WORK when session is given
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 4.
# MyCopyReturn works fine without the session
Invoke-Command -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
# 3.
# MyCopyReturn works fine with session too
Invoke-Command -Session $session -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
Remove-PSSession $session
I make some digging with ILSpy and can say, that the problem in the bug in ScriptBlock.GetPowerShell method. It does not bind parameters properly, if them come not from param block:
function f($Arg){write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
function g{param($Arg) write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
$Function:f.GetPowerShell('Test1','Test2').Invoke()
# $Arg="";$Args="Test1 Test2"
$Function:g.GetPowerShell('Test1','Test2').Invoke()
# $Arg="Test1";$Args="Test2"
As you can see, $Function:f.GetPowerShell('Test1','Test2') bind both arguments to $Args automatic variable and nothing get bound to $Arg. So when you invoke this command
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
$from and $to does not get bound properly and cause error.
Why error does not happens when you not use -Session parameter?
Looks like Invoke-Command have to convert ScriptBlock to PowerShell to invoke command in remote session and that does not required when ScriptBlock invoked locally.
Why MyCopyReturn does not cause same error?
Not all ScripBlocks can be converted to PowerShell by GetPowerShell method (in particular, it is required that ScriptBlock must have a single statement, having another statement return violate this). If that is the case (GetPowerShell throws ScriptBlockToPowerShellNotSupportedException), than Invoke-Command use some backup scenario to convert ScriptBlock to PowerShell and that scenario does not suffer from bug of GetPowerShell method.
I'm using PSRemoting with the WebAdministration module to get info about various sites, and it's working. I am, however, receiving an annoying non-fatal COM exception during invocation of the command, and wondering if anyone else has resolved it. Here's a minimal implementation:
cls
$command = {
param($alias)
Import-Module 'WebAdministration'
$binding = Get-WebBinding -HostHeader $alias
$binding
}
$server = 'server'
$args = #('alias')
$session = New-PSSession -ComputerName $server
Write-Host ("Invoking")
try {
Invoke-Command -Session $session -ScriptBlock $command -ArgumentList $args
Write-Host ("Invoked")
} catch {
Write-Host ("Caught $_")
} finally {
Write-Host ("Removing")
Remove-PSSession -Session $session
Write-Host ("Removed")
}
And here are the results:
Invoking
protocol : http
bindingInformation : 10.x.x.x:80:alias
...
Schema : Microsoft.IIs.PowerShell.Framework.ConfigurationElementSchema
An unhandled COM interop exception occurred: Either the application has not called WSAStartup, or WSAStartup failed. (Exception from HRESULT: 0x800
7276D)
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : COMException
Invoked
Removing
Removed
I observe the result is returned prior to the error being thrown.
Amusing details:
- Get-Website, Get-Item "IIS:\...", Get-WebBinding all result in the same error
- Running $command directly on the target machine as written results in no error
- Get-Item "d:\..." does not result in any error
- The COM error doesn't
I was able to work around the issue using the following:
$iisIpAddresses = Invoke-Command -Session $session -scriptblock {
if (!(Get-Module WebAdministration))
{
Import-Module WebAdministration
}
$iisBindings = Get-WebBinding
[String[]]$iisBindings = $iisBindings | Select bindingInformation
$iisBindings
}
Remove-PSSession $session
This is buried somewhere deep in the bowels of PowerShell's implementation of .NET and winsock. It's below anything I can calibrate, so I've added " -ErrorAction SilentlyContinue" to my remote invoke. It doesn't fix anything, but everything works correctly. That's answer enough for now, I guess.