Functions/Private/Artifacts/IIS/GetManifestFromMetabase.ps1

function GetManifestFromMetabase {
<#
.SYNOPSIS
Scans for presence of the Internet Information Services (IIS) Web Server on Windows Server 2003 images.
 
.PARAMETER MountPath
The path where the Windows image was mounted to.
 
.PARAMETER OutputPath
The filesystem path where the discovery manifest will be emitted.
 
.PARAMETER ArtifactParam
Optional - one or more Website names to include in the output.
#>

[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSShouldProcess",'')]
[CmdletBinding()]
param (
    [Parameter(Mandatory = $true)]
    [string] $MountPath,

    [Parameter(Mandatory = $true)]
    [string] $OutputPath,

    [Parameter(Mandatory = $true)]
    [string] $ImageWindowsVersion,

    [Parameter(Mandatory = $false)]
    [string[]] $ArtifactParam
)

$ManifestResult = @{
    FeatureName = ''
    Status = 'Absent'
    AspNetStatus = 'Absent'
    AspNet35Status = 'Absent'
}

$MetabasePath = "$MountPath\Windows\System32\inetsrv\MetaBase.xml"

if (Test-Path -Path $MetabasePath) {

    $IISConfig = [xml](Get-Content -Path $MetabasePath)
    
    $AspNetInstalled = $false
    ForEach ($svc in $IISConfig.configuration.MBProperty.IIsWebService) {
        if ($svc.ApplicationDependencies.Contains('ASP.NET')) {
            $AspNetInstalled = $true
            break
        }
    }

    $Sites = New-Object System.Collections.ArrayList
    ForEach ($site in $IISConfig.configuration.MBProperty.IIsWebServer) {  
        if ($site.ServerBindings -ne $null){
            $Sites.add([PSCustomObject]@{ 
                Name = $site.ServerComment;
                ID = $site.Location;
                Bindings = $site.ServerBindings  }) | Out-Null
        }
    }
    Write-Verbose -Message "Found: $($Sites.Count) sites"
    
    $apps = $IISConfig.configuration.MBProperty.IIsWebVirtualDir

    $Websites = New-Object System.Collections.ArrayList
    ForEach ($app in $apps) { 
        if ($app.Path -ne $null){
            $siteID = $app.Location.Substring(0, $app.Location.ToLower().IndexOf('/root'))
            $site = $Sites.where({$_.ID -eq $siteID})
            $Websites.add([PSCustomObject]@{ 
                Name = $app.AppFriendlyName;
                ID = $app.Location;
                ApplicationPool = $app.AppPoolId;
                PhysicalPath = $app.Path.replace('%SystemDrive%','C:'); # TODO - resolve for mount & local
                Binding = [PSCustomObject]@{ Protocol = 'http'; #TODO - discover protocol from metabase
                BindingInformation = "*" + $site.Bindings } 
            }) | Out-Null
        }
    }    

    $Websites = New-Object System.Collections.ArrayList
    $iis = $IISConfig.configuration.MBProperty
    ForEach ($site in $iis.IIsWebServer.where{$_.ServerBindings -ne $null}) { 
        $siteId = $site.Location
        $applications = New-Object System.Collections.ArrayList
        
        # in IIS 6 the app for the website is the root virtual directory
        $mainApp = $iis.IIsWebVirtualDir.where{$_.Location -eq "$SiteId/root"}
        $virtualDirectories =  New-Object System.Collections.ArrayList
        $mainVirtualDir = [PSCustomObject]@{ 
                    Path = '/';
                    PhysicalPath = $mainApp.Path.replace('%SystemDrive%','C:'); # TODO - resolve for mount & local
                }
        $virtualDirectories.add($mainVirtualDir) | Out-Null   

        # virtual directories are IIsWebVirtualDir elements with no app name
        ForEach ($virtualDirectory in $iis.IIsWebVirtualDir.where{
            $_.Location.StartsWith("$SiteId/root/") -and
            $_.AppFriendlyName -eq $null}){
                $virtualDirectories.add([PSCustomObject]@{ 
                    Path = '/' + $virtualDirectory.Location.Substring("$SiteId/root/".Length);
                    PhysicalPath = $virtualDirectory.Path.replace('%SystemDrive%','C:'); # TODO - resolve for mount & local
                }) | Out-Null
            }             
        $applications.add([PSCustomObject]@{ 
                Path = '/';
                ApplicationPool = ''; # TODO
                VirtualDirectories = $virtualDirectories;
            }) | Out-Null

        # apps are IisWebDirectory elements with an app name
        ForEach ($application in $iis.IIsWebDirectory.where{
            $_.Location.StartsWith("$SiteId/root/") -and
            $_.AppFriendlyName -ne $null}){
            $path = $application.Location.Substring("$SiteId/root/".Length)
            $virtualDirectories =  New-Object System.Collections.ArrayList
            $virtualDirectories.add([PSCustomObject]@{ 
                    Path = '/';
                    PhysicalPath = "$($mainVirtualDir.PhysicalPath)\$path"
                }) | Out-Null  
            $applications.add([PSCustomObject]@{ 
                Path = '/' + $path;
                ApplicationPool = $application.AppPoolId;
                VirtualDirectories = $virtualDirectories;
            }) | Out-Null
        }

        $bindings = New-Object System.Collections.ArrayList
        $bindings.add([PSCustomObject]@{ 
            Protocol = 'http'; #TODO - discover protocol from metabase
            BindingInformation = $site.ServerBindings
        }) | Out-Null

        $Websites.add([PSCustomObject]@{ 
                    Name = $site.ServerComment;
                    ID = $siteId;
                    Applications = $applications;
                    Bindings = $bindings;
            }) | Out-Null
    }

    $ManifestResult.FeatureName = ''    
    $ManifestResult.Status = 'Present'
    $ManifestResult.Websites = $Websites
    $ManifestResult.ApplicationPools = New-object System.Collections.ArrayList
    $ManifestResult.HttpHandlers = New-object System.Collections.ArrayList
    $ManifestResult.SiteDefaults = New-object System.Collections.ArrayList
    $ManifestResult.ApplicationDefaults =New-object System.Collections.ArrayList
    $ManifestResult.VirtualDirectoryDefaults = New-object System.Collections.ArrayList

    if ($AspNetInstalled -eq $true){        
        $ManifestResult.AspNetStatus = 'Present'
    }

    #TODO
    $ManifestResult.AspNet35Status = 'Absent'
}

return $ManifestResult 
}