I'm trying to call Get-WMIObject (gwmi) on multiple computers selected via Get-ADComputer as a background job.
My first attempt was
$job = Get-ADComputer -filter "name -like '*t90*'" | % { gwmi -computername $_.name -query "select name,username from win32_computersystem" -asjob -throttlelimit 10 }
However, since I'm calling gwmi once for each computer object returned, hundreds of background jobs are created, and I don't believe they're collectively heeding the ThrottleLimit.
Am I doing this right?
I know that gwmi can also accept an array for the computername attribute, as so:
$job = gwmi -computername "computer1","computer2","computer3" -query "select * from win32_computersystem" -asjob -throttlelimit 10
Doing it this way results in a single job rather than hundreds, since gwmi is only called once. Is that the way I should be doing it? And, if so, how do I feed the output of Get-ADComputer to gwmi as an array?
Thanks!
First get all computer names and pass them to the computerName parameter:
$cn = Get-ADComputer -filter "name -like '*t90*'" | select -expand name
$job = gwmi -computername $cn -query "select name,username from win32_computersystem" -asjob -throttlelimit 10
Related
#Listing machine from which we will Query
$Machines = Get-ADComputer -Filter * -SearchBase 'OU=Laptops,OU=Win10Modern,OU=LN,OU=Workstations,DC=cooley,DC=com' | Select-Object Name
#Getting the Network Adapter version for Wi-Fi Adapter
ForEach ($Machine in $Machines) {
Get-NetAdapter | Select-Object Name,InterfaceDescription,DriverVersion,DriverDate,DriverProvider
}
Currently, your code loops over objects in variable $Machines, where each object has a single property called Name.
In order to get just the name values, either use Select-Object -ExpandProperty Name or get the array of names like this:
# get an array of computernames
$Machines = (Get-ADComputer -Filter * -SearchBase 'OU=Laptops,OU=Win10Modern,OU=LN,OU=Workstations,DC=cooley,DC=com').Name
Next loop over these computernames and have each computer run the Get-NetAdapter cmdlet:
# capture the output(s) in variable $result
$result = foreach ($Machine in $Machines) {
if (Test-Connection -ComputerName $Machine -Count 1 -Quiet) {
Invoke-Command -ComputerName $Machine -ScriptBlock {
Get-NetAdapter | Select-Object SystemName,Name,InterfaceDescription,
DriverVersion,DriverDate,DriverProvider,Status,AdminStatus
}
}
else {
Write-Warning "Computer '$Machine' does not respond"
}
}
# output on screen
$result
# or to GridView
$result | Out-GridView -Title 'NetAdapterInfo'
# or to CSV file
$result | Export-Csv -Path 'X:\NetAdapterInfo.csv' -NoTypeInformation
AdminStatus is a setting (enabled --> 'up'; disabled --> 'down')
Status is operational status (connected --> 'up'; disconnected --> 'down')
I don't think you can use Get-NetAdapter to connect to remote computers.
You can however use Get-WmiObject Win32_NetworkAdapter -ComputerName .
Like this:
ForEach ($Machine in $Machines) {
Get-WmiObject -Class Win32_NetworkAdapter -Filter "NetConnectionStatus = 2" -ComputerName $Machine
}
You need to become familiar with the properties of the Win32_NetworkAdapter class. You can see all of the properties by running this command:
Get-WmiObject -Class Win32_NetworkAdapter -ComputerName "Localhost" | fl * -Force
or you can use this command to see all of the properties (and methods) available to you.
Get-WmiObject -Class Win32_NetworkAdapter -ComputerName "Localhost" | Get-Member
Most computers will have more than 1 network card (some are hidden) and you have to filter the irrelevant ones out.
I have a WMI query to get the memory usage on a remote server:
$w3wpresult = (get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop| select ({$_.privatepagecount / 1gb})
$vmresult = (get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop| select ({$_.virtualsize / 1gb}))
Output:
IP 21Aug2015 0939 #{$_.privatepagecount / 1gb=1.0206184387207} #{$_.virtualsize / 1gb=1.77864074707031}
IP 21Aug2015 0939 #{$_.privatepagecount / 1gb=0.945835113525391} #{$_.virtualsize / 1gb=1.72514343261719}
I do not want the #{$.privatepagecount / 1gb= part of the string.
I just want to see the numeric value for the memory.
How do I do this?
Any input is greatly appreciated thanks!
You can't use Select-Object with that type of scriptblock for a custom property. Instead, build it this way using a hash table and specifying a label and expression:
#{L='PrivatePageCountGB';E={$_.privatepagecount / 1gb}}
Putting it together to look like this:
$w3wpresult = get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop|
select #{L='PrivatePageCountGB';E={$_.privatepagecount / 1gb}}
$vmresult = get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop|
select #{L='VirtualSizeGB';E={$_.virtualsize / 1gb}}
If you only care about the value, then this would work as well.
$w3wpresult = (get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop).privatepagecount /1GB
$vmresult = (get-wmiobject Win32_Process -filter "commandline like '%serviceoptimization%'" -computername $server -ErrorAction Stop).virtualsize/1GB
I have this command
$remoteuserlist = Get-WmiObject Win32_UserAccount `
-filter "LocalAccount =True" –computername $PC -verbose
that I am running to get a list of local accounts on a machine. I would also like to exclude the guest account from my list. so I tried something like this
$remoteuserlist = Get-WmiObject Win32_UserAccount `
-filter {LocalAccount =True -and Name -ne "Guest" –computername $PC -verbose}
but I get an invalid query error. Can someone explain my presumably blindingly obvious error?
Thanks
$remoteuserlist = Get-WmiObject Win32_UserAccount -filter {LocalAccount = "True" and Name != "Guest"} –computername $PC -verbose
You were mixing WMI syntax and PowerShell syntax
The brackets encompassing the filter were around the other parameters of Get-WmiObject
The WQL "not equal" operator is != or <>.
WQL Operators
If you have a bunch of old VBScript WMI queries laying around you can use the Get-WMIObject -Query param to reuse them.
$remoteuserlist = Get-WmiObject -query "SELECT * FROM Win32_UserAccount WHERE LocalAccount = 'True' and Name != 'Guest'" –computername $PC -verbose
Not groundbreaking but it can help if you don't want to rewrite queries.
I'm pulling my hair out here, because I just can't seem to get this to work, and I can't figure out how to google this issue. I'm running Powershell 2.0. Here's my script:
$computer_names = "server1,server2"
Write-Output "Invoke-Command -ComputerName $computer_names -ScriptBlock {
Get-WmiObject -Class Win32_LogicalDisk |
sort deviceid |
Format-Table -AutoSize deviceid, freespace
}"
Invoke-Command -ComputerName $computer_names -ScriptBlock {
Get-WmiObject -Class Win32_LogicalDisk |
sort deviceid |
Format-Table -AutoSize deviceid, freespace
}
The last command gives the error:
Invoke-Command : One or more computer names is not valid. If you are trying to
pass a Uri, use the -ConnectionUri parameter or pass Uri objects instead of
strings.
But when I copy the output of the Write-Output command to the shell and run that, it works just fine. How can I cast the string variable to something that Invoke-Command will accept? Thanks in advance!
Jamey and user983965 are correct, in that your declaration is wrong. However foreach here is not mandatory. If you just fix your array declaration like this, it will work:
$computer_names = "server1","server2"
Invoke-Command -ComputerName $computer_names -ScriptBlock {
Get-WmiObject -Class Win32_LogicalDisk |
sort deviceid |
Format-Table -AutoSize deviceid, freespace
}
You declared your array incorrectly. Put a comma between strings and pipe it to for-each like:
$computer_names = "server1", "server2";
$computer_names | %{
Write-Output "Invoke-Command -ComputerName $_ -ScriptBlock {
...snip
If you're getting an array of computers from active directory too - like this:
$computers = Get-ADComputer -filter {whatever}
Make sure you remember to select/expand the results.. like this:
$Computers= Get-ADComputer -filter * | Select-Object -ExpandProperty Name
Then...
Invoke-Command -ComputerName $Computers -ScriptBlock {Do Stuff}
have you tried:
$computer_names = "server1" , "server2"
foreach ($computer in $computer_names)
{
Write-Output "Invoke-Command -ComputerName $computer -ScriptBlock {
Get-WmiObject -Class Win32_LogicalDisk |
sort deviceid |
Format-Table -AutoSize deviceid, freespace
}"
Invoke-Command -ComputerName $computer -ScriptBlock {
Get-WmiObject -Class Win32_LogicalDisk |
sort deviceid |
Format-Table -AutoSize deviceid, freespace
}
}
I am trying to get a list of running processes and filter by two process names - can any one tell me how to get this working?
I've so far got it working and filtering out one process name:
$rn = Get-WMIObject Win32_Process -computer servername `
-credential mydomain\administrator -filter "Name='program1.exe'" |
select -expand path
$lst = Get-Content “C:\path\path2\List.txt”
Compare-Object $lst $rn
What I want it to do is filter two process names but nothing I've tried works. Any ideas?
Here's how to get a complete set of Process objects which match a list of process names you're interested in.
$ProcessNames = #( 'explorer.exe', 'notepad.exe' )
Get-WmiObject Win32_Process -Computer 'localhost' |
Where-Object { $ProcessNames -contains $_.Name } |
Select-Object ProcessID, Name, Path |
Format-Table -AutoSize
This example finds all processes, then filters that list by sending them to a pipeline filter that checks to see if the process name is contained in the list of interesting process names. The main benefit of using the pipeline this way is that you can easily access other attributes (such as ProcessID) of the returned processes.
ProcessID Name Path
--------- ---- ----
5832 explorer.exe C:\Windows\Explorer.EXE
4332 notepad.exe C:\Windows\system32\NOTEPAD.EXE
2732 notepad.exe C:\Windows\system32\notepad.exe
Use WQL operators like OR, AND, LIKE etc:
Get-WMIObject Win32_Process -computer servername -credential mydomain\administrator -filter "Name='program1.exe' OR Name='program2.exe'"
Create an array of the processes you're after:
$processes = #('winword.exe', 'notepad.exe', 'excel.exe') | `
% {
$rn = Get-WMIObject Win32_Process -computer servername -credential mydomain\admin -filter "Name='$_'" | select -expand path
#$lst = Get-Content “C:\path\path2\List.txt”
#Compare-Object $lst $rn
write-host $rn
}
I've commented out your compare so you can see how we are looping through the array clearly.
if I understood well try this:
$rn = Get-WMIObject Win32_Process -computer servername -credential mydomain\administrator -filter "Name='program1.exe OR Name='program2.exe'"
Compare-Object $rn[0].path $rn[1].path # if there are only one instance for process with name program1.exe and program2.exe