psobject results not as expected

This topic contains 5 replies, has 4 voices, and was last updated by Profile photo of Russ J Russ J 2 months, 2 weeks ago.

  • Author
    Posts
  • #54243
    Profile photo of Russ J
    Russ J
    Participant

    Hi all

    I have the script below, running against PowerShell v2.0. Unfortunately I can't get the filtering working correctly and I'm at my limit in terms of my understanding of PowerShell. For example the DriveLetter custom property returns all the WMI members of Win32_Volume and I only want the drive letter in this particular example. Plus the same thing is happening with other WMI queries, and I really don't know what I am doing wrong.

    Thanks to all for your help in advance....

    $ServerBuildresults = @()

    $hosts = 'localhost'

    ForEach($h in $hosts) {

    $Services = Get-WmiObject Win32_Service
    $LogicalDisks = Get-WmiObject Win32_Volume -Filter "DriveType='3'"
    $WindowsVersion = Get-WmiObject Win32_OperatingSystem | Select-Object name
    $OSVersion = Get-WmiObject Win32_OperatingSystem
    $Domain = Get-WmiObject Win32_ComputerSystem
    $LocalGroups = Get-WmiObject win32_group -Filter "LocalAccount='True'"

    $obj = new-object psobject
    $obj | Add-Member -membertype NoteProperty -Name DriveLetter -Value (($LogicalDisks | Where-object { $_.DriveLetter } ) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name DriveSize -Value (($LogicalDisks | Select-Object capacity | % {$_.Capacity / 1GB -as [int]}) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name Label -Value (($LogicalDisks.Label) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name FileSystem -Value (($LogicalDisks.FileSystem) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name BlockSize -Value (($LogicalDisks.Blocksize) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name Monitoring.health -Value ($Services | Where-Object { $_.Name -eq 'healthservice'})
    $obj | Add-Member -membertype NoteProperty -Name Monitoring.ccmexec -Value ($Services | Where-Object { $_.Name -eq 'ccmexec' })
    $obj | Add-Member -membertype NoteProperty -Name Monitoring.masvc -Value ($Services | Where-Object { $_.Name -eq 'masvc' })
    $obj | Add-Member -membertype NoteProperty -Name SQLServices -Value (($Services | Where-Object { $_.StartName -notlike '*Local*' -and $_.Name -like '*SQL*' }) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name WindowsVersion -Value (($OSVersion.Caption) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name MemberDomain -Value (($Domain.Domain) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name LocalGroups.Caption -Value (($LocalGroups.Caption) | out-string).Trim()
    $obj | Add-Member -membertype NoteProperty -Name LocalGroups.Name -Value (($LocalGroups.name) | out-string).Trim()

    $ServerBuildresults += $obj

    }

    $ServerBuildresults

  • #54247
    Profile photo of Erik Sundin
    Erik Sundin
    Participant

    In this part of your code: $LogicalDisks | Where-object { $_.DriveLetter }, what you ask for is every object in $LogicalDisks that contains a value for Driveletter, so what you get in return is the entire object. Simply running $LogicalDisks.DriveLetter will give you every drive letter for every object in $LogicalDisks.

    • #54290
      Profile photo of Russ J
      Russ J
      Participant

      Thanks for the suggestion Erik but I've tried that and it doesn't work. I'm stuck on version 2.0 of powershell.

      Daniel your suggestion returns error 'invalid query'

      • This reply was modified 2 months, 2 weeks ago by Profile photo of Russ J Russ J.
  • #54248
    Profile photo of Daniel Krebs
    Daniel Krebs
    Participant

    You can update your WMI filter to exclude drives without a drive letter.

    Get-WmiObject Win32_Volume -Filter "DriveType='3' AND DriveLetter IS NOT NULL"

  • #54292
    Profile photo of Rob Simmers
    Rob Simmers
    Participant

    Take a look at this example:

    $computers = @($env:COMPUTERNAME)
    
    #The services filter is a bit lengthy, so to make it more readable
    #use a here string to format it.  The filter is the same regardless of
    #the computer, so it can be placed outside of the for construct.  One gotcha
    #is the first and last lines cannot be indented, but it's a must for WQL\SQL query
    #formatting and script readability
    $servicesFilter = @"
        Name = 'healthservice' 
        or 
        Name = 'ccmexec' 
        or 
        Name = 'masvc' 
        or 
        (Name Like '*SQL*' And NOT Name Like '*LOCAL*')
    "@
    
    #Place a variable ($results) at the top of your for loop structure to collect
    #all enumerated information.
    
    $results = foreach ( $computer in $computers ) {
        #Disks are a collection of information.  The code provided you
        #are breaking the properties up into different columns as strings,
        #which isn't the best approach.  Also, take a look the last line, 
        #this is a calculated expression, which is a great way to convert
        #or calculate values or even rename a property name
        $disks = Get-WmiObject Win32_Volume -Filter "DriveType='3' AND DriveLetter IS NOT NULL" -ComputerName $computer | 
                 Select DriveLetter, 
                 Label, 
                 FileSystem, 
                 BlockSize, 
                 @{Name="Capacity";Expression={$_.Capacity / 1GB -as [int]}}
        #Above I mentioned readability. Look at this remarked like with the filter typed
        #out.  You can read it, but you're probably going to be scrolling when you can just
        #do some formatting to make it simple to read and edit
        #$services = Get-WmiObject -Class Win32_Service -Filter "Name = 'XblGameSave' or Name = 'ccmexec' or Name = 'masvc' or (Name Like '*SQL*' And NOT Name Like '*LOCAL*')" -Property Name, State -ComputerName $computer
        $services = Get-WmiObject -Class Win32_Service -Filter $servicesFilter -Property Name, State -ComputerName $computer
    
        $os = Get-WmiObject -Class Win32_OperatingSystem  -ComputerName $computer| 
              Select Caption, 
                     Version
    
        $computersys = Get-WmiObject -Class Win32_ComputerSystem -ComputerName $computer | 
                       Select Domain
    
        #Personally, not a fan of Add-Member.  It has it's place doing some advanced property settings,
        #but there are much cleaner ways of generating objects.  For Powershell v2, you can create a hash
        #table and use New-Object to generate the object.  The New-Object gets passed back to the $results var
        $props = @{
            ComputerName = $computer
            OperatingSystem = $os | Select -ExpandProperty Caption
            Version = $os | Select -ExpandProperty Version
            Disks = $disks
            Services = $services
        }
    
        New-Object -TypeName PSObject -Property $props
    }
    

    Output:

    Services        : Win32_Service.Name="XblGameSave"
    ComputerName    : COMPUTER123
    Disks           : {@{DriveLetter=E:; Label=LRS_ESP; FileSystem=FAT32; BlockSize=4096; Capacity=1}, @{DriveLetter=C:; Label=Windows8_OS; FileSystem=NTFS; BlockSize=4096; Capacity=448}, @{DriveLetter=D:; 
                      Label=LENOVO; FileSystem=NTFS; BlockSize=4096; Capacity=25}, @{DriveLetter=V:; Label=Virtual Machines; FileSystem=NTFS; BlockSize=4096; Capacity=403}}
    Version         : 10.0.14393
    OperatingSystem : Microsoft Windows 10 Home
    

    For the Services and Disks, these are collections and are nested objects. You can access these by getting an object (the [0] is the first object by index):

    PS C:\Users\Rob> $results[0].Disks
    
    
    DriveLetter : E:
    Label       : LRS_ESP
    FileSystem  : FAT32
    BlockSize   : 4096
    Capacity    : 1
    
    DriveLetter : C:
    Label       : Windows8_OS
    FileSystem  : NTFS
    BlockSize   : 4096
    Capacity    : 448
    
    DriveLetter : D:
    Label       : LENOVO
    FileSystem  : NTFS
    BlockSize   : 4096
    Capacity    : 25
    
    DriveLetter : V:
    Label       : Virtual Machines
    FileSystem  : NTFS
    BlockSize   : 4096
    Capacity    : 403
    

    Now, I did not do the groups so you can attempt to figure it out yourself. Additionally, you want to use Test-Connection (basically a ping) and place error handling on your first WMI query so that if WMI cannot connect, you fail your first query and don't do 5 failed queries. In the eBooks like above, check out the Big Book of Error Handling

    • #54352
      Profile photo of Russ J
      Russ J
      Participant

      Thanks for the example Rob you've taken a bit of time to provide an alternative and document it, appreciate it.

      I'll take a look into this one.

      Thanks again.

You must be logged in to reply to this topic.