Royston
Royston

Reputation: 598

Adding Multiple Objects into Array using Get-WmiObject | Where-Object

I have the working code below which is used as a detection clause within SCCM to detect if Server Features are installed or not as part of a server feature scripted installer.

$role = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 2}
if ($role) {
    Write-Host "Installed"
}
else {
}

The problem, question is, the above only features 1 of the server features, how would i use an array to add in every relevant server feature in the class so that the detection clause is 100% Accurate?

Relevant Roles in this case are:

Web-Server Web-ISAPI-Ext Web-Windows-Auth Web-Metabase Web-WMI RDC

On a machine with them already installed I can extract this information to add in:

Get-WmiObject -Class win32_serverfeature | select Name, ID

Name                                ID
----                                --
Web Server (IIS)                     2
File Services                        6
Windows Deployment Services         19
.NET Framework 3.0 Features         36
Windows Process Activation Service  41
Telnet Client                       44
SNMP Services                       59
Remote Server Administration Tools  67
Web Server                         140
Common HTTP Features               141
Static Content                     142
Default Document                   143
Directory Browsing                 144
HTTP Errors                        145
Application Development            147
ISAPI Extensions                   152
Health and Diagnostics             155
HTTP Logging                       156
Request Monitor                    158
Security                           162
Windows Authentication             164
Request Filtering                  169
Performance                        171
Static Content Compression         172
Management Tools                   174
IIS Management Console             175
IIS 6 Management Compatibility     178
IIS 6 Metabase Compatibility       179
Configuration APIs                 217
.NET Environment                   218
Process Model                      219
.NET Framework 3.0                 220
SNMP Service                       224
SNMP WMI Provider                  225
Deployment Server                  251
Transport Server                   252
File Server                        255
Role Administration Tools          256
Windows Deployment Services Tools  264
Web Server (IIS) Tools             281

Note: this is designed for legacy servers running 2008 SP2 so, this means i have older toolsets to work with (ServerFeaturecmd.exe - Install-WindowsFeature and Get-Windowfeature cannot be used)

Thanks

Upvotes: 0

Views: 1215

Answers (3)

Syberdoor
Syberdoor

Reputation: 2619

If you just want to reduce the code you could write it like this:

$featureIDs = @(2, 140, 141, 162, 164, 179)
$compliant = $true

foreach($ID in $featureIDs) {
    $compliant = $compliant -and ((Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq $ID}) -ne $null)
}

if ($compliant) {
    Write-Host "Installed"
}
else {
}

However this does really a lot of WMI calls instead of just the one you would need. I am unsure if this can be done a lot better with some WQL syntax (as WQL is very limited) but if I find a more elegant way I will update this. I am mainly posting this rather crude solution now because I think I understand what you want to achieve in the hopes to inspire a much better solution.

Upvotes: 1

Lee_Dailey
Lee_Dailey

Reputation: 7489

i suspect that i am totally misunderstanding your question, but here is my answer anyway ...

why are you wanting to make repeated calls to create what you already have? [frown] you have a collection of the entire set of properties from that WMI call. if you only want a subset of them, create a [PSCustomObject] that contains the properties you want.

DO NOT make repeated calls to the same silly WMI class! [grin]

i've no such class as Win32_ServerFeature on my win7ps5.1 box, so the following demo is with other classes.

[note 1] you can make calls to several classes, save them to unique $Vars, and then use them to build your subset of the entire bundle of properties.

[note 2] you can call all of these in a scriptblock with Invoke-Command to run them on the remote systems in parallel.

#requires -RunAsAdministrator

# fake reading in a list of computer names
#    in real life, use Get-Content or (Get-ADComputer).Name
$ComputerList = @'
Localhost
BetterNotBeThere
127.0.0.1
10.0.0.1
::1
'@.Split("`n").Trim("`r")

