dev.core.netsh.psm1

Import-Module "$PSScriptRoot\dev.core.utils.psm1" -DisableNameChecking;


$UrlaclTemplate = [PSCustomObject]@{
    PSTypeName = "Netsh.ParseTemplate";    
    TypeName = "Netsh.Http.Urlacl";
    Properties = @(
        @{ Prefix = " Reserved URL : "; Name = "ReservedURL";  IsFirstProperty = $true; },
        @{ Prefix = " User: ";                 Name = "Users"; IsMultiValueProperty = $true; }
    );
}

$SslcertTemplate_SetIPAndPortProperty = [scriptblock]{
    param([PSCustomObject]$item, [string]$Value);
    $item.IP = $Value.Split(":")[0];
    $item.Port = $Value.Split(":")[1];
};

$SslcertTemplate = [PSCustomObject]@{
    PSTypeName = "Netsh.ParseTemplate";    
    TypeName = "Netsh.Http.Sslcert";
    Properties = @(
        @{ Prefix = " IP:port : "; Name = @("IP", "Port"); IsFirstProperty = $true; SetPropertyValue = $SslcertTemplate_SetIPAndPortProperty; },
        @{ Prefix = " Certificate Hash : "; Name = "CertificateHash"; },
        @{ Prefix = " Application ID : "; Name = "ApplicationID"; }
    );
}


#
# Private functions
#

function New-ParsedNetshObject([PSTypeName("Netsh.ParseTemplate")]$Template)
{
    $item = [PSCustomObject]@{
        PSTypeName = $Template.TypeName;
    }; 

    foreach ($property in $Template.Properties)
    {
        $value = if ($property.IsMultiValueProperty) { @() } else { $null };
        $value = @();
        foreach ($name in $property.Name)
        {
            $item | Add-Member -MemberType NoteProperty -Name $name -Value $value | Out-Null;
        }
    }

    return $item;
}

function Parse-Output([string[]]$Lines, [PSTypeName("Netsh.ParseTemplate")]$Template)
{
    $item = $null;
    foreach ($line in $Lines)
    {
        Write-Verbose "$line";

        foreach ($property in $Template.Properties)
        {
            if ($line.StartsWith($property.Prefix))
            {
                if ($property.IsFirstProperty)
                {
                    if ($item)
                    {
                        Write-Output $item;
                    }                

                    $item = New-ParsedNetshObject -Template $Template;
                }

                
                $value = $line.Substring($property.Prefix.Length).Trim();
                if ($property.SetPropertyValue)
                {
                    . $property.SetPropertyValue -item $item -value $value;
                } 
                elseif ($property.IsMultiValueProperty)
                {
                    $item.($property.Name) += $value;
                }
                else 
                {
                    $item.($property.Name) = $value;
                }
            };
        }
    }

    if ($item)
    {
        Write-Output $item;
    }
}


#
# Public functions
#

function Get-NetshHttpUrlAcl
{
    [CmdletBinding()]
    param([string]$Url, [string]$User);

    if ($Url)
    {
        $lines = "http show urlacl url=$Url" | netsh;
    }
    else
    {
        $lines = "http show urlacl" | netsh;
    }

    $items = Parse-Output -Lines $lines -Template $UrlaclTemplate;

    if ($Url)
    {
        $items = $items | ? { $_.ReservedUrl -eq $Url };
    }

    if ($User)
    {
        $items = $items | ? { $_.Users -contains $User };
    }

    foreach ($item in $items)
    {
        Write-Output $item;
    }
}

function New-NetshHttpUrlAcl
{
    [CmdletBinding()]
    param([string]$Url, [string]$User);

    Confirm-RunAsAdmin -Command $MyInvocation.MyCommand;

    $lines = "http add urlacl url=$Url user=$User" | netsh;
    if (!$lines.Contains("URL reservation successfully added"))
    {
        throw $lines;
    }

    Get-NetshHttpUrlAcl -Url $url -User $User;
}

function Remove-NetshHttpUrlAcl
{
    [CmdletBinding()]
    param([string]$Url);

    Confirm-RunAsAdmin -Command $MyInvocation.MyCommand;

    $lines = "http delete urlacl url=$Url" | netsh;
    if (!$lines.Contains("URL reservation successfully deleted"))
    {
        throw $lines;
    }
}

function Get-NetshHttpSslcert
{
    [CmdletBinding()]
    param([string]$Ip = "0.0.0.0", [int]$Port, [string]$CertificateHash);

    if ($PSBoundParameters.ContainsKey("Port"))
    {
        $lines = "http show sslcert ipport=${Ip}:${Port}" | netsh;
    }
    else
    {
        $lines = "http show sslcert" | netsh;
    }

    $items = Parse-Output -Lines $lines -Template $SslcertTemplate;

    if ($Ip)
    {
        $items = $items | ? { $_.Ip -eq $Ip };
    }

    if ($Port)
    {
        $items = $items | ? { $_.Port -eq $Port };
    }

    if ($CertificateHash)
    {
        $items = $items | ? { $_.CertificateHash -eq $CertificateHash };
    }

    foreach ($item in $items)
    {
        Write-Output $item;
    }
}

function New-NetshHttpSslcert
{
    [CmdletBinding()]
    param(
        [string]$Ip = "0.0.0.0", 
        [Parameter(Mandatory=$true)][int]$Port, 
        [Parameter(Mandatory=$true)][string]$CertificateHash, 
        [Parameter(Mandatory=$true)][guid]$ApplicationId);

    Confirm-RunAsAdmin -Command $MyInvocation.MyCommand;

    $lines = "http add sslcert ipport=${Ip}:${Port} certhash=$CertificateHash appid=$($ApplicationId.ToString("b"))" | netsh;
    if (!$lines.Contains("SSL Certificate successfully added"))
    {
        throw $lines;
    }

    Get-NetshHttpSslcert -IP $Ip -Port $Port -CertificateHash $CertificateHash;
}

function Remove-NetshHttpSslcert
{
    [CmdletBinding()]
    param([string]$Ip = "0.0.0.0", [int]$Port);

    Confirm-RunAsAdmin -Command $MyInvocation.MyCommand;

    $lines = "http delete sslcert ipport=${Ip}:${Port}" | netsh;
    if (!$lines.Contains("SSL Certificate successfully deleted"))
    {
        throw $lines;
    }
}

#
# Module Initialization
#

Export-ModuleMember -Function Get-NetshHttpUrlAcl;
Export-ModuleMember -Function New-NetshHttpUrlAcl;
Export-ModuleMember -Function Remove-NetshHttpUrlAcl;
Export-ModuleMember -Function Get-NetshHttpSslcert;
Export-ModuleMember -Function New-NetshHttpSslcert;
Export-ModuleMember -Function Remove-NetshHttpSslcert;