?
Solved

PowerShell: Combining IIS Information from several WMI Queries

Posted on 2014-04-08
7
Medium Priority
?
668 Views
Last Modified: 2014-04-14
Experts,

I have a monster of a PowerShell script that when run against an IIS server, it provides me with information regarding the IIS site that I want.  Here is the script:

$computerList = ("SERVER01","SERVER02")
foreach($computer in $computerList){
$CentralLogging = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query 'Select * from IIsWebServiceSetting' -authentication 6	| Select CentralW3CLoggingEnabled
$CentralLog = $CentralLogging | ForEach-Object {$_.CentralW3CLoggingEnabled}
$ContentPaths = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query "SELECT * FROM IIsWebVirtualDirSetting" -authentication 6  | Where {$_.Name -like '*/Root'} | Select @{L="VirDirName"; E={$_.Name -replace '/Root',''}},@{L="ContentPath";E={$_.path}}
$FoundSites =  gwmi -namespace "root\MicrosoftIISv2" -ComputerName $Computer -query 'Select * from IIsWebServerSetting' -authentication 6  `
| Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.ServerComment}}, @{L="SiteID";E={$_.Name -replace "/"}}, `
@{L="HostHeaders";E={[string]::join(',',($_.ServerBindings  | select -expand hostname | Where-Object {$_ -ne $null}))}} `
, @{L="Ports";E={[string]::join(';',($_.ServerBindings  | select -expand Port | Where-Object {$_ -ne "80"}))}} `
, "LogFileDirectory", "NTAuthenticationProviders" , @{L="CentralLoggingEnabled";E={$CentralLog}} `
| Where-Object {$_.SiteName -ne 'Default Web Site' -and $_.SiteName -ne 'HealthCheck' -and $_.SiteName -notlike 'SharePoint*'}`
| ForEach-Object { $_.ServerName = "$computer"; return $_ } |Sort-Object "SiteName" | ConvertTo-CSV -NoTypeInformation `
#| Out-File -FilePath C:\Temp\PowerShell\Results.csv -Append
$ErrorActionPreference = "silentlycontinue"
$FoundSites
}

Open in new window


I want to get the content path (example: E:\InetPub\...) and know that I can get that information from a script like this:

$computer = "SERVER01"
gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query "SELECT * FROM IIsWebVirtualDirSetting" -authentication 6 | Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.name}}, @{L="ContentPath";E={$_.path }} , @{L="AppPool";E={$_.AppPoolId }} #| where {$_.SiteName -like '*/root'} #| ForEach-Object { $_.ServerName = "$computer"; return $_ }} 

Open in new window


But how can add the second script to the first to grab the information I want added?

Thanks in advance,

Hank
0
Comment
Question by:Hankinater
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 2
7 Comments
 
LVL 19

Expert Comment

by:Raheman M. Abdul
ID: 39986701
Try this (updated)

$computerList = ("SERVER01","SERVER02")
foreach($computer in $computerList){
$CentralLogging = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query 'Select * from IIsWebServiceSetting' -authentication 6      | Select CentralW3CLoggingEnabled

$CentralLog = $CentralLogging | ForEach-Object {$_.CentralW3CLoggingEnabled}

$ContentPaths = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query "SELECT * FROM IIsWebVirtualDirSetting" -authentication 6  | Where {$_.Name -like '*/Root'} | Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.name}}, @{L="ContentPath";E={$_.path }} , @{L="AppPool";E={$_.AppPoolId }}, @{L="VirDirName"; E={$_.Name -replace '/Root',''}}

$FoundSites =  gwmi -namespace "root\MicrosoftIISv2" -ComputerName $Computer -query 'Select * from IIsWebServerSetting' -authentication 6  `
| Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.ServerComment}}, @{L="SiteID";E={$_.Name -replace "/"}}, `
@{L="HostHeaders";E={[string]::join(',',($_.ServerBindings  | select -expand hostname | Where-Object {$_ -ne $null}))}} `
, @{L="Ports";E={[string]::join(';',($_.ServerBindings  | select -expand Port | Where-Object {$_ -ne "80"}))}} `
, "LogFileDirectory", "NTAuthenticationProviders" , @{L="CentralLoggingEnabled";E={$CentralLog}} `
| Where-Object {$_.SiteName -ne 'Default Web Site' -and $_.SiteName -ne 'HealthCheck' -and $_.SiteName -notlike 'SharePoint*'}`
| ForEach-Object { $_.ServerName = "$computer"; return $_ } |Sort-Object "SiteName" | ConvertTo-CSV -NoTypeInformation `
#| Out-File -FilePath C:\Temp\PowerShell\Results.csv -Append
$ErrorActionPreference = "silentlycontinue"
$FoundSites
}



