Determine PowerShell version remotely via WMI - powershell

I have searched here and elsewhere and could not find an answer, so here is my question.
What is the best way to determine PowerShell version on a remote computer using WMI?
Background
My task is to audit and update some 1000 servers to recent version of PowerShell. Some of them have PowerShell v1 and some do not have WinRM configured, so Invoke-command is not an option. PSExec is also not an option in this environment. This is why I need to use WMI for this task.
Any help would be appreciated.
EDIT:
After much research I'm still leaning towards WMI. In particular retrieving the file version of "powershell.exe". This seems to me to be the only way to cover all versions.
Code I have so far is here:
$path = "C:\\Windows\\system32\\WindowsPowerShell\\v1.0\\powershell.exe"
$query = "SELECT Version FROM CIM_DataFile WHERE Name = '$path'"
$PSFileVer = Get-WmiObject -Query $query -ComputerName $servername -Credential $creds
$BuildVer = [version]$PSFileVer.Version.Split()[0]
All I need now is a comprehensive list, mapping file version (build number) to powershell version. Any Ideas?

The solution from here is
$command = "ipconfig/all > C:\temp\result.txt"
$cmd = "cmd /c $command"
Invoke-WmiMethod -class Win32_process -name Create -ArgumentList $cmd -ComputerName "remotepc"
sleep 1
Get-Content \\remotepc\C$\temp\result.txt
You can also do similar via this method. If you do so, you can't get the return value directly, u must redirect to a file.
You could setup share for the results instead of putting result on local machine

If it helps here is the command :
$command = "powershell -command "+'"$PSVersionTable.PsVersion.Major | out-file c:\temp\version.txt"'

Related

Using Parameters when Calling Script with Start-Job

I am working on a script that must change users in the middle of running in order to be able to access a network folder. I have figured out how to get the credentials working, but now cannot understand how to pass parameters to the second script that is being called. The code that I currently have:
$myJob = Start-Job -ScriptBlock {& "\\my\folder\path\script.ps1" -serverName $serverName -serverInstance $serverInstance} -Credential $cred
$myJob | Wait-Job
$myJob | Receive-Job -Keep
I need to pass the serverName and serverInstance variables to the script that Start-Job is running, while also still being able to use credential. Is there a way to do this?
I have investigated Invoke-Command and Invoke-Expression, but neither of those fit this situation. Invoke-Command doesn't work with remote computers/drives and Invoke-Expression doesn't work with credentials. I tried the answer that was provided here, but that would not correctly pass in the parameters either.
Any help is much appreciated as I have been working on this problem for a few hours now. I am sure I am missing something obvious.
You can use the using scope modifier provided you are on PowerShell version 3 or higher:
$myJob = Start-Job -ScriptBlock {& "\\my\folder\path\script.ps1" -serverName $using:serverName -serverInstance $using:serverInstance}
You can also use local variables in remote commands, but you must indicate that the variable is defined in the local session. Beginning in Windows PowerShell 3.0, you can use the Using scope modifier to identify a local variable in a remote command. The syntax of Using is as follows:
$Using:<VariableName>
If you are on PowerShell version 2, you will need to utilize the -ArgumentList parameter and then modify your scriptblock to accept the arguments that are passed. Avshalom comments on one way to do this.
See About_Remote_Variables for more information.

Powershell Invoke-GPUpdate - "No Logoff" possible?

Looking to run Invoke-GPUPdate -force to a group of remote computers and respond to the logoff prompt with "No".
Tried:
Echo "n" | invoke-gpupdate
Error:Invoke-gpupdate does not accept pipeline input
Command Used:
Invoke-GPUpdate -Computer $computer -RandomDelayInMinutes 0 -force
Unfortunately it looks like this cmdlet initiates/schedules a run of gpupdate that ends up happening separately (out of process), so there isn't much to do via PowerShell's standard ways of dealing with something like that, since the prompt doesn't come from within PowerShell. There's a -LogOff parameter, but it's a switch parameter which implies that its value is meant to be used just for doing the logoff. You can try it this way: -Logoff:$false but most likely it won't work to get rid of the prompt.
I think your best chance is not to use this cmdlet, but to instead use Invoke-Command with gpupdate.exe directly:
Invoke-Command -ComputerName $computer -ScriptBlock {
echo nn | gpupdate.exe /force
}
But this requires that PowerShell remoting is enabled on the machines you want to manage.

powershell execute .exe remotely

$computername = Read-Host "Enter Machine Name - "
Invoke-command -ComputerName $computername -ScriptBlock { & cmd /c 'c:\download\niniteone\niniteone.exe' /select "malwarebytes"}
Wondering if someone could tell me where I've gone wrong with this, it just dies when I run it. I've put this script together by looking at the others here but I can't seem to get it to work. We use ninite pro to update/install some 3rd party apps and I'm trying to setup some powershell scripts to run it on remote computers. Any help would be appreciated :)
Update - I added the cmd /c to the script block and now it works great!? I read cmd /c isnt needed with powershell v2? I'm confused... It's working but I'd like to get it right.
How about:
Invoke-command -ComputerName $computername -ScriptBlock { Start-Process -FilePath "c:\download\niniteone\niniteone.exe" -ArgumentList "/select `"malwarebytes`""}

Installing Windows Features on remote server 2012 using powershell 3.0

I am wondering which is best practice considering both examples will probably work. Using the built in help examples I have written a script to install windows features on remote servers. Here is my code:
$servers = ('server1', 'server2', 'server3', 'server4')
ForEach ($server in $servers) {
Install-WindowsFeature -Name Desktop-Experience -ComputerName $server -IncludeAllSubFeature -IncludeManagementTools -Restart
}
Would the above be preferred OR should I wrap the "Install-WindowsFeature ..." in an "Invoke-Command" block like the following?
Invoke-Command -ComputerName server1, server2, server3, server4 -command {
Install-WindowsFeature -Name Desktop-Experience -ComputerName $server -IncludeAllSubFeature -IncludeManagementTools -Restart
}
Thanks for your insight!
Personally I would use the latter (directly call Install-WindowsFeature -ComputerName $server rather than do a separate Invoke-Command) in this case for the following reasons:
You may be hard-coding the feature names now, but in the future you may want to put those in a variable. If you put them in a variable, you'll have to pass it as a parameter into the Invoke-Command's script block. This is entirely possible, but more work.
By using your own loop, you can write progress messages, logging, etc.
You gain nothing by using Invoke-Command in this case because you're running a single command on the remote computer (as opposed to running multiple commands with -ComputerName parameters vs. running multiple commands inside the script block).

Powershell remote script execution issue

I am trying to execute a powershell script from the host 1.2.3.3 on the box 1.2.3.4 remotely
$cred = get-credential
$process = get-wmiobject -query "SELECT * FROM Meta_Class WHERE __Class = 'Win32_Process'" -namespace "root\cimv2" -computername 1.2.3.4 -credential $cred
$results = $process.Create("powershell.exe /c C:\Windows\temp\hello.ps1 arg1")
I can see the process getting created (as the return value says 0) but the process is dies down immediately in the remote system(1.2.3.4)
I tried powershell.exe -file option also instead of powershell.exe /c
I tried using Invoke-Command but that dosent work because of trusted hosts issue.
Can somebody shed some light on this?
PowerShell.exe parameters starts with a dash (e.g '-'), for full help type: PowerShell.exe /?.
What do you expect to happen? What the script is doing? Should it "die" this way?