$cmd = {
param([System.Array]$filestocopy = $(throw "need files"),
[bool]$copyxml)
if($copy)
#do stuff
}
$files = #("one","two","three")
invoke-command -session $s -scriptblock $cmd -argumentlist (,$files) $copyxml
Error:
Invoke-Command : A positional parameter cannot be found that accepts argument 'True'.
I have searched high and low and cannot find how to pass in an array along with something in a argumentlist. I have tried: (,$files,$copyxml), (,$files),$copyxml, and (,$files) $copyxml
Is there a way to do this?
The argument to the parameter -ArgumentList must be an array, otherwise $copyxml will be interpreted as the next positional parameter to Invoke-Command. Also, passing the array in a subexpression ((,$files)) will cause it to be mangled. Simply passing the variable ($files) is sufficient. Change this:
invoke-command -session $s -scriptblock $cmd -argumentlist (,$files) $copyxml
into this:
invoke-command -session $s -scriptblock $cmd -argumentlist $files,$copyxml
Related
I have a this set of code:
#Find the OU with the selected Canonical name and save it to this variable
$OUObject = Invoke-Command -Session $S -ScriptBlock {Get-ADOrganizationalUnit -filter * -Property CanonicalName | Where-Object {$_.CanonicalName -eq $using:listBox2.SelectedItem}}
So after this code i get a an OU stored in a variable $OUObject.
i now want to get all the gpo's linked to this ou.
so my next step is this:
$test = $OUObject.LinkedGroupPolicyObjects
and now $test hold all the gpos linked to its ou. problem now is i want to get them by name. so i can do this:
invoke-command -session $s -scriptblock {get-gpo -guid $test}
but i will get this error:
PS C:\WINDOWS\system32> invoke-command -session $s -scriptblock {get-gpo -guid $test}
Cannot validate argument on parameter 'Guid'. The argument is null or empty. Provide an argument that is not null or empty, and then try the command again.
+ CategoryInfo : InvalidData: (:) [Get-GPO], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.GroupPolicy.Commands.GetGpoCommand
+ PSComputerName : DC01
so i look at $test and this is what it holds:
PS C:\WINDOWS\system32> $test
cn={5873971D-F689-4E83-8AFA-389FDD7F34CD},cn=policies,cn=system,DC=bla,DC=local
cn={2B7F8931-038E-46BC-B1DB-FBFA86097C08},cn=policies,cn=system,DC=bla,DC=local
cn={C74CADA1-B609-44A3-8D3C-F733CF3112E2},cn=policies,cn=system,DC=bla,DC=local
so what i acually need is to past to the get-gpo command only the part inside the cn{..}
if i hardcode for example and do this:
invoke-command -session $s -scriptblock {get-gpo -guid 5873971D-F689-4E83-8AFA-389FDD7F34CD}
i get the result right.
can anyone help me achive this please?
Use the regex -replace operator to extract the GUID from the DN, then pass the value to Invoke-Command using the $using: modifier:
$GUIDs = $test -replace '^cn=(\{[0-9a-f-]+\}).*$'
Invoke-Command -Session $s { $using:GUIDs |ForEach-Object { Get-GPO -Guid $_ } }
Currently I have the following Invoke-Command:
Invoke-Command -ComputerName $i -ScriptBlock ${Function:query} `
-Credential oracle -ArgumentList $metconexao,$dumpdir,$i > $arq
Realize that the output of the Invoke-Command is put into $arq variable.
Now I need to do something like this:
Invoke-Command -ComputerName $i -ScriptBlock ${Function:query, commandTwo} `
-Credential oracle -ArgumentList $metconexao,$dumpdir,$i > $arq > outputTwo
I need the output of the commandTwo in another variable/file.
Is there some way to do this?
Create a PowerShell session and run each command with a separate Invoke-Command statement in the same session:
$s = New-PSSession -Computer $i -Credential oracle
Invoke-Command -Session $s -ScriptBlock ${function:query} -ArgumentList $metconexao,$dumpdir,$i > $arq
Invoke-Command -Session $s -ScriptBlock { commandTwo } -ArgumentList $metconexao,$dumpdir,$i > outputTwo
Note that > $arq does not write the output into the variable $arq, but into a file named after the value of that variable.
I'm trying to return exit code from a powershell script that is executed on a remote machine. But, when I check ExitCode it has some random number.
What I'm doing wrong? In addition, is it possible to return the whole text?
my script
$proc = Start-Process -Filepath "$PSExec" -ArgumentList "\\$server -h -u $user -p $pass -d PowerShell $command" -PassThru -Wait
$proc.ExitCode
remote script
New-Item "c:\temp\1.txt" -type file -force
exit 123
UPDATE
$secureString = ConvertTo-SecureString $password -Force -AsPlainText #$password includes password in clear text
$cred = New-Object System.Management.Automation.PSCredential($usrName, $secureString)
$sess = New-PSSession -ComputerName $serverName -Credential $cred
$command = "`"C:\temp\1.ps1`""
$result = Invoke-Command -Session $sess -ScriptBlock {
Start-Process -Filepath "$PSExec" -ArgumentList "\\$server -h -u $usrName -p $password -d PowerShell $command" -PassThru -Wait
}
Can you use Invoke-Command as an alternative?
Example:
$session = New-PSSesson -ComputerName $serverName -Credential (Get-Credential)
$result = Invoke-Command -Session $session -ScriptBlock {
Start-Process ...
}
As an alternative to Get-Credential you can created a credential object and pass it via the -Credential paramter to Invoke-Command. Example:
$secureString = ConvertTo-SecureString $password -Force -AsPlainText #$password includes password in clear text
$cred = [System.Management.Automation.PSCredential]::new($usrName, $secureString)
$sess = New-PSSession -ComputerName $ComputerName -Credential $cred
Invoke-Command -Session $sess -ScriptBlock { ... }
$result should also include the ExitCode property, since Powershell Remoting serializes the remote object. I always suggest Powershell Remoting compared to the cmdlet specific ComputerName implementations. It uses a more standardized way (WsMan -> HTTP(S)). See this link for further details.
Hope that helps.
For your first approach, your issue is that when running psexec with the -d (don't wait) flag it returns the pid of the command that launched it, rather than waiting and returning the exitcode.
Altogether your process also could be optimized. First if you wanted to use psexec.exe, I don't see a reason for Start-Process since you are waiting and passing through. Just & $psexec ... would suffice.
However Moerwald's suggestion for using Invoke-Command is a great one. In your updated code, you are still running Start-Process and Psexec which are unnecessary. When you are invoking the command, you are already remotely running code, so just run the code:
$secureString = ConvertTo-SecureString $password -Force -AsPlainText
$cred = New-Object System.Management.Automation.PSCredential($usrName, $secureString)
$result = Invoke-Command -ComputerName $serverName -Credential $cred -ScriptBlock {
New-Item "c:\temp\1.txt" -type file -force
exit 123
}
Also, since it doesn't look like you are reusing the session, I dropped the saving the session to a variable. And it would also be better to replace all of the credential setup with a Get-Credential rather than passing plaintext passwords around (avoid the password ending up in a saved transcript). That would look like this:
$result = Invoke-Command -ComputerName $serverName -Credential (Get-Credential) -ScriptBlock {
New-Item "c:\temp\1.txt" -type file -force
exit 123
}
I am trying to run any command I want on a remote machine. Example: gpupdate /force or copy file1 to file2 etc... so I have this code:
$ComputerName = Read-Host "Enter a remote computer name"
$RemoteCommand = Read-Host "Enter a remote command to run: Example gpupdate /force"
$s = New-PSSession -ComputerName $ComputerName
Invoke-Command -Session $s -ScriptBlock {$RemoteCommand}
Invoke-Command -Session $s -ScriptBlock { $? }
It runs without error and in fact it returns TRUE. But the file I have in c:\temp never gets copied to c:\temp\tmp
why not?
The problem is that you are passing a string variable to Invoke-Command in the scriptblock, which just evaluates to the content of the string. You are not passing it a scriptblock with actual commands.
To illustrate the difference see this code:
# Output is just the content of the string
$commandString = "Get-Service spooler"
Invoke-Command {$commandString}
# Output is the result of the commandlet
$scriptBlock = {Get-Service spooler}
Invoke-Command -ScriptBlock $scriptBlock
To get the result you want you can use the [scritpblock] accelerator, like this:
# Output is the result of the commandlet invocation defined in the string
$commandString = "Get-Service spooler"
$scriptBlock = [scriptblock]::Create($commandString)
Invoke-Command -ScriptBlock $scriptBlock
Try running the script like this:
Invoke-Command -Session $s -ScriptBlock { powershell.exe -Command "$RemoteCommand"}
If you get problems with escaping characters, there is also the -encodedCommand switch. From the powershell help:
# To use the -EncodedCommand parameter:
$command = 'dir "c:\program files" '
$bytes = [System.Text.Encoding]::Unicode.GetBytes($command)
$encodedCommand = [Convert]::ToBase64String($bytes)
powershell.exe -encodedCommand $encodedCommand
I have the following code:
Invoke-Command -ComputerName $remoteComputerName -Credentials $cred {& c:/program.exe}
How can I return the rc from program.exe as the Invoke-Command return code, particularly when it is non-zero.?
By default Invoke-Command will pass back whatever the result of the script was. If you are not sending back any other data you can always do something like this:
Invoke-Command -ComputerName $remoteComputerName -Credentials $cred {& c:/program.exe;$lastexitcode}
That should return the exit code of whatever application you were trying to run.
as an extension for what TheMadTechnician says, you can insert what ever happend in the remote computer to a powershell object, you can even wrap it with try{} catch{} or send back only $? (same as $LASTEXITCODE) and pass it back to the script:
$rc_oporation = Invoke-Command -ComputerName $remoteComputerName -Credentials $cred {& c:/program.exe; $?}
$rc_other_option = Invoke-Command -ComputerName $remoteComputerName -Credentials $cred { try{& c:/program.exe} catch{"there was a problem"} }
now "$rc_oporation" will hold your answers as 0 refer to success with no errors
hope that helps :)
before the above anwsers I got the following working (thanks to themadtechnician):
$s = New-PSSession -Name autobuild -ComputerName <ip address> -Credential $cred
Invoke-Command -Session $s -ScriptBlock {& 'C:\program.exe'}
$rc = Invoke-Command -Session $s -ScriptBlock {$lastexitcode}
if ($rc -ne 0)
{
write-output "run failed ..."
Remove-PSSession -Name autobuild
exit 1
}
else
{
write-output "run complete ..."
Remove-PSSession -Name autobuild
exit 0
}