Powershell -Filter not accepting two conditions - powershell

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.

Related

Using (*) in Where command in PowerShell

I am Using this command to get a Local User in Administrators group, and it works
Get-WmiObject -Class Win32_Groupuser -ComputerName $computer |? {$_.groupcomponent -like '*"Administrators"' -and $_.Partcomponent -like '*"User"'}|ft groupcomponent,Partcomponent
But now i want to use variable like this
$Group="Administrators"
$Account="users"
Get-WmiObject -Class Win32_Groupuser -ComputerName $computer |? {$_.groupcomponent -like *$Group -and $_.Partcomponent -like *$Account}|ft groupcomponent,Partcomponent
but i get nothing back
 
If the group name is "Administrators" you do not need to use a wildcard. The asterisk will match one or more characters. For example:
"Administrator*" matches Administrator, Administators, "Administrator
Groups", etc
"*Administrators" matches Administrators, "Windows Administrators", etc
"*Administrator*" matches Administrators, "Administrator Groups", "Windows Administrators", etc
For the second command you can use a sub-expression to expand the variable.
Where-Object { $_.groupcomponent -like "*$($Group)*" }
This is a working example:
$Group = '"Administrators"'
Get-WmiObject -Class Win32_Groupuser -ComputerName $computer |? {$_.groupcomponent -like "*$Group"}
The same can be adapted for $_.partcomponent.

Powershell IF and not condition not working properly

I'm struggling to have two conditions met, somehow it seems only one of them works. I'm trying to do :
If a user is connected AND NOT at the lock screen, ask for permission. The commands themselves have been verified and work individually but I must be missing something. Here is what i have:
if (Get-WmiObject –ComputerName $poste –Class Win32_ComputerSystem | Select-Object -expandproperty UserName -and -not (get-process -ComputerName $poste -name logonui)) {
"ask for permission"
}
Right now it just doesn't go in this code, it skips to the lower part where something else is happening.
What is wrong with my syntax ?
I can work around it and make it work this old fashioned way from my CMD days:
Clear-Variable -name statut_user
$statut_user -eq 0
if (Get-WmiObject –ComputerName $poste –Class Win32_ComputerSystem | Select-Object -expandproperty UserName) {$statut_user +=1}
if (-not (get-process -ComputerName $poste -name logonui)) {$statut_user += 1}
if ($statut_user -eq 2) {
"ask for permission"
}
It works, but not as clean as a proper one liner with the two conditions. Thank you for your help!
ANSWER EDIT: Thanks to vonPryz's answer below i ended up using :
$utilisateur = Get-WmiObject –ComputerName $poste –Class Win32_ComputerSystem | Select-Object -expandproperty UserName
$ecran_verr = get-process -ComputerName $poste -name logonui
if( -not ($ecran_verr) -and ($utilisateur)) {
"ask for permission"
}
Aim for clarity, not small codebase size. Instead of making WMI calls in the if statement and piping the results, consider something more readable. Like so,
$cs = gwmi -computername $p Win32_ComputerSystem
$uname = $cs | select-object -expandproperty UserName
$logonui = get-process -ComputerName $p -name logonui
if( -not ($logonui) -and ($uname )) {
# Stuff
}
This approach makes it easy to check that the WMI objects contain sensible values, whatever those may be. Then it should be easier to write a concise conditional statement.
While breaking an expression down into multiple steps is always a good idea for debugging, as demonstrated in vonPryz's helpful answer, sometimes you do want the concision of a single expression without auxiliary variables.
What is wrong with my syntax?
You're missing (...) around the Get-WmiObject ... | Select-Object ... pipeline.
To use a command or pipeline as part of a larger expression, you must always enclose it in (...) A command in PowerShell is a call to an executable - be it a cmdlet, function, alias, or external program.
A simple example:
# !! BROKEN: tokens `-eq 'jdoe'` are interpreted as *arguments for Select-Object*
# !! rather than as operator -eq and RHS 'jdoe'
if (Get-WmiObject Win32_ComputerSystem | Select-Object -Expand UserName -ne 'jdoe') {
'not jdoe'
}
# OK: (...) around the pipeline properly embeds it in the overall expression:
if ((Get-WmiObject Win32_ComputerSystem | Select-Object -Expand UserName) -ne 'jdoe') {
'not jdoe'
}
Here's a fixed version of your original command that fixes that improves other aspects too:
if (
(Get-WmiObject –ComputerName $poste –Class Win32_ComputerSystem).UserName `
-and -not `
(Get-Process -ErrorAction SilentlyContinue -ComputerName $poste -name logonui)
) {
"ask for permission"
}
Given that your Get-WmiObject call only ever outputs 1 object, you can access the .UserName property directly, which is also more efficient than piping to Select-Object -ExpandProperty.
Get-Process outputs a non-terminating error if a process by the given name cannot be found, so -ErrorAction SilentlyContinue suppresses that.
Note the use of ` as a line-continuation character, which allows spreading the conditional across multiple lines, making it much more readable.
Note that the ` must be at the very end of the line.

PowerShell Get-Service is very slow to return results

I have tried several methods for gathering service data and I can't seem to get one to meet all my needs. Get-Service works fine but is very slow when I pipe in a couple Where-Object properties. Get-CimInstance is much faster but I can't figure out how to exclude services. Any ideas?
Here's my code attempts so far. This one is fast until I add the Where-Object. Then it takes 3 times longer if I do:
Get-Service -DisplayName * -ComputerName $Name -Exclude $ExcludedServices | Where-Object { $_.status -eq 'Running' -or $_.StartType -eq 'Automatic' }
This one works much faster but I don't know how to exclude a list of Services if needed:
Get-CimInstance -ClassName Win32_Service -ComputerName $Name | Where-Object { $_.state -eq 'Running' -or $_.StartMode -eq 'Auto' }
I don't know how to exclude a list of Services if needed
Get-CimInstance allows you to impose a WQL WHERE clause constraint on the query:
Get-CimInstance Win32_Service -Filter 'Name != "excludedSvc"'
You can also restrict the items based on the State or StartMode properties inside the query, so the remote computer doesn't have to send back all of the services:
Get-CimInstance Win32_Service -Filter 'Name != "excludedSvc" AND State = "Running" AND StartMode = "Auto"'

Powershell Pipeline filter

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

Calling Get-WMIObject on multiple computers selected via Get-ADComputer

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