invoke-command doesn't work as expected - powershell

I'm trying to use invoke-command to find a specific process using this code
Invoke-Command -ComputerName $selected_server.ServerName -ArgumentList $selected_server.ProcessId -ScriptBlock {Get-Process -Name "winlogon" | where{$_.Id -like $args[0]} }
This command doesn't work, but if I use the numeric value contained in
$selected_server.ProcessId that is 8900, instead of using $args[0], it works.
I also tried to execute this command to verify if variables are read correctly and it seems so
Invoke-Command -ComputerName $selected_server.ServerName -ArgumentList $selected_server.ProcessId -ScriptBlock {$args[0]; $args[0].gettype().fullname}
> 8900
> System.Int32
Am I missing something?

Don't know why but this works ( maybe $args in foreach-object scriptblock is out of scope):
Invoke-Command -ComputerName $selected_server.ServerName `
-ArgumentList $selected_server.ProcessId -ScriptBlock `
{param ($x) Get-Process -Name "winlogon" | where{$_.Id -like $x} }

C.B's answer is good & works anywhere you have remoting available (v2.0 & higher), but there is another (easier) way if you're using PowerShell 3.0 - the Using scope modifier. See about_Remote_Variables
Invoke-Command -ComputerName $selected_server.ServerName -ArgumentList $selected_server.ProcessId -ScriptBlock {Get-Process -Name "winlogon" | where{$_.Id -like $Using:selected_server.ProcessId} }

Related

Remotely setting wallpaper on demand via powershell

I have created a function Set-Wallpaper:
Function Set-WallPaper($Value)
{
Set-ItemProperty -path 'HKCU:\Control Panel\Desktop\' -name wallpaper -value $value
rundll32.exe user32.dll, UpdatePerUserSystemParameters
}
and can run it locally to use a network path to the desired jpg
Set-Wallpaper -value "\\server\share\image.jpg"
and it works.
Now I want to run this function on a remote PC, I tried
Invoke-Command -ComputerName TARGETPC Set-Wallpaper -value "\\server\share\image.jpg"
but it errors out with
Invoke-Command : A parameter cannot be found that matches parameter name 'value'.
what am I missing?
$session= new-pssession -Computername "yourClientname"
$reslt= Invoke-Command -Session $session -ScriptBlock {your code}
If u want to ahnd over an argument use it like this
$reslt= Invoke-Command -Session $session -argumentlist $argument -ScriptBlock {param ($argument) your code with $argument[0]}

Any Idea how to uninstall .MSI with a password in the argument parameter?

I am still pretty new to PowerShell and I am trying to create a PS script that uninstalls a program remotely, however it doesn't seem to be working, it runs fine with no error messages, but just doesn't seem to uninstall the app. I am sure I might be doing something completely wrong... Hoping someone can point me in the right direction. Code below:
$Password = "1234"
Invoke-Command -ComputerName TEST `
-ScriptBlock {
$product = Get-WmiObject win32_product | where{$_.name -eq "Program Name"}
$product.IdentifyingNumber
Start-Process "C:\Windows\System32\msiexec.exe" `
-ArgumentList "/x $($product.IdentifyingNumber) PASSWORD=$Password /quiet /noreboot" -Wait }
Because of the strange indentation in your code I didn't see it at first, but the thing is that variable $Password is unknown in the scriptblock, unless you either scope it with using: or send it as parameter in the ArgumentsList parameter of the scriptblock and add a param() block in there.
Also, as commented, only proceed with the Start-Process command if you have checked that the Get-WmiObject call actually returned a valid product object.
Try
Using the using: scope modifier
$Password = "1234"
Invoke-Command -ComputerName TEST -ScriptBlock {
$product = Get-WmiObject win32_product | Where-Object {$_.name -eq "Program Name"}
if ($product) {
$argList = "/x $($product.IdentifyingNumber) PASSWORD=$using:Password /quiet /noreboot"
Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList $argList -Wait
}
}
or use a param() block in the scriptblock
$Password = "1234"
Invoke-Command -ComputerName TEST -ScriptBlock {
param( $Password )
$product = Get-WmiObject win32_product | Where-Object {$_.name -eq "Program Name"}
if ($product) {
$argList = "/x $($product.IdentifyingNumber) PASSWORD=$Password /quiet /noreboot"
Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList $argList -Wait
}
} -ArgumentList $Password
You may consider using the newer Get-CimInstance cmdlet instead of Get-WmiObject

