Public/Add-NSPNpsVpnPolicySet.ps1

function Add-NSPNpsVpnPolicySet {
    <#
    .SYNOPSIS
        Adds the standard VPN Network Policy set to NPS - Combined, IPSec-only and SSLVPN-only - from
        group names, without the NPS Manager menus. Supports -WhatIf.
    .DESCRIPTION
        The engine NPS Manager's "Import Kickstart Definitions" uses (Add-NPSPolicySet): ias.xml is
        backed up, the new policies are inserted at -InsertAtSequence (existing ones shift down), and
        each policy matches the RADIUS client address plus group membership:
          IPSec-only a member of any -IPSecGroup
          SSLVPN-only a member of any -SSLVPNGroup
          Combined both
        With no -SSLVPNGroup only the IPSec-only policy is added. Each policy returns
        Fortinet-Group-Name VSAs: -IPSecVsaGroupName / -SSLVPNVsaGroupName, defaulting to the required
        group names in lower case. Groups may be names or SIDs; names are resolved in AD. Run on the
        NPS server, elevated; restart NPS (or let NPS Manager do it) to load the change.
    .PARAMETER BaseName
        Policy base name, e.g. 'RADIUS - Staff' (the three policies are named from it).
    .PARAMETER ClientIPAddress
        The RADIUS client (FortiGate) address the policies match.
    .PARAMETER IPSecGroup
        Group(s) granting IPSec access - membership of any one is enough.
    .PARAMETER SSLVPNGroup
        Group(s) granting SSLVPN access.
    .PARAMETER IPSecVsaGroupName
        Fortinet-Group-Name value(s) the IPSec policies send.
    .PARAMETER SSLVPNVsaGroupName
        Fortinet-Group-Name value(s) the SSLVPN policies send.
    .PARAMETER InsertAtSequence
        Processing order of the first new policy. Default 1 (top).
    .PARAMETER IASConfigPath
        ias.xml. Default: %SystemRoot%\System32\ias\ias.xml.
    .EXAMPLE
        Add-NSPNpsVpnPolicySet -BaseName 'RADIUS - Staff' -ClientIPAddress 192.0.2.1 -IPSecGroup IKEv2_Staff -WhatIf
    #>

    [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Medium')]
    param(
        [Parameter(Mandatory)][string]$BaseName,
        [Parameter(Mandatory)][ValidatePattern('^\d{1,3}(\.\d{1,3}){3}$')][string]$ClientIPAddress,
        [Parameter(Mandatory)][string[]]$IPSecGroup,
        [string[]]$SSLVPNGroup,
        [string[]]$IPSecVsaGroupName,
        [string[]]$SSLVPNVsaGroupName,
        [ValidateRange(1, 999000)][int]$InsertAtSequence = 1,
        [string]$IASConfigPath = (Join-Path $env:SystemRoot 'System32\ias\ias.xml')
    )
    if (-not (Test-Path -LiteralPath $IASConfigPath)) { throw "ias.xml not found at $IASConfigPath - run this on the NPS server." }
    $resolve = { param([string[]]$Groups) , @(foreach ($g in $Groups) { if ($g -match '^S-1-5-\d+(-\d+)+$') { $g } else { Get-ADGroupSID -GroupNameOrSID $g } }) }
    $ipsecSids = & $resolve $IPSecGroup
    $sslvpnSids = if ($SSLVPNGroup) { & $resolve $SSLVPNGroup } else { $ipsecSids }
    $ipsecVsa = if ($IPSecVsaGroupName) { $IPSecVsaGroupName } else { @($IPSecGroup | ForEach-Object { $_.ToLowerInvariant() }) }
    $sslvpnVsa = if ($SSLVPNVsaGroupName) { $SSLVPNVsaGroupName } elseif ($SSLVPNGroup) { @($SSLVPNGroup | ForEach-Object { $_.ToLowerInvariant() }) } else { $ipsecVsa }
    $kinds = if ($SSLVPNGroup) { @('Combined', 'IPSecOnly', 'SSLVPNOnly') } else { @('IPSecOnly') }

    $engineArgs = @{
        Path = $IASConfigPath; BaseName = $BaseName; ClientIPAddress = $ClientIPAddress
        IPSecGroupSidSets = @(, $ipsecSids); SSLVPNGroupSidSets = @(, $sslvpnSids)
        IPSecVsaGroupNames = @($ipsecVsa); SSLVPNVsaGroupNames = @($sslvpnVsa)
        InsertAtSequence = $InsertAtSequence; Kinds = $kinds
    }
    if (-not $PSCmdlet.ShouldProcess($IASConfigPath, "Add $($kinds.Count) Network Policies '$BaseName' ($($kinds -join ', ')) at sequence $InsertAtSequence")) {
        return Add-NPSPolicySet @engineArgs -WhatIf
    }
    Add-NPSPolicySet @engineArgs
}