Using (*) in Where command in PowerShell - 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.

Related

Get Uptime on Each Computer in an Array, Select the machines with the most uptime, and remotely execute a Script on each Machine

The majority of this code was pulled from a blog online, but I think it's exactly the way I need to be tackling this. I want to get the top 4 machines from an OU based on uptime, and run a script that lives on each of the top 4 machines. I know that the problem involves the Array losing access to the Get-ADComputer properties, but I'm unsure of how to pass these new properties back to their original objects. This works as expected until it gets to the foreach loop at the end.
$scriptBlock={
$wmi = Get-WmiObject -Class Win32_OperatingSystem
($wmi.ConvertToDateTime($wmi.LocalDateTime) – $wmi.ConvertToDateTime($wmi.LastBootUpTime)).TotalHours
}
$UpTime = #()
Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***" -SearchScope Subtree `
| ForEach-Object { $Uptime += `
(New-Object psobject -Property #{
"ComputerName" = $_.DNSHostName
"UpTimeHours" = (Invoke-Command -ComputerName $_.DNSHostName -ScriptBlock $scriptBlock)
}
)
}
$UpTime | Where-Object {$_.UpTimeHours -ne ""} | sort-object -property #{Expression="UpTimeHours";Descending=$true} | `
Select-Object -Property ComputerName,#{Name="UpTimeHours"; Expression = {$_.UpTimeHours.ToString("#.##")}} | Select-Object -First 4 |`
Format-Table -AutoSize -OutVariable $Top4.ToString()
foreach ($Server in $Top4.ComputerName) {
Invoke-Command -ComputerName $Server -ScriptBlock {HOSTNAME.EXE}
}
I'm not married to Invoke-Command in the last foreach but am having the same issues when I try to use psexec. Also, I'm running hostname.exe as a check to make sure I'm looping through the correct machines before I point it at my script.
Here's a streamlined version of your code, which heeds the comments on the question:
# Get all computers of interest.
$computers = Get-ADComputer -Filter 'ObjectClass -eq "Computer"' -SearchBase "OU=***,OU=***,OU=***,DC=***,DC=***" -SearchScope Subtree
# Get the computers' up-times in hours.
# The result will be [double] instances, but they're also decorated
# with .PSComputerName properties to identify the computer of origin.
$upTimes = Invoke-Command -ComputerName $computers.ConputerName {
((Get-Date) - (Get-CimInstance -Class Win32_OperatingSystem).LastBootUpTime).TotalHours
}
# Get the top 4 computers by up-time.
$top4 = $upTimes | Sort-Object -Descending | Select-Object -First 4
# Invoke a command on all these 4 computers in parallel.
Invoke-Command -ComputerName $top4.PSComputerName -ScriptBlock { HOSTNAME.EXE }

Powershell Remove Printer

Get-WmiObject -Class Win32_Printer | where{$_.Network -eq ‘true‘}| foreach{$_.delete()}
I know this script will delete all network printers, but I need to delete only certain network printers…like CLEPRINT15-2 and CLEPRINT 15-4, but not 15-3. How would I do this?
You already have a where filter on the Network property just more conditionals on the Name property.
Get-WmiObject -Class Win32_Printer |
Where-Object {$_.Network -eq $true -and ($_.Name -eq 'CLEPRINT15-2' -or $_.Name -eq 'CLEPRINT15-4')} |
ForEach-Object {$_.Delete()}
Note: Also be careful with smart quotes. ‘ is different than '
Try this additional where condition with a RegEx class [24]:
Get-WmiObject -Class Win32_Printer |
where{$_.Network -eq $true -and $_.Name -match '^CLEPRINT-?15-[24]$'} |
foreach{$_.delete()}

CASE, IFElse, or SWITCH Powershell to change output of Get-WmiObject

I have the following code that works as a stand-alone query:
$Type = (Invoke-Command -ComputerName $Computer -ScriptBlock { Get-WmiObject -Class Win32_ComputerSystem | Select-Object -ExpandProperty Manufacturer })
switch -regex ($Type)
{
"VMw.+" {"VM"}
default {"Physical"}
}
I want to add the switch command within the Invoke command instead of a variable (dropping the $Type variable) so that it can be run against multiple computers, how can this be accomplished, I am not determined to use Switch to accomplish the end result?
Get-WmiObject has a ComputerName property so you don't need to use Invoke-Command
switch -regex (Get-WmiObject -ComputerName $Computer -Class Win32_ComputerSystem | Select-Object -ExpandProperty Manufacturer)
{
"VMw.+" {"VM"}
default {"Physical"}
}
And by wrapping it in a simple foreach loop you can easily run it against multiple computers:
$Computers = "computer1","computer3","computer3"
foreach ($Computer in $Computers) {
switch -regex (Get-WmiObject -ComputerName $Computer -Class Win32_ComputerSystem | Select-Object -ExpandProperty Manufacturer)
{
"VMw.+" {Write-Output "$Computer is a VM Computer"}
default {Write-Output "$Computer is a Physical Computer"}
}
}

Running a powershell script against all the computers in Active Directory

I have written a script that generates some information but I need to run it on over 160 computers in an active directory. I don't want to run this script on each machine individually, is there any way of executing this script all all the machines from one centralized location?
invoke-command -ComputerName test-pc -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike '"*' -and $_.PathName -like "*\* *\*"}}
I don't want to be logging on to each machine individually. Is there quicker way? There must be.
Any help will be much appreciated.
Sohail.
Updated version:
invoke-command -ComputerName #(Get-ADComputer -Filter {Name -like "GBST*"} | Select-Object Name) -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike '"*' -and $_.PathName -like "*\* *\*"}}
Error message:
invoke-command : One or more computer names are not valid. If you are trying to pass a URI, use the -ConnectionUri parameter, or pass URI objects
instead of strings.
At line:1 char:2
+ invoke-command -ComputerName #(Get-ADComputer -filter {Name -like "GBSU1*"} | S ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (System.String[]:String[]) [Invoke-Command], ArgumentException
+ FullyQualifiedErrorId : PSSessionInvalidComputerName,Microsoft.PowerShell.Commands.InvokeCommandCommand
Just to make it shorter :
(Get-ADComputer -Filter 'Name -like "GBSU*"').Name | % {
Get-WMIObject Win32_Service |
Select-Object Name, PathName |
Where-Object { $_.PathName -notlike '"*' -and $_.PathName -like "** **" }
}
As pointed out by #bluuf :
This is actually not a 'good' solution since Get-WmiObject supports
the ComputerName parameter : Invoke-Command shouldn't be used at all
in this case.
There is a syntax error in your revised example where you kept the "*" in the Filter. You can't filter for all then narrow your results. Asterisk is implied when filtering based on properties.
I also added the ".Name" property to the computer search to only pass that to the invoke-command section. I tried the following code and it seemed to work.
invoke-command -ComputerName #((Get-ADComputer -Filter 'Name -like "GBST*"').Name) -ScriptBlock {gwmi win32_service | Select-object Name, PathName | where-object {$_.PathName -notlike 'C:\Windows\system32\*' -and $_.PathName -like 'C:\Program Files\*'}}