Remote management with powershell

I'm trying to get some information from several machines on the network but I get loads of entries of the local machine.. for each entry in the text file I get an entry from the local machine.
Any idea where I'm going wrong.. winrm is configured on the remote machines and running.
$Username = Read-Host "Please enter Username"
$Password = read-host "please enter Password"
$pass = ConvertTo-SecureString -AsPlainText $Password -Force
$Cred = New-Object System.Management.Automation.PSCredential -ArgumentList $Username,$pass
$computers = gc c:\test\file.txt
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
cls
Thanks in advance :)
Invoke-Command will take an array for the ComputerName param so you can use $computers instead of using a foreach loop (assuming that you have one computer name per-line in the file).
I've also used Get-Credential to prompt for the full credential in one go rather than asking for username and password individually.
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | Out-File c:\test\output.txt -Append}
The reason you are only seeing a single computers info in c:\test\output.txt is because the output of the the ipconfig command is being saved to the remote computer... so you will have a c:\test\output.txt file on each computer you run the command against.
EDIT:
To take the output of each remote command and save it to your local computer just move the Out-File outside the Invoke-Command like this:
$Cred = Get-Credential
$computers = Get-Content c:\test\file.txt
Invoke-Command -ComputerName $computers -Credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"} | Out-File c:\test\output.txt -Append
The issue is you are iterating one by one but you are not passing one by one to the invoke-command, $computer will have each value at a time in the foreach loop.
Instead of this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computers -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Do this:
foreach ($Computer in $computers)
{
Invoke-command -ComputerName $computer -credential $cred -ErrorAction Stop -ScriptBlock {Invoke-Expression -Command:"cmd.exe /c 'ipconfig'" | out-file c:\test\output.txt -append}
}
Further improvement:
You do not have to give Invoke-Expression -Command:"cmd.exe /c 'ipconfig'"
Instead of this,you can directly use ipconfig inside the scriptblock.

Importing Scriptblock from file

I've got a working Powershell script and I'd like to have the scriptblock pulled in from an external file.
Working:
$scriptblock = { ... }
invoke-command -ComputerName $server -ScriptBlock $Scriptblock -ArgumentList $server,$team -Credential $credential -asjob -JobName Dashboard_$server -SessionOption (New-PSSessionOption -NoMachineProfile)
Output of "get-job -id | receive-job" is fine
Not working:
# Generate scriptblock from file
$file = Get-Content E:\Dashboard\Windows\winrm_scriptblock.txt
$Scriptblock = $executioncontext.invokecommand.NewScriptBlock($file)
invoke-command -ComputerName $server -ScriptBlock $Scriptblock -ArgumentList $server,$team -Credential $credential -asjob -JobName Dashboard_$server -SessionOption (New-PSSessionOption -NoMachineProfile)
Output of "get-job -id | receive-job" is empty
The contents of winrm_scriptblock.txt is exactly what is included between the braces in the scriptblock variable defined in the working version.
Any assistance is appreciated.
I know you already have answers, but another way to get a scriptblock from a script file is to use the get-command cmdlet:
$sb=get-command C:\temp\add-numbers.ps1 | select -ExpandProperty ScriptBlock
$sb is now the scriptblock for the script.
Very related to the answer from How do I pass a scriptblock as one of the parameters in start-job
If you stored the string "Get-ChildItem C:\temp" in the file "E:\Dashboard\Windows\winrm_scriptblock.txt" then this code should output the contents of the folder "C:\temp" on your local machine.
Invoke-Command -ScriptBlock ([scriptblock]::Create((Get-Content "E:\Dashboard\Windows\winrm_scriptblock.txt")))
Parameters
As far as passing parameters goes Pass arguments to a scriptblock in powershell covers that answer as well. As Keith Hill states: a scriptblock is just an anonymous function
Consider the following file contents
param(
$number
)
$number..2 | ForEach-Object{
Write-Host "$_ lines of code in the file."
}
And the command
Invoke-Command -ScriptBlock ([scriptblock]::Create((Get-Content "E:\Dashboard\Windows\winrm_scriptblock.txt"))) -ArgumentList "99"
Would give you the annoying output of
99 lines of code in the file.
98 lines of code in the file.
97 lines of code in the file.
....
Any reason not to just use the -FilePath parameter of Invoke-Command?
you must extract {} from E:\Dashboard\Windows\winrm_scriptblock.txt

invoke-expression inside scriptblock of invoke-command not working

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'"