Reputation: 598
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
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
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
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