System Query Script

This topic contains 4 replies, has 3 voices, and was last updated by  Olaf Soyk 5 months, 1 week ago.

  • Author
    Posts
  • #73111

    Eric
    Participant

    Hello Eeryone,

    I'll start by saying i'm pretty new to Powershell and am really hoping to learn and eventually become proficient, but for now a I have what I think to be a simple question...

    I'm building a script to query a single host which is entered by the user and return a pile of information. In my case I have set up each piece of information to query independently so it can be stored in a variable (Username, RAM, OS, ect.), but in doing so I now have 19 queries so far that as you can imagine can a bit to run being that I still have 4 more queries to add I was wondering what I can do to circle back and make this process more efficient. My current run time so far is roughly 50, obviously id like to see that closer to 5-7, I was wondering if there is a way to have the script fire say 5 separate WMI queries to a single machine simultaneously rather than one at a time.

    Maybe i'm looking at this all wrong? Would it be better to pull down an entire namespace at once and somehow extract data from it? So far i'm querying 3 name spaces on the target machine if that makes a difference.

  • #73118

    Olaf Soyk
    Participant

    Without any line of your code it will quite hard to recommend something for you. But some general advices might help either.
    If you fire some wmi queries to one machine it makes sense to combine these single queries in one cim session. That usually speeds up those tasks noticeably ... here is something I set up time ago for a customer:

    function Get-WMIPCInfo {
        [CmdletBinding()]
        param(
            $ComputerName = $ENV:ComputerName
        )
        if (Test-Connection $ComputerName -Quiet -Count 1) {
            Write-Debug -Message "$ComputerName reachable"
            $so = New-CimSessionOption -Protocol DCOM 
            $WMIData = New-CimSession -CN $ComputerName -SessionOption $so
            $BIOS = Get-CimInstance -Class CIM_BIOSElement -CimSession $WMIData | Select-Object -Property *
            $OS = Get-CimInstance -Class CIM_OperatingSystem -CimSession $WMIData | Select-Object -Property *
            $ServiceBranch = (([wmiclass]"\\$($ComputerName)\root\default:stdRegProv").GetStringValue(2147483650,'SOFTWARE\Microsoft\Windows NT\CurrentVersion','ReleaseID')).svalue
            $DISK = Get-CimInstance -Class CIM_LogicalDisk -CimSession $WMIData | Where-Object {$_.DeviceID -eq "C:"} | Select-Object -Property *
            $Computer = Get-CimInstance -Class CIM_ComputerSystem -CimSession $WMIData | Select-Object -Property *
            $IPConfig = Get-CimInstance -Class Win32_NetworkAdapterConfiguration -CimSession $WMIData | Where-Object{$_.DefaultIPGateway -match "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}"}  | Select-Object -Property *
            #$LoggedOnUser = (Get-CimInstance -Class CIM_Process -CimSession $WMIData -Filter "Name = 'explorer.exe'" -ErrorAction SilentlyContinue | Invoke-CimMethod -MethodName GetOwner).User
            $UserQuery = ( C:\Windows\System32\quser.exe /server:$ComputerName 2> null)
            if ($UserQuery) {
                $UserQuery[1].Trim() -match "^(\S+)\s+.*((\d{2}\.){2}\d{4}\s+\d{2}:\d{2})" | Out-Null
                $LoggedOnUser = $Matches[1]
                $LogonTime = Get-Date -Date $Matches[2]
            }
            Remove-CimSession $WMIData
            Write-Debug -Message "`$BIOS: $BIOS"
            Write-Debug -Message "`$OS:  $OS"
            Write-Debug -Message "`$DISK:  $DISK"
            Write-Debug -Message "`$Computer:  $Computer"
            Write-Debug -Message "`$IPConfig:  $IPConfig"
            Write-Debug -Message "`$LoggedOnUser:  $LoggedOnUser"
            $CIMOutput = [PSCustomObject]@{
                ComputerName = $BIOS.PSComputerName;
                Model = $Computer.Model;
                BIOSName    = $BIOS.Name;
                SMBIOSVersion = $BIOS.SMBIOSBIOSVersion;
                BIOSVersion  = $BIOS.BIOSVersion;
                ReleaseDate  = $BIOS.ReleaseDate;
                SerialNumber = $BIOS.SerialNumber;
                OSCaption   = $OS.Caption;
                OSVersion   = $OS.Version;
                ServiceBranch = $ServiceBranch;
                InstallDate  = $OS.InstallDate;
                LastBootUpTime = $OS.LastBootUpTime;
                PhysicalRAM = [math]::round((($Computer.TotalPhysicalMemory) / 1GB),2);
                DiskSize     =  [math]::round(($DISK.Size / 1GB),2);
                DiskFreeSpace =  [math]::round(($DISK.FreeSpace / 1GB),2);
                IPV4Address     = $IPConfig.IPAddress[0];
                DefaultGateway = $IPConfig.DefaultIPGateway[0];
                DNSDomain = $IPConfig.DNSDomain;
                DHCPEnabled = $IPConfig.DHCPEnabled;
                LoggedOnUser = $LoggedOnUser
                LogonTime = $LogonTime
            }
        $CIMOutput
        }
        else {
            Write-Warning "`tComputer '$($ComputerName)' unreachable`n" 
        }
    }
    

    ... you can use as an inspiration. 😉

  • #73120

    Don Jones
    Keymaster

    So, if you're using Get-WmiObject, switch to Get-CimInstance. Faster. Establish a CimSession first, query against it, and then close it. Much faster. Make the connection over Dcom if needed (CimSessionOption), but don't use the old, deprecated Wmi commands.

    It's not possible to query an entire namespace, and if it was, it would NOT be faster. Not the way the tech works.

  • #73126

    Eric
    Participant

    I was able to clean it up quite a bit after I posted this by combining all of my "like" queries into one request, i'm evolving quickly. My second attempt ran in 7 seconds. I will deffinately look into switching to Get-CimInstance, im going to add some more info into this first. I have attached my remote query block below, this is just pulling basic system info. How can I segment a script into blocks of code? I would like to be able to control when, where, and why parts of my script execute, later adding call options as part of a GUI. I'm looking to have a call such as "Summary" that would just run this block and stop eliminating the need to have multiple script files.

    $WMIOS = gwmi -comp $hostname -Query "SELECT FreePhysicalMemory,Name,OSArchitecture FROM Win32_OperatingSystem"
    $freeMemory         = ($WMIOS.FreePhysicalMemory*1000/1gb).ToString(".00")
    $OS                 = $WMIOS.Name.split('|')[0]
    $Arch               = $WMIOS.OSArchitecture
    
    
    $WMICS = gwmi -comp $hostname -Query "SELECT DNSHostName, Domain, Username FROM win32_computersystem"
    $name               = $WMICS.DNSHostName
    $domain             = $WMICS.Domain
    $username           = $WMICS.Username
    
    
    $WMIMEM = gwmi -comp $hostname -Query "SELECT Capacity FROM Win32_PhysicalMemory"
    $totalMemory        = $WMIMEM.Capacity/1gb.ToString(".00")
    
    $NetAdapter=(get-wmiobject win32_networkadapter -filter "netconnectionstatus = 2" -comp $hostname).Name
    
    $FQDN = ($name+"."+$domain)
    
    $filter = "(&(objectCategory=computer)(objectClass=computer)(cn=$hostname))"
    $DN=([adsisearcher]$filter).FindOne().Properties.distinguishedname
    $OU=(($DN -split ',(?=OU)') | Select-Object -skip 1) -join ',' -replace ".{27}$" -Replace ",OU=", " / " -Replace "OU=";
    
    • #73130

      Olaf Soyk
      Participant

      Unfortunately my first reply has been blocked – I don't know why. So I try again.
      Here something I put together a while ago for a customer. You could use an inspiration or blue print and adapt it to your needs

      function Get-WMIPCInfo {
          [CmdletBinding()]
          param(
              $ComputerName = $ENV:ComputerName
          )
          if (Test-Connection $ComputerName -Quiet -Count 1) {
              Write-Debug -Message "$ComputerName reachable"
              $so = New-CimSessionOption -Protocol DCOM 
              $WMIData = New-CimSession -CN $ComputerName -SessionOption $so
              $BIOS = Get-CimInstance -Class CIM_BIOSElement -CimSession $WMIData | Select-Object -Property *
              $OS = Get-CimInstance -Class CIM_OperatingSystem -CimSession $WMIData | Select-Object -Property *
              $ServiceBranch = (([wmiclass]"\\$($ComputerName)\root\default:stdRegProv").GetStringValue(2147483650,'SOFTWARE\Microsoft\Windows NT\CurrentVersion','ReleaseID')).svalue
              $DISK = Get-CimInstance -Class CIM_LogicalDisk -CimSession $WMIData | Where-Object {$_.DeviceID -eq $OS.SystemDrive} | Select-Object -Property *
              $Computer = Get-CimInstance -Class CIM_ComputerSystem -CimSession $WMIData | Select-Object -Property *
              $IPConfig = Get-CimInstance -Class Win32_NetworkAdapterConfiguration -CimSession $WMIData | Where-Object{$_.DefaultIPGateway -match "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}"}  | Select-Object -Property *
              $UserQuery = ( C:\Windows\System32\quser.exe /server:$ComputerName 2> null)
              if ($UserQuery) {
                  $UserQuery[1].Trim() -match "^(\S+)\s+.*((\d{2}\.){2}\d{4}\s+\d{2}:\d{2})" | Out-Null
                  $LoggedOnUser = $Matches[1]
                  $LogonTime = Get-Date -Date $Matches[2]
              }
              Remove-CimSession $WMIData
              Write-Debug -Message "`$BIOS: $BIOS"
              Write-Debug -Message "`$OS:  $OS"
              Write-Debug -Message "`$DISK:  $DISK"
              Write-Debug -Message "`$Computer:  $Computer"
              Write-Debug -Message "`$IPConfig:  $IPConfig"
              Write-Debug -Message "`$LoggedOnUser:  $LoggedOnUser"
              $CIMOutput = [PSCustomObject]@{
                  ComputerName = $BIOS.PSComputerName;
                  Model = $Computer.Model;
                  BIOSName    = $BIOS.Name;
                  SMBIOSVersion = $BIOS.SMBIOSBIOSVersion;
                  BIOSVersion  = $BIOS.BIOSVersion;
                  ReleaseDate  = $BIOS.ReleaseDate;
                  SerialNumber = $BIOS.SerialNumber;
                  OSCaption   = $OS.Caption;
                  OSVersion   = $OS.Version;
                  ServiceBranch = $ServiceBranch;
                  InstallDate  = $OS.InstallDate;
                  LastBootUpTime = $OS.LastBootUpTime;
                  PhysicalRAM = [math]::round((($Computer.TotalPhysicalMemory) / 1GB),2);
                  DiskSize     =  [math]::round(($DISK.Size / 1GB),2);
                  DiskFreeSpace =  [math]::round(($DISK.FreeSpace / 1GB),2);
                  IPV4Address     = $IPConfig.IPAddress[0];
                  DefaultGateway = $IPConfig.DefaultIPGateway[0];
                  DNSDomain = $IPConfig.DNSDomain;
                  DHCPEnabled = $IPConfig.DHCPEnabled;
                  LoggedOnUser = $LoggedOnUser
                  LogonTime = $LogonTime
              }
          $CIMOutput
          }
          else {
              Write-Warning "`tComputer '$($ComputerName)' unreachable`n" 
          }
      }

      In my environment it used to run in less than a second.
      Have fun! 😉

You must be logged in to reply to this topic.