Solved

PowerShell: Combining IIS Information from several WMI Queries

Posted on 2014-04-08
7
565 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
  • 4
  • 2
7 Comments
 
LVL 18

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 18

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
NAS Cloud Backup Strategies

This article explains backup scenarios when using network storage. We review the so-called “3-2-1 strategy” and summarize the methods you can use to send NAS data to the cloud

 
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 17

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

Best Practices: Disaster Recovery Testing

Besides backup, any IT division should have a disaster recovery plan. You will find a few tips below relating to the development of such a plan and to what issues one should pay special attention in the course of backup planning.

Question has a verified solution.

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

Synchronize a new Active Directory domain with an existing Office 365 tenant
A brief introduction to what I consider to be the best editor for PowerShell.
A short film showing how OnPage and Connectwise integration works.
This is a video describing the growing solar energy use in Utah. This is a topic that greatly interests me and so I decided to produce a video about it.

914 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

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now