Invoke-WmiMethod - Quickly fix PsRemoting/WinRM problems (for Invoke-Command usage) - powershell

In the event you have computers that are unreachable with Invoke-Command either because WinRm is not running or PsRemoting is disabled here is a good, sure way I've found works everytime, in my environement at least:
$target_comp = "abc1234"
Invoke-WmiMethod -ComputerName $target_comp -Path win32_process -Name create -ArgumentList "powershell.exe -command Enable-PSRemoting -SkipNetworkProfileCheck -Force"
Invoke-WmiMethod -ComputerName $target_comp -Path win32_process -Name create -ArgumentList "powershell.exe -command winrm quickconfig -quiet"
do {
$testpsremoting = invoke-command -computername $target_comp -scriptblock {"test"}
} while (!$testpsremoting)
#REST OF CODE
Explanation :
-Declare variable of your computer name.
-Run the two commands to enable PsRemoting and setup WinRM via Invoke-WmiMethod.
*Since Invoke-WmiMethod returns instantly without WAITING for the commands to actually be done:
-Make a loop that runs until PsRemoting is enabled (until the test Invoke-Command works).
No more Invoke-Command problems! Enjoy and fine tune to your heart's content.

You could use Get-wmi to get the result directly
Get-WmiObject Win32_service -ComputerName $poste | select State,Name,DisplayName

Question changed to provide answer and useful fix for the community.

Related

Invoke-Command executes on remote machine without having an effect

I'm trying to run a command on a VM using Invoke-Command. The command should stop a program that processes jobs after it finishes its current job. It works if I run it in the terminal using RDC.
& 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' /stop
But if I run it from a different machine using Invoke-Command nothing seems to happen.
$session = New-PSSession -ComputerName 'hostname' -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
& 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' /stop
}
However Process Monitor shows the command come in for both cases, but the program is still running.
I have also tried using Start-Process with the same result, i.e. it works in the terminal on the VM but not using Invoke-Command.
Start-Process -FilePath 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe' -ArgumentList '/stop'
I've been stuck for many days and I've exhausted my googlable knowledge for this problem.
Are you sure that file exists on the remote computer?
For simplicity, I rewrote your command to a known executable that is always there in Windows and returns unique info for any given computer.
C:\> & 'C:\Windows\system32\HOSTNAME.EXE'
server1
C:\> icm {& 'C:\Windows\system32\HOSTNAME.EXE'}
server1
C:\> icm {& 'C:\Windows\system32\HOSTNAME.EXE'} -ComputerName server2
server2
Here's your script with some error handling.
$session = New-PSSession -ComputerName 'hostname' -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
$exe = 'C:\Program Files\Autodesk\Vault Client 2021\Explorer\JobProcessor.exe'
$ok = Test-Path $exe
if ($ok) {& $exe /stop} else {
Write-Warning "EXE not present on $($env:COMPUTERNAME)!"
}
}
Learn how to add error handling and you'll be well on your way to solving your problems faster and getting more stuff done.

Accessing cmd remotely using PowerShell

I need to run a couple of bcdedit commands on a remote computer's cmd using a PowerShell script that runs on my computer. I am able to create a PSSession but I'm not sure how I can run cmd on the remote computer. When I run the code in the 'Invoke-Command' line, I get an error Connection to remote server failed with the following error message: Access is denied. When I just run Invoke-Command, I am prompted to enter the ScriptBlock, but when I do, I get yet another error: "Cannot bind parameter 'ScriptBlock' Cannot convert the "cmd /c 'bcdedit /copy {current} /d "Description"'} value of type System.String to type System.Management.Automation.ScriptBlock
I have never worked with PowerShell before. I need to do this in a couple of hours, and I am absolutely clueless right now.
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts $ip -Concatenate -Force
$session = New-PSSession -ComputerName $ip -Credential $cred -ConfigurationName $config -UseSSL -SessionOption $sessopt
#problematic code
Invoke-Command -ComputerName $ip -ScriptBlock {cmd /c 'bcdedit /copy {current} /d "Description"'}
#works fine
Restart-Computer -ComputerName $ip -Force
ping.exe -t $ipaddr | Foreach{"{0}-{1}" -f (Get-Date -f "yyyy/MM/dd HH:mm:ss"), $_}
Assume that $ip, $ipaddr, $config, $sessopt and $cred store valid parameters.
You can run bcedit.exe directly in PowerShell, but because in PowerShell { and } are metacharacters, you need to quote identifiers such as {current}:
bcdedit /copy '{current}' /d 'Description'
See this answer for a discussion and list of PowerShell's metacharacters.
If you get an error on connecting to a remote computer, the implication is that your user account either doesn't have sufficient privileges to connect remotely or the target computer isn't set up for PowerShell remoting.
Note that Enable-PSRemoting -Force must be run on the target (server) machine, not on the calling (client) machine.
See the conceptual about_Remote_Troubleshooting topic.
The Restart-Computer cmdlet's -ComputerName parameter does not use PowerShell remoting, so the fact that it succeeds does not imply that PowerShell remoting, such as via Invoke-Command, works.
When I just run Invoke -Command, I am prompted to enter the ScriptBlock
PowerShell's automatic prompting feature for mandatory parameter values that weren't specified on the command line has severe limitations, and not being able to prompt for a script-block parameter value is one of them - see GitHub issue #4068; however, this additional problem is incidental to your real problem.
Thanks for all the suggestions, I was able to fix the error by adding -Credential to the Invoke-Command and Restart-Computer commands:
#problematic code
Invoke-Command -ComputerName $ip -Credential $cred -ScriptBlock {cmd /c 'bcdedit /copy {current} /d "Description"'}
Restart-Computer -ComputerName $ip -Credential $cred -Force

