Filtering Show-NetIPSec Rules based on IP Address

Get-NetIPSecRule seems a little half-baked.  A coworker asked me to come up with a way to only return IPsec rules for a given address.  I’m surprised Show-NetIPSecRule natively doesn’t have that, nor does each record have the RemoteAddress property, which would be against which I would filter.  I’m not sure I understand the design decisions behind it, nor Get-NetFirewallAddressFilter.  Either way, I had to caveman a solution.

 

 function Get-NetIpSecRuleByIPAddress
{
    <#
    .synopsis
    Extend Show-NetIPSecRule to allow filtering by IP address on the output of the corresponding Get-NetFirewallAddressFilter.

    .parameter IPAddress
    IP address on which to filter.

    .parameter ShowRemoteAddress.
    Return remote address(es) from Get-NetFilrewallAddressFilter, one per record.

    .parameter AsObject
    Return all IPSec rules and Get-NetFirewallAddressFilter output.

    .notes
    I'm surprised this isn't in the basic functionality.

    This complicated by the fact that Show-NetIPSecRule returns objects of a few different base types, so not everything has the same schema.

    #>

    param (
        [parameter(Mandatory=$true)]
        [string]$IPAddress ,

        [switch]$ShowRemoteAddress,

        [switch]$AsObject
    );

    $local:ErrorActionPreference = 'stop';

    # stop trying to search for the dang module path
    $local:PSModuleAutoLoadingPreference = 'none';

    Import-Module NetSecurity

    Write-Progress -Activity (Get-Date) -Status "Retrieving NetIPSecRules";

    $allRules = Show-NetIPSecRule -ErrorAction SilentlyContinue -ErrorVariable errorVariable -PolicyStore ActiveStore |
    Select-Object -Property @{
        n = 'IPSecRule'; e = { $_; }
    }, @{
        n = 'Filter'; e = { $_ | Get-NetFirewallAddressFilter }
    } |
    Where-Object { $_.Filter; }

   if ($errorVariable)
    {
        $message = $errorVariable[0].Exception.Message;

        if ($message -match 'Access is denied')
        {
            Write-Warning "You must be in a 'Run As Administrator'PowerShell session to execute this cmdlet.";

        } # if ($message ...
        else
        {
            Write-Warning $message;

        } # if ($message ... else

        return;

    } # if ($errorVariable)

    if (!$allRules)
    {
        Write-Warning "Show-NetIPSecRule returned no data";
        return;

    } # if (!$allRules

    Write-Progress -Activity (Get-Date) -Status "Filtering for $IPAddress";

    $rules = $allRules |
    Where-Object {
        $_.Filter.RemoteAddress -match $IPAddress;
    } # $rules = $allRules ...

    if (!$rules)
    {
        Write-Warning "no match for $IPAddress";
        return;

    } # if (!$rules)

    if ($AsObject)
    {
        $rules;
        return;

    } # if ($AsObject

    foreach ($rule in $rules)
    {
        $baseObject = $rule.IPSecRule |
        Select-Object -Property IPAddress, DisplayName, Platform, Enabled, InboundSecurity, OutboundSecurity;

        $baseObject.IpAddress = $IPAddress;

        # $_.Platform is a string array!
        foreach ($platform in $rule.IPSecRule.Platform)
        {
            $object = $baseObject;
            $object.Platform = $platform;

            if ($ShowRemoteAddress)
            {
                foreach ($remoteAddress in $rule.Filter.RemoteAddress)
                {
                    $object |
                    Select-Object -Property IPAddress, DisplayName, Platform, Enabled, InboundSecurity, OutboundSecurity, @{
                        n = 'RemoteAddress';
                        e = { $remoteAddress }

                    } # $object | Select-Object ...

                } # foreach ($remoteAddress ...

            } # if ($ShowRemoteAddress)

        } # foreach ($platform in $rule.IPSecRule.Platform)

    } # foreach ($rule in $rules)

    if ($object)
    {
        $object;

    } # if ($object)
    else
    {
        Write-Warning "somehow we didn't get any data.  go bug a dev."
    } # if ($object) ... else

} # function Get-NetIpSecRuleByIPAddress