$IC_ScriptBlock = {
    $CIM_ComputerSystem = Get-CimInstance -ClassName CIM_ComputerSystem
    $CIM_BIOSElement = Get-CimInstance -ClassName CIM_BIOSElement
    $CIM_OperatingSystem = Get-CimInstance -ClassName CIM_OperatingSystem
    $CIM_Processor = Get-CimInstance -ClassName CIM_Processor
    $CIM_LogicalDisk = Get-CimInstance -ClassName CIM_LogicalDisk |
        Where-Object {$_.Name -eq $CIM_OperatingSystem.SystemDrive}

    [PSCustomObject]@{
        LocalComputerName = $env:COMPUTERNAME
        Manufacturer = $CIM_ComputerSystem.Manufacturer
        Model = $CIM_ComputerSystem.Model
        SerialNumber = $CIM_BIOSElement.SerialNumber
        CPU = $CIM_Processor.Name
        SysDrive_Capacity_GB = '{0:N2}' -f ($CIM_LogicalDisk.Size / 1GB)
        SysDrive_FreeSpace_GB ='{0:N2}' -f ($CIM_LogicalDisk.FreeSpace / 1GB)
        SysDrive_FreeSpace_Pct = '{0:N0}' -f ($CIM_LogicalDisk.FreeSpace / $CIM_LogicalDisk.Size * 100)
        RAM_GB = '{0:N2}' -f ($CIM_ComputerSystem.TotalPhysicalMemory / 1GB)
        OperatingSystem_Name = $CIM_OperatingSystem.Caption
        OperatingSystem_Version = $CIM_OperatingSystem.Version
        OperatingSystem_BuildNumber = $CIM_OperatingSystem.BuildNumber
        OperatingSystem_ServicePack = $CIM_OperatingSystem.ServicePackMajorVersion
        CurrentUser = $CIM_ComputerSystem.UserName
        LastBootUpTime = $CIM_OperatingSystem.LastBootUpTime
        }
    }

$IC_Params = @{
    ComputerName = $ComputerList
    ScriptBlock = $IC_ScriptBlock
    ErrorAction = 'SilentlyContinue'
    }
$RespondingSystems = Invoke-Command @IC_Params
$NOT_RespondingSystems = $ComputerList.Where({
    # these two variants are needed to deal with an ipv6 localhost address
    "[$_]" -notin $RespondingSystems.PSComputerName -and
    $_ -notin $RespondingSystems.PSComputerName
    })

$RespondingSystems
$NOT_RespondingSystems

truncated output from responding systems ...

LocalComputerName           : [MySystemName]
Manufacturer                : System manufacturer
Model                       : System Product Name
SerialNumber                : System Serial Number
CPU                         : AMD Phenom(tm) II X4 945 Processor
SysDrive_Capacity_GB        : 931.41
SysDrive_FreeSpace_GB       : 750.18
SysDrive_FreeSpace_Pct      : 81
RAM_GB                      : 8.00
OperatingSystem_Name        : Microsoft Windows 7 Professional 
OperatingSystem_Version     : 6.1.7601
OperatingSystem_BuildNumber : 7601
OperatingSystem_ServicePack : 1
CurrentUser                 : [MySystemName]\[MyUserName]
LastBootUpTime              : 2018-10-29 1:48:53 AM
PSComputerName              : Localhost
RunspaceId                  : 367b79f3-dd9a-48c3-8e15-7be4d9134eda

output from non-responding systems ...

BetterNotBeThere
10.0.0.1

Upvotes: 0

Royston
Royston

Reputation: 598

Something like this was what i was thinking but, putting the objects into an array instead of individual variables? This doesn't seem the easiest way.

$roleID2 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 2}
$roleID140 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 140}
$roleID141 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 141}
$roleID162 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 162}
$roleID164 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 164}
$roleID179 = Get-WmiObject -Class Win32_ServerFeature | Where-Object {$_.ID -eq 179}

If ($roleID2 -and $roleID140 -and $roleID141 -and $roleID162 -and $roleID164 $roleID179) {
    Write-Host "Installed"
}
else {
}

Upvotes: 0

Related Questions