How to use invoke-command in powershell, to run a script on remote machine

Is it possible to use Invoke-Command in PowerShell to run a script on a remote machine?
I have tried :
Invoke-Command -ComputerName $MyPC -Credential $mycreds -ScriptBlock {
& "C:\Users\MyPC\Desktop\scripts\Script1.ps1"
}
which returns
script1.ps1 is not recognized as the name of a cmdlet
The scenario here is, I have some scripts on a remote folder, and I need to use Invoke-Command or some other ways to run the script on a remote machine.
Also, how to write if I want to pass some parameters for script1.ps1? Thanks in advance!
Instead of this:
Invoke-Command -ComputerName $MyPC -Credential $mycreds -ScriptBlock {& "C:\Users\MyPC\Desktop\scripts\Script1.ps1"}
Try this:
Invoke-Command -ComputerName $MyPC -Credential $mycreds -FilePath C:\Users\MyPC\Desktop\scripts\Script1.ps1
to avoid confusion with filepaths on local machines/remote machines; i always run stuff from smb-shares; you can enter UNC as filepath... eg:
-FilePath \server\Netscripts\script.ps1

Powershell (Version 2.0) remote execution of services with credentials

I want to start/stop apache and mysql services on remote machine by using powershell version 2.0 (Windows Server 2008). I found syntax for remote execution as follow:
(Get-WmiObject -Computer myCompName Win32_Service -Filter "Name='myServiceName'").InvokeMethod("Stop-Service",$null)
But I have to provide credentials (DOMAIN_NAME\USERNANE and PASSWORD) also for this exceution. I am new to powershell and need help for correct syntax (example will be easy to understand and implement).
Get-WMIObject accepts the -Credential parameter. You shouldn't be keeping your credentials in plain text in your script, so you'll want to prompt for them.
$creds = get-credential;
(Get-WmiObject -Computer myCompName Win32_Service -Filter "Name='myServiceName'" -credential $creds).InvokeMethod("Stop-Service",$null)
If you have PSRemoting enabled on the remote system, you can do this without WMI.
$creds = get-credential;
Invoke-Command -computername myCompName -credential $creds -scriptblock {(get-service -name myServiceName).Stop()};
Update based on comments
Since you're running this as a scheduled job, you should not be storing or prompting for credentials at all. Configured the scheduled job itself (via Scheduled Tasks) to run under the required user account, then either of the following should work:
# Your original code
(Get-WmiObject -Computer myCompName Win32_Service -Filter "Name='myServiceName'").InvokeMethod("Stop-Service",$null)
# If you have remoting enabled
Invoke-Command -computername myCompName -scriptblock {(get-service -name myServiceName).Stop()};

Prevent additional windows from displaying in powershell script

The idea here is to uninstall a program silently. Unfortunately the program's msi is custom and executes a batch file during the uninstall process. What I am trying to do is prevent this window from displaying during the powershell uninstall script. I'm using wmi uninstall method because the msi that the program uses doesn't respond to quite or uninstall flags (/q, /x, /uninstall). I have attempted to run it as a background job but the window still appears. The script looks as follows:
start-job -scriptblock `
{(Get-WmiObject -class Win32_Product |? {$_Name -eq "Annoying1"}).uninstall()} `
-Name Uninstall1
$job = get-job -name Uninstall1
wait-job $job
receive-job $job
This will run mostly hidden until the uninstall job gets to the point where the batch file is executed, at which point a cmd window will appear and run. Any ideas of how to run this script without displaying extra windows?
The script is ran with -windowstyle hidden as well.
Be indulgent, I'am not proud of this, but I'am quite sure that if you try to localy run your script using remoting the window will not be seen by the user :
I just try :
$sess = New-PSSession -ComputerName localhost
Invoke-Command -Session $sess -ScriptBlock {calc.exe}
get-process "calc"
In your case try :
$sess = New-PSSession -ComputerName localhost
$job = Invoke-Command -Session $sess -ScriptBlock {(Get-WmiObject -class Win32_Product |? {$_Name -eq "Annoying1"}).uninstall()} -asjob -Name Uninstall1
wait-job $job
receive-job $job