This may help you if you looking for:
http://blogs.technet.com/b/heyscriptingguy/archive/2013/07/16/query-multiple-wmi-classes-but-return-one-object-with-powershell.aspx
0
 
LVL 2

Author Comment

by:Hankinater
ID: 39986891
Raheman,

Thanks for your reply, the results are the same as before when running your updated versions.  Did you just reformat it?

Thanks,

Hank
0
 
LVL 19

Expert Comment

by:Raheman M. Abdul
ID: 39987068
I understand that you want to combine 2nd and 1st script. Is that you want? sorry i missed your point.
can you be a bit clear please.
0
Does Powershell have you tied up in knots?

Managing Active Directory does not always have to be complicated.  If you are spending more time trying instead of doing, then it's time to look at something else. For nearly 20 years, AD admins around the world have used one tool for day-to-day AD management: Hyena. Discover why

 
LVL 2

Author Comment

by:Hankinater
ID: 39987092
This is the script I started with:

cls
$computerList = ("SERVER01",SERVER02") 
foreach($computer in $computerList){
$CentralLogging = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query 'Select * from IIsWebServiceSetting' -authentication 6	| Select CentralW3CLoggingEnabled
$CentralLog = $CentralLogging | ForEach-Object {$_.CentralW3CLoggingEnabled}
$FoundSites = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $Computer -query 'Select * from IIsWebServerSetting' -authentication 6  `
| Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.ServerComment}}, @{L="SiteID";E={$_.Name -replace "/"}}, `
@{L="HostHeaders";E={[string]::join(',',($_.ServerBindings  | select -expand hostname | Where-Object {$_ -ne $null}))}} `
, @{L="Ports";E={[string]::join(';',($_.ServerBindings  | select -expand Port | Where-Object {$_ -ne "80"}))}} `
, "LogFileDirectory", "NTAuthenticationProviders" , @{L="CentralLoggingEnabled";E={$CentralLog}} `
| Where-Object {$_.SiteName -ne 'Default Web Site' -and $_.SiteName -ne 'HealthCheck' -and $_.SiteName -notlike 'SharePoint*'} `
| ForEach-Object { $_.ServerName = "$computer"; return $_ } |Sort-Object "SiteName" | ConvertTo-CSV -NoTypeInformation `
$ErrorActionPreference = "silentlycontinue"
$FoundSites
}

Open in new window


It gives me information about the IIS sites that are on the servers I target.  But what it doesn't give me is the path to the content for each site, for instance "E:\Inetpub\Site01".  The only way I can get that is with a seperate script.

My point is that I want the script to be altered so that it will pull in the path information.

Does that clear it up?

Thanks,

Hank
0
 
LVL 18

Expert Comment

by:Learnctx
ID: 39987293
You can use Add-Member to add an additional attribute to your $FoundSites object from a separate command.

$FoundSites = .....
$SitePath = gwmi .....
$FoundSites | Add-Member -MemberType NoteProperty -Name SitePath -Value $SitePath

Open in new window

This would insert a property called SitePath with the value from the result your first query returned, the $FoundSites object. Just insert the code into the loop. Not sure if that's what you're after.
0
 
LVL 2

Accepted Solution

by:
Hankinater earned 0 total points
ID: 39988844
I appreciate everyone's input.  Learnctx - I couldn't get Add-Member to work.  However I was able to find the following article "Join-Object".  I wasn't able to get it to work calling a script named Join-Object.ps1, so I added it's contents to my script.

cls
$computerList = ("SERVER01","SERVER02") 
function AddItemProperties($item, $properties, $output)
{
    if($item -ne $null)
    {
        foreach($property in $properties)
        {
            $propertyHash =$property -as [hashtable]
            if($propertyHash -ne $null)
            {
                $hashName=$propertyHash["name"] -as [string]
                if($hashName -eq $null)
                {
                    throw "there should be a string Name"  
                }
         
                $expression=$propertyHash["expression"] -as [scriptblock]
                if($expression -eq $null)
                {
                    throw "there should be a ScriptBlock Expression"  
                }
         
                $_=$item
                $expressionValue=& $expression
         
                $output | add-member -MemberType "NoteProperty" -Name $hashName -Value $expressionValue
            }
            else
            {
                # .psobject.Properties allows you to list the properties of any object, also known as "reflection"
                foreach($itemProperty in $item.psobject.Properties)
                {
                    if ($itemProperty.Name -like $property)
                    {
                        $output | add-member -MemberType "NoteProperty" -Name $itemProperty.Name -Value $itemProperty.Value
                    }
                }
            }
        }
    }
}
 
    
function WriteJoinObjectOutput($leftItem, $rightItem, $leftProperties, $rightProperties, $Type)
{
    $output = new-object psobject
 
    if($Type -eq "AllInRight")
    {
        # This mix of rightItem with LeftProperties and vice versa is due to
        # the switch of Left and Right arguments for AllInRight
        AddItemProperties $rightItem $leftProperties $output
        AddItemProperties $leftItem $rightProperties $output
    }
    else
    {
        AddItemProperties $leftItem $leftProperties $output
        AddItemProperties $rightItem $rightProperties $output
    }
    $output
}
 
<#
.Synopsis
   Joins two lists of objects
.DESCRIPTION
   Joins two lists of objects
.EXAMPLE
   Join-Object $a $b "Id" ("Name","Salary")
#>
function Join-Object
{
    [CmdletBinding()]
    [OutputType([int])]
    Param
    (
        # List to join with $Right
        [Parameter(Mandatory=$true,
                   Position=0)]
        [object[]]
        $Left,
 
        # List to join with $Left
        [Parameter(Mandatory=$true,
                   Position=1)]
        [object[]]
        $Right,
 
        # Condition in which an item in the left matches an item in the right
        # typically something like: {$args[0].Id -eq $args[1].Id}
        [Parameter(Mandatory=$true,
                   Position=2)]
        [scriptblock]
        $Where,
 
        # Properties from $Left we want in the output.
        # Each property can:
        # - Be a plain property name like "Name"
        # - Contain wildcards like "*"
        # - Be a hashtable like @{Name="Product Name";Expression={$_.Name}}. Name is the output property name
        #   and Expression is the property value. The same syntax is available in select-object and it is 
        #   important for join-object because joined lists could have a property with the same name
        [Parameter(Mandatory=$true,
                   Position=3)]
        [object[]]
        $LeftProperties,
 
        # Properties from $Right we want in the output.
        # Like LeftProperties, each can be a plain name, wildcard or hashtable. See the LeftProperties comments.
        [Parameter(Mandatory=$true,
                   Position=4)]
        [object[]]
        $RightProperties,
 
        # Type of join. 
        #   AllInLeft will have all elements from Left at least once in the output, and might appear more than once
        # if the where clause is true for more than one element in right, Left elements with matches in Right are 
        # preceded by elements with no matches. This is equivalent to an outer left join (or simply left join) 
        # SQL statement.
        #  AllInRight is similar to AllInLeft.
        #  OnlyIfInBoth will cause all elements from Left to be placed in the output, only if there is at least one
        # match in Right. This is equivalent to a SQL inner join (or simply join) statement.
        #  AllInBoth will have all entries in right and left in the output. Specifically, it will have all entries
        # in right with at least one match in left, followed by all entries in Right with no matches in left, 
        # followed by all entries in Left with no matches in Right.This is equivallent to a SQL full join.
        [Parameter(Mandatory=$false,
                   Position=5)]
        [ValidateSet("AllInLeft","OnlyIfInBoth","AllInBoth", "AllInRight")]
        [string]
        $Type="OnlyIfInBoth"
    )
 
    Begin
    {
        # a list of the matches in right for each object in left
        $leftMatchesInRight = new-object System.Collections.ArrayList
 
        # the count for all matches  
        $rightMatchesCount = New-Object "object[]" $Right.Count
 
        for($i=0;$i -lt $Right.Count;$i++)
        {
            $rightMatchesCount[$i]=0
        }
    }
 
    Process
    {
        if($Type -eq "AllInRight")
        {
            # for AllInRight we just switch Left and Right
            $aux = $Left
            $Left = $Right
            $Right = $aux
        }
 
        # go over items in $Left and produce the list of matches
        foreach($leftItem in $Left)
        {
            $leftItemMatchesInRight = new-object System.Collections.ArrayList
            $null = $leftMatchesInRight.Add($leftItemMatchesInRight)
 
            for($i=0; $i -lt $right.Count;$i++)
            {
                $rightItem=$right[$i]
 
                if($Type -eq "AllInRight")
                {
                    # For AllInRight, we want $args[0] to refer to the left and $args[1] to refer to right,
                    # but since we switched left and right, we have to switch the where arguments
                    $whereLeft = $rightItem
                    $whereRight = $leftItem
                }
                else
                {
                    $whereLeft = $leftItem
                    $whereRight = $rightItem
                }
 
                if(Invoke-Command -ScriptBlock $where -ArgumentList $whereLeft,$whereRight)
                {
                    $null = $leftItemMatchesInRight.Add($rightItem)
                    $rightMatchesCount[$i]++
                }
            
            }
        }
 
        # go over the list of matches and produce output
        for($i=0; $i -lt $left.Count;$i++)
        {
            $leftItemMatchesInRight=$leftMatchesInRight[$i]
            $leftItem=$left[$i]
                               
            if($leftItemMatchesInRight.Count -eq 0)
            {
                if($Type -ne "OnlyIfInBoth")
                {
                    WriteJoinObjectOutput $leftItem  $null  $LeftProperties  $RightProperties $Type
                }
 
                continue
            }
 
            foreach($leftItemMatchInRight in $leftItemMatchesInRight)
            {
                WriteJoinObjectOutput $leftItem $leftItemMatchInRight  $LeftProperties  $RightProperties $Type
            }
        }
    }
 
    End
    {
        #produce final output for members of right with no matches for the AllInBoth option
        if($Type -eq "AllInBoth")
        {
            for($i=0; $i -lt $right.Count;$i++)
            {
                $rightMatchCount=$rightMatchesCount[$i]
                if($rightMatchCount -eq 0)
                {
                    $rightItem=$Right[$i]
                    WriteJoinObjectOutput $null $rightItem $LeftProperties $RightProperties $Type
                }
            }
        }
    }
}

foreach($computer in $computerList){
$CentralLogging = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query 'Select * from IIsWebServiceSetting' -authentication 6	| Select CentralW3CLoggingEnabled

$CentralLog = $CentralLogging | ForEach-Object {$_.CentralW3CLoggingEnabled}

$SitePath = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $computer -query "SELECT * FROM IIsWebVirtualDirSetting" -authentication 6  | Where {$_.Name -like '*/Root'} | Select @{L="VirDirName"; E={$_.Name -replace '/Root',''}},@{L="ContentPath";E={$_.path}}

$FoundSites = gwmi -namespace "root\MicrosoftIISv2" -ComputerName $Computer -query 'Select * from IIsWebServerSetting' -authentication 6  `
| Select @{N="ServerName";E={$computer}}, @{L="SiteName";E={$_.ServerComment}}, @{L="Name";E={$_.Name}} , @{L="SiteID";E={$_.Name -replace "/"}}, `
@{L="HostHeaders";E={[string]::join(',',($_.ServerBindings  | select -expand hostname | Where-Object {$_ -ne $null}))}} `
, @{L="Ports";E={[string]::join(';',($_.ServerBindings  | select -expand Port | Where-Object {$_ -ne "80"}))}} `
, "LogFileDirectory", "NTAuthenticationProviders" , @{L="CentralLoggingEnabled";E={$CentralLog}} `
| Where-Object {$_.SiteName -ne 'Default Web Site' -and $_.SiteName -ne 'HealthCheck' -and $_.SiteName -notlike 'SharePoint*'} `
| ForEach-Object { $_.ServerName = "$computer"; return $_ } |Sort-Object "SiteName" | ConvertTo-Csv -NoTypeInformation `
$ErrorActionPreference = "silentlycontinue"
}

$FoundSites | Out-File -FilePath "E:\OpalisScripts\PowerShell\WebAppRetire\FoundSites.csv" -Force

$SitePath | Export-CSV -NoTypeInformation -Path "E:\OpalisScripts\PowerShell\WebAppRetire\SitePath.csv" -Force 

$Sites = Import-Csv "E:\OpalisScripts\PowerShell\WebAppRetire\FoundSites.csv"
$PathToContent = Import-Csv "E:\OpalisScripts\PowerShell\WebAppRetire\SitePath.csv"

$FinalList = Join-Object -Left $Sites -Right $PathToContent -where {$args[0].Name -eq $args[1].VirDirName} -LeftProperties "ServerName","SiteName","SiteID","HostHeaders","Ports","LogFileDirectory","NTAuthenticationProviders","CentralLoggingEnabled" -RightProperties "ContentPath" -Type AllinLeft
$FinalList | ConvertTo-CSV -NoTypeInformation

Open in new window


I'm still troubleshooting it as it behaves differently from machine to machine.
0
 
LVL 2

Author Closing Comment

by:Hankinater
ID: 39998550
I was unable to get the advice they provided to work.  After doing further research I was able to find my own solution.
0

Featured Post

Moving data to the cloud? Find out if you’re ready

Before moving to the cloud, it is important to carefully define your db needs, plan for the migration & understand prod. environment. This wp explains how to define what you need from a cloud provider, plan for the migration & what putting a cloud solution into practice entails.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preparing an email is something we should all take special care with – especially when the email is for somebody you may not know very well. The pressures of everyday working life stacked with a hectic office environment can make this a real challen…
My attempt to use PowerShell and other great resources found online to simplify the deployment of Office 365 ProPlus client components to any workstation that needs it, regardless of existing Office components that may be needing attention.
Exchange organizations may use the Journaling Agent of the Transport Service to archive messages going through Exchange. However, if the Transport Service is integrated with some email content management application (such as an antispam), the admini…
This is my first video review of Microsoft Bookings, I will be doing a part two with a bit more information, but wanted to get this out to you folks.

649 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question