Passing an array as parameter from CMD to PowerShell give problems [duplicate] - powershell

This question already has an answer here:
Passing string[] from batch file (which contains double quotes ") to powershell script
(1 answer)
Closed 3 years ago.
I have problems to pass an array to PowerShell script as parameter from CMD.
Here an example of the PS code:
[CmdletBinding()]
Param(
[string[]]$serverArray,
)
$serviceName = 'service1'
function getState {
Process {
$serverArray
foreach ($server in $serverArray) {
$servState = (Get-WmiObject Win32_Service -ComputerName $server -Filter "name='$serviceName'").State
}
}
getState
How I call script from CMD:
powershell -file .\script.ps1 -serverArray Server1,Server2
I get an error because $serverArray is not passed an array:
Server1,Server2
Get-WmiObject : The RPC server is unavailable. (Exception from HRESULT:
0x800706BA)
At C:\script.ps1:58 char:29
+ $servState = (Get-WmiObject <<<< Win32_Service -ComputerName $server -Filter "name='$serviceName'").State
+ CategoryInfo : InvalidOperation: (:) [Get-WmiObject], COMException
+ FullyQualifiedErrorId : GetWMICOMException,Microsoft.PowerShell.Commands.GetWmiObjectCommand
If I run the same command from a PowerShell window it works because the script accepts $serverArray as an array:
.\script.ps1 -serverArray Server1,Server2
Server1
Server2

CMD doesn't know anything about PowerShell arrays. You can pass the server list as individual tokens
powershell -File .\script.ps1 Server1 Server2
and use the automatic variable $args instead of a named parameter in your script:
foreach ($server in $args) {
...
}
or you can split the value of the parameter at commas in the body:
[CmdletBinding()]
Param(
[string]$Servers
)
$serverArray = $Servers -split ','

You can run this from command prompt:
powershell script.ps1 "Server1,Server2"
And if you add more parameters to your script :
powershell script.ps1 "Server1,Server2" "parameter2 argument" "parameter3 argument"

Related

retrieve vhdx path from a remote server

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.

Passing PSRemotingJob Object as Parameter in Powershell 4.0

I'm writing a Powershell Cmdlet for which I need to pass in a PSRemotingJob
object as a parameter. The MCVE follows:
function My-Cmdlet {
[CmdletBinding()]
Param(
[Parameter(Position=0,
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true)]
[PSRemotingJob[]]$Job
)
BEGIN {}
PROCESS {
ForEach ($j in $Job) {
$j
}
}
END {}
}
The issue is that when I pass a job into the cmdlet, I get an error, as follows:
PS C:\Temp> Invoke-Command -AsJob -CN svr001 -Command {Start-Sleep 10} | My-Cmdlet
My-Cmdlet : Unable to find type [PSRemotingJob]. Make sure that the assembly that contains this type is loaded.
At line:1 char:63
+ Invoke-Command -AsJob -CN svr001 -Command {Start-Sleep 10} | My-Cmdlet
+ ~~~~~~~~~
+ CategoryInfo : InvalidOperation: (PSRemotingJob:TypeName) [], RuntimeException
+ FullyQualifiedErrorId : TypeNotFound
PS C:\Temp>
I realize that this should be a simple matter of substituting the correct object
type or fully-qualified object, but I've also tried using
[System.Management.Automation.PSRemotingJob] with the same results.
I'm using Powershell 4.0.
System.Management.Automation.PSRemotingJob is not public type and thus can not be expressed in PowerShell type syntax. But you can use its base public type instead: [System.Management.Automation.Job].

Property is empty when run through Invoke-Command

I am trying to individually monitor memory usage of a process (w3wp.exe) that has multiple instances of itself by filtering out a string found in the process' CommandLine property.
It works when I run this script locally:
$proc = (WmiObject Win32_Process -Filter "Name = 'w3wp.exe'" | Where-Object {$_.CommandLine -like "*SomeTextFromCl*"})
$id = $proc.ProcessId
$ws = [math]::round((Get-Process -Id $id).WS/1MB)
Write-Host $ws
However, when I try to run it remotely through Invoke-Command, I get an error telling that the Id property's value is null:
Cannot bind argument to parameter 'Id' because it is null.
+ CategoryInfo : InvalidData: (:) [Get-Process], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.GetProcessCommand
+ PSComputerName : RemoteServerName
My Invoke-Command syntax is:
Invoke-Command -ComputerName RemoteServerName -FilePath script.ps1 -Credential $mycredential
I'm sure it's simple but I'm back to PS after a long absence and I had a look around but couldn't find anything really helpful.
You are writing the answer to the console. You use the ps1 as a function, so you should use:
return $ws
instead of
write-host $ws

Run an executable with a parameter using Invoke-Command

I am trying to run an executable with a config file as a parameter using invoke-command through a PowerShell script.
Here is what I have so far in my PowerShell script:
$config = 'D:\EmailLoader\App.config'
invoke-command -ComputerName SERVER-NAME -ScriptBlock {param($config) & 'D:\EmailLoader\GetMailAndAttachment.exe' $config} -ArgumentList $config
I then Execute the PowerShell script with the following command:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy ByPass -File "D:\PowerShellScripts\Email.ps1"
And I get the following error:
Unexpected token 'config' in expression or statement.
At D:\PowerShellScripts\Email.ps1:3 char:121
+ invoke-command -ComputerName SERVER-NAME -ScriptBlock {param($config) 'D:\EmailLoader\GetMailAndAttachment.exe' $config <<<< } -ArgumentList $config
+ CategoryInfo : ParserError: (config:String) [], ParentContainsE rrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
The code looks like it should work. But the exception message is clearly missing the & symbol. I would check that first, because you are getting the exact same message I would anticipate to get when the & was missing. So maybe there is problem with the saved file, rather than with your code.
Side note: If you are on PowerShell 3.0 or newer you should consider using the $using: scope in the script block to avoid adding the param and -ArgumentList.
$config = 'D:\EmailLoader\App.config'
Invoke-Command -ComputerName SERVER-NAME -ScriptBlock {
&'D:\EmailLoader\GetMailAndAttachment.exe' $using:config
}
There is no need to pass $config as a parameter to a ScriptBlock. Also not needed to add the $config parameter twice. This should work:
$config = 'D:\EmailLoader\App.config'
Invoke-Command -ComputerName SERVER-NAME -ScriptBlock {&('D:\EmailLoader\GetMailAndAttachment.exe')} -ArgumentList #($config)

Powershell: Issue with & in scriptblock

I face an issue when I run the following command
$x = "c:\Scripts\Log3.ps1"
$remoteMachineName = "172.16.61.51"
Invoke-Command -ComputerName $remoteMachineName -ScriptBlock {& $x}
The expression after '&' in a pipeline element produced an invalid object. It must result in a command name, script
block or CommandInfo object.
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : BadExpression
+ PSComputerName : 172.16.61.51
Issue is not seen if I dont use $x variable
Invoke-Command -ComputerName $remoteMachineName -ScriptBlock {& 'c:\scripts\log3.ps1'}
Directory: C:\scripts
Mode LastWriteTime Length Name PSComputerName
---- ------------- ------ ---- --------------
-a--- 7/25/2013 9:45 PM 0 new_file2.txt 172.16.61.51
Variables in your PowerShell session are not transferred to sessions created with Invoke-Command
You need to use the -ArgumentList parameter to send the variables your command and then use the $args array to access them in the script block so your command will look like:
Invoke-Command -ComputerName $remoteMachineName -ScriptBlock {& $args[0]} -ArgumentList $x
If you work with variables inside a script block you need to add the modifier using:. Otherwise Powershell would search for the var definition inside the script block.
You can use it also with the splatting technique. E.g.:#using:params
Like this:
# C:\Temp\Nested.ps1
[CmdletBinding()]
Param(
[Parameter(Mandatory=$true)]
[String]$Msg
)
Write-Host ("Nested Message: {0}" -f $Msg)
# C:\Temp\Controller.ps1
$ScriptPath = "C:\Temp\Nested.ps1"
$params = #{
Msg = "Foobar"
}
$JobContent= {
& $using:ScriptPath #using:params
}
Invoke-Command -ScriptBlock $JobContent -ComputerName 'localhost'