Cannot match if condition

Basically, I'm trying to read a BIOS setting and then with the if condition, if it matches to execute another command.
It works fine with other variables, it is just with this one.
#This Script will check for VT and VTD on Lenovo machines and enable them
#if the current value is disabled.
#Run Set-ExecutionPolicy Unrestricted first.
#Run As administrator
#Check the current values
$VT= gwmi -class Lenovo_BiosSetting -namespace root\wmi |
Where-Object {$_.CurrentSetting.split(",",[StringSplitOptions]::RemoveEmptyEntries) -eq "VirtualizationTechnology"} |
Format-List CurrentSetting
$VTD= gwmi -class Lenovo_BiosSetting -namespace root\wmi |
Where-Object {$_.CurrentSetting.split(",",[StringSplitOptions]::RemoveEmptyEntries) -eq "VTdFeature"} |
Format-List CurrentSetting
#Modify the values
#$EnabledVT= (gwmi -class Lenovo_SetBiosSetting -namespace root\wmi).SetBiosSetting("VirtualizationTechnology,Enable")
#$EnableVTD= (gwmi -class Lenovo_SetBiosSetting -namespace root\wmi).SetBiosSetting("VTdFeature,Enable")
#$SaveBios=(gwmi -class Lenovo_SaveBiosSettings -namespace root\wmi).SaveBiosSettings()
#Check if VT is disabled and enable it if it is.
Echo "Virtualization current settings are below"
Write-output $VT
IF ($VT -like "*Disable*") {
"this is not working"
} else {
"Setting is already set to enabled, no changes made."
}
#Check if VTD is disabled and enable it if it is.
Write-output $VTD
IF ($VTD -like "*,Disable") {
this is not working
} else {
"Setting is already set to enabled, no changes made."
}
#Save bios settings.
$SaveBios
Write-host "Check completed, Please restart computer for changes to take effect if any changes were made. "
I have tried different conditions to match exactly or the like or the match but nothing seems to be able to find anything.
So, here's the issue that you are having. You are piping the output of your command to Format-List, and storing that info in your variable. Don't do that. The Format-* cmdlets should be used to format things for output to the console, not for storing data for use later. Instead remove that part, and then reference the CurrentSetting property of the object.
$VT= gwmi -class Lenovo_BiosSetting -namespace root\wmi | Where-Object {$_.CurrentSetting.split(“,”,[StringSplitOptions]::RemoveEmptyEntries) -eq “VirtualizationTechnology”}
$VTD= gwmi -class Lenovo_BiosSetting -namespace root\wmi | Where-Object {$_.CurrentSetting.split(“,”,[StringSplitOptions]::RemoveEmptyEntries) -eq “VTdFeature”}
IF ($VT.CurrentSetting -like "*Disable*") {"this is now working"}
else {"Setting is already set to enabled, no changes made."}
This will function as desired.
Instead of Format-List, use Select-Object -ExpandProperty:
$VT = gwmi -class Lenovo_BiosSetting -namespace root\wmi | Where-Object {$_.CurrentSetting.split(“,”,[StringSplitOptions]::RemoveEmptyEntries) -eq “VirtualizationTechnology”} | Select-Object -ExpandProperty CurrentSetting
$VTD = gwmi -class Lenovo_BiosSetting -namespace root\wmi | Where-Object {$_.CurrentSetting.split(“,”,[StringSplitOptions]::RemoveEmptyEntries) -eq “VTdFeature”} | Select-Object -ExpandProperty CurrentSetting