Help: if something equals a certain value, change value to 'x'

This topic contains 9 replies, has 3 voices, and was last updated by Profile photo of Dave Wyatt Dave Wyatt 3 years, 6 months ago.

  • Author
    Posts
  • #11683
    Profile photo of John Gatto
    John Gatto
    Participant

    Hopefully my title isn't too vague. I've put together a simple script that does a WMI query on anything in the domain with a "Server" OS, and then checks to see if it is physical or virtual. It outputs to a CSV file, and I can sort by the 'version' column to determine if it's physical or virtual. Here's a sample of the code:

    $servers = get-adcomputer -filter 'OperatingSystem -like "*Server*"' -searchbase "DC=domain,DC=local" | select -ExpandProperty Name
     
    $results = foreach ($server in $servers ) {gwmi win32_bios -computer $server -Credential $creds  | select PSComputerName,SerialNumber,Version,@{l='IPAddress';e={ (test-connection $server -count 1).ipv4address} }  }
     
    $results | export-csv C:\servers\Physical_Servers.csv -NoTypeInformation

    What I'd like to accomplish is to have it write something simple like "Physical" if the version doesn't match the conditions for VMware or Hyper-V, or "Virtual" if it does. I run this to just get physical servers:

    $servers = get-adcomputer -filter 'OperatingSystem -like "*Server*"' -searchbase "DC=domain,DC=local" | select -ExpandProperty Name
     
    $results = foreach ($server in $servers ) {gwmi win32_bios -computer $server -Credential $creds | Where-Object { $_.SerialNumber -notlike "*VMware*" -and $_.Version -notlike "*VRTUAL*" }  | select PSComputerName,SerialNumber,Version,@{l='IPAddress';e={ (test-connection $server -count 1).ipv4address} }  }
     
    $results | export-csv C:\servers\Physical_Servers.csv -NoTypeInformation

    This works, but I'd like to do it as listed in the first example and just get a simple output that lists server name and whether it is physical or virtual. Any ideas?

    Thanks!

  • #11684
    Profile photo of Don Jones
    Don Jones
    Keymaster

    So, the trick is just to add another custom property to your Select-Object property list. You've got one for IPAddress already; just add another. Call it "MachineType" or something. In the expression portion, put all your logic. That can include an entire sub-script, with if constructs and whatever. Whatever you "Write-Output" from the expression will become the value of the "MachineType" property.

    $stuff | Select Name,Foo,Bar,@{n='Widget';e={ if ($_ -notin (1,2,3,4,5) ) { Write "Physical" } else { Write $_ } }
    

    BTW, I avoid "l" instead of "label" because it looks a lot like the number 1.

  • #11691
    Profile photo of John Gatto
    John Gatto
    Participant

    This is exactly what I was looking for. Thanks! I was close... I was just over-thinking it, I guess. Also, good tip about using 'n' instead of 'l' for custom properties. It's much easier to read that way.

    Thanks again!

  • #11760
    Profile photo of John Gatto
    John Gatto
    Participant

    Follow up question:

    So I'm trying to apply the same logic to a query to determine whether or not SNMP is enabled on all servers running any variation of 2008 Server. This is my code:


    $creds = Get-Credential
    $servers = get-adcomputer -Filter 'OperatingSystem -like "*2008*"' | select -ExpandProperty Name
    $SNMP = foreach ($server in $servers ) {gwmi -computer $server -Credential $creds -query "select *from win32_ServerFeature where name = 'snmp service' "| select PSComputerName,@{N="SNMPInstalled";e={ if ($_.Name -ne "") {write-output "Yes"} else {write-output "No"} } } }
    $SNMP | Export-Csv c:\servers\SNMPInstalled.csv -NoTypeInformation

    This works, but it's only returning a value for servers that have SNMP installed. It's skipping over the ones that don't have it installed. I suspect that this is because the WMI query is returning a null value, but I thought that my 'if ($_.Name -ne "")' statement would catch that.

    Thanks in advance for any insight!

  • #11761
    Profile photo of Don Jones
    Don Jones
    Keymaster

    On servers without SNMP, WMI is probably not returning anything. So, there's nothing to pipe to Select-Object, so it doesn't execute. WMI isn't returning NULL, it's returning nothing. There's not really a way to handle that in a one-liner – you'd need to capture the WMI query to a variable, and then test it using a standalone if construct to see if it contains an object or not.

    One-liners are great, but they don't really do logical branching well.

  • #11765
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Give this a shot:

    $creds = Get-Credential
    
    $props = @(
        @{ Name = 'ComputerName'; Expression = { $_.Name } }
        @{ Name = 'SNMPInstalled'; Expression = { (Get-WmiObject -ComputerName $_.Name -Credential $creds -Query "select *from win32_ServerFeature where name = 'snmp service' ") -ne $null } }
    )
    
    Get-ADComputer -Filter 'OperatingSystem -like "*2008*"' |
    Select-Object -Property $props |
    Export-Csv c:\servers\SNMPInstalled.csv -NoTypeInformation
    
    
  • #11772
    Profile photo of John Gatto
    John Gatto
    Participant

    Dave, this worked perfectly! Thank you. I didn't think to separate the name and WMI query out into two different components like you're doing here. Thanks again!

  • #11813
    Profile photo of John Gatto
    John Gatto
    Participant

    Dave, I have a followup question. Again, this worked, but I'm a bit confused. According to the help files, Get-WMIObject does not accept pipeline input for the 'computername' property, but it appears that we're passing the name through from the 'get-adcomputer' cmdlet. How is this working? Doe it behave differently if you store it in an array first?

    Thanks!

  • #11814
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    You're not piping anything directly to Get-WmiObject, in that example. It's Select-Object that accepts the pipeline input. When you use a constructed property, the Expression is a script block that gets executed for each of the input objects that Select-Object is processing (referred to by the $_ automatic variable inside the expression), and that script block's return value is what gets assigned to the resulting property.

  • #11815
    Profile photo of Dave Wyatt
    Dave Wyatt
    Moderator

    Using Select-Object in that way is sort of a nice shorthand for something like this:

    $creds = Get-Credential
    
    Get-ADComputer -Filter 'OperatingSystem -like "*2008*"' |
    ForEach-Object {
        $computer = $_
        $snmpObject = Get-WmiObject -ComputerName $computer.Name -Credential $creds -Query "select *from win32_ServerFeature where name = 'snmp service' "
    
        if ($snmpObject -ne $null)
        {
            $isSnmpInstalled = $true
        }
        else
        {
            $isSnmpInstalled = $false
        }
    
        New-Object psobject -Property @{
            ComputerName = $computer.Name
            SNMPInstalled = $isSnmpInstalled
        }
    } |
    Export-Csv c:\servers\SNMPInstalled.csv -NoTypeInformation
    

    They both get you PSObjects with the same properties, but I prefer how the pipeline looks when there's not a big ForEach-Object loop stuck in the middle of it.

You must be logged in to reply to this topic.