教程:在 Windows 客户端设备上创建 Always On VPN 连接

本教程介绍如何在 Windows 客户端设备上创建 AlwaysOn VPN 连接。 该系列将继续在示例环境中部署 AlwaysOn VPN。 在系列中之前,你 部署了一个示例基础结构配置了证书颁发机构模板

在本教程中,你将:

  • 创建并测试一个用于 Always On VPN 连接模板的手动用户 VPN 连接。
  • 使用 PowerShell 将手动 VPN 连接转换为 AlwaysOn VPN 连接。

AlwaysOn VPN 连接可配置为设备隧道或用户隧道:

  • 设备隧道:在用户登录到设备之前连接到指定的 VPN 服务器。 设备隧道用于预登录连接方案和设备管理目的。

  • 用户隧道:仅在用户登录到设备后进行连接。 用户隧道允许用户通过 VPN 服务器访问组织资源。

有关设备隧道与用户隧道之间的差异的详细信息,请参阅 在 Windows 客户端中配置 VPN 设备隧道

AlwaysOn VPN 连接(无论是设备隧道还是用户隧道)是使用 VPNv2 配置服务提供程序(CSP)中的 ProfileXML 节点配置的。 本教程中的步骤演示如何在单个 Windows 客户端设备上配置用户隧道。 可以将这些步骤用于小型环境或测试目的。

对于较大的环境,应使用 Microsoft Intune 或 Microsoft Configuration Manager 将 AlwaysOn VPN 配置文件部署到 Windows 客户端设备。 有关详细信息,请参阅使用 Microsoft Intune 将 AlwaysOn VPN 配置文件部署到 Windows 客户端 ,并使用 Microsoft Configuration Manager 将 AlwaysOn VPN 配置文件部署到 Windows 客户端

先决条件

完成本教程中的步骤需要具备以下各项:

创建并测试手动用户 VPN 连接

首先,需要创建 VPN 客户端连接,以验证 VPN 测试客户端是否可以建立成功的 VPN 连接。 通过此连接,还可以创建用于 AlwaysOn VPN 连接的可扩展身份验证协议(EAP)设置。 有关 EAP 设置的详细信息,请参阅 EAP 配置

  1. 以之前在 “创建 Active Directory”测试用户中创建的 VPN 用户身份登录到已加入域的 Windows 客户端设备。

  2. 在“开始”菜单上,键入 VPN 以选择 VPN 设置。 按 Enter。

  3. 在详细信息窗格中,选择 “添加 VPN 连接”。

  4. 对于 VPN 提供程序,请选择“Windows”(内置)。

  5. 对于 连接名称,请输入 Contoso VPN

  6. 对于 服务器名称或地址,输入您的 VPN 服务器的外部完全限定域名(例如,vpn.contoso.com)。

  7. 对于 VPN 类型,请选择 IKEv2

  8. 对于“登录信息的类型”,请选择“证书”。

  9. 选择“ 保存”。

  10. “相关设置”下,选择“ 更改适配器”选项

  11. 右键单击 Contoso VPN,然后选择 “属性”。

  12. 在“ 安全性 ”选项卡上,对于 数据加密,请选择 “最大强度加密”。

  13. 选择“使用可扩展身份验证协议”(EAP)。 然后,对于使用可扩展身份验证协议(EAP),请选择Microsoft:受保护的 EAP(PEAP)(已启用加密)。

  14. 选择 “属性 ”以打开 受保护的 EAP 属性,并完成以下步骤:

    1. 对于 连接到这些服务器,请输入 NPS 服务器的主机名。

    2. 对于受信任的根证书颁发机构,请选择颁发 NPS 服务器证书的 CA(例如 contoso-CA)。

    3. 对于 连接前的通知,请选择 “不要要求用户授权新服务器或受信任的 CA”。

    4. 对于 “选择身份验证方法”,请选择 “智能卡”或其他证书

    5. 选择“ 配置”。

      1. 选择“ 在此计算机上使用证书”。

      2. 对于 连接到这些服务器,请输入 NPS 服务器的主机名。

      3. 对于 受信任的根证书颁发机构,请选择颁发 NPS 服务器的证书的 CA。

      4. 选择 “不提示用户授权新服务器或受信任的证书颁发机构”。

      5. 选择 “确定” 关闭 智能卡或其他证书属性

      6. 选择 “确定 ”关闭 受保护的 EAP 属性

    6. 选择 “确定 ”关闭 Contoso VPN 属性

  15. 关闭“网络连接”窗口。

  16. 在“设置”中,选择 “Contoso VPN”,然后选择“ 连接”。 应成功建立 VPN 连接。 可以通过检查“ 网络连接” 窗口来验证连接。 Contoso VPN 连接应显示为“已连接”。 测试你是否可以连接到 VPN 隧道另一端的资源,例如文件共享或 Web 服务器。

  17. 验证 VPN 连接是否成功后,请断开与 VPN 连接的连接。

重要

确保模板 VPN 成功连接到 VPN 服务器。 这样做可确保 EAP 设置在下一部分使用之前是正确的。 在继续作之前,必须至少连接一次;否则,配置文件不包含连接到 VPN 所需的所有信息。

将手动 VPN 连接转换为 AlwaysOn VPN 连接

接下来,使用 PowerShell 脚本将手动 VPN 连接转换为 AlwaysOn VPN 连接。

  1. 与 Windows 客户端设备上的同一用户一样,以管理员身份打开 Windows PowerShell ISE

  2. 将以下 PowerShell 脚本复制并粘贴到 Windows PowerShell ISE 编辑器窗口中,然后请务必更改自己的八个变量值。

    展开此部分以显示 PowerShell 脚本。
    # Set the variables for the VPN profile.
    $___domain = 'corp' # Name of the ___domain.
    $templateName = 'Contoso VPN' # Name of the test VPN connection you created in the tutorial. 
    $profileName = 'Contoso AlwaysOn VPN' # Name of the profile we are going to create.
    $servers = 'aov-vpn.contoso.com' # Public or routable IP address or DNS name for the VPN gateway.
    $dnsSuffix = 'corp.contoso.com' # Specifies one or more commas separated DNS suffixes. 
    $domainName = '.corp.contoso.com' # Used to indicate the namespace to which the policy applies. Contains `.` prefix.
    $dnsServers = '10.10.0.6' # List of comma-separated DNS Server IP addresses to use for the namespace.
    $trustedNetwork = 'corp.contoso.com' # Comma-separated string to identify the trusted network.
    
    # Get the EAP settings for the current profile called $templateName
    $connection = Get-VpnConnection -Name $templateName
    
    if(!$connection)
    {
        $message = "Unable to get $templateName connection profile: $_"
        Write-Host "$message"
        exit
    }
    
    $EAPSettings= $connection.EapConfigXmlStream.InnerXml
    
    $profileNameEscaped = $profileName -replace ' ', '%20'
    
    # Define ProfileXML
    $profileXML = @("
    <VPNProfile>
      <DnsSuffix>$dnsSuffix</DnsSuffix>
      <NativeProfile>
    <Servers>$servers</Servers>
    <NativeProtocolType>IKEv2</NativeProtocolType>
    <Authentication>
      <UserMethod>Eap</UserMethod>
      <Eap>
        <Configuration>
        $EAPSettings
        </Configuration>
      </Eap>
    </Authentication>
    <RoutingPolicyType>SplitTunnel</RoutingPolicyType>
      </NativeProfile>
    <AlwaysOn>true</AlwaysOn>
    <RememberCredentials>true</RememberCredentials>
    <TrustedNetworkDetection>$trustedNetwork</TrustedNetworkDetection>
      <DomainNameInformation>
    <DomainName>$domainName</DomainName>
    <DnsServers>$dnsServers</DnsServers>
    </DomainNameInformation>
    </VPNProfile>
    ")
    
    # Output the XML for possible use in Intune
    $profileXML | Out-File -FilePath ($env:USERPROFILE + '\desktop\VPN_Profile.xml')
    
    # Escape special characters in the profile (<,>,")
    $profileXML = $profileXML -replace '<', '&lt;'
    $profileXML = $profileXML -replace '>', '&gt;'
    $profileXML = $profileXML -replace '"', '&quot;'
    
    # Define WMI-to-CSP Bridge properties
    $nodeCSPURI = "./Vendor/MSFT/VPNv2"
    $namespaceName = "root\cimv2\mdm\dmmap"
    $className = "MDM_VPNv2_01"
    
    try
    {
    
        # Determine user SID for VPN profile.
        $WmiLoggedOnUsers = (Get-WmiObject Win32_LoggedOnUser).Antecedent
        If($WmiLoggedOnUsers.Count -gt 1) { 
            $WmiLoggedOnUsers = $WmiLoggedOnUsers -match "Domain=""$___domain"""
        }
    
        $WmiUserValid = ($WmiLoggedOnUsers | Select-Object -Unique -First 1) -match 'Domain="([^"]+)",Name="([^"]+)"'
    
        If(-not $WmiUserValid){
            Throw "Returned object is not a valid WMI string"
        }
    
        $UserName = "$($Matches[1])\$($Matches[2])"
    
        $ObjUser = New-Object System.Security.Principal.NTAccount($UserName)
        $Sid = $ObjUser.Translate([System.Security.Principal.SecurityIdentifier])
        $SidValue = $Sid.Value
        $message = "User SID is $SidValue."
    
        Write-Host "$message"
    
    }
    catch [Exception] 
    {
    
        $message = "Unable to get user SID. $_"
        Write-Host "$message" 
        exit
    }
    
    try 
    {
    
        # Define WMI session.
        $session = New-CimSession
        $options = New-Object Microsoft.Management.Infrastructure.Options.CimOperationOptions
        $options.SetCustomOption("PolicyPlatformContext_PrincipalContext_Type", "PolicyPlatform_UserContext", $false)
        $options.SetCustomOption("PolicyPlatformContext_PrincipalContext_Id", "$SidValue", $false)
    
    }
    catch {
    
        $message = "Unable to create new session for $profileName profile: $_"
        Write-Host $message
        exit
    }
    
    try
    {
    
        # Detect and delete previous VPN profile.
        $deleteInstances = $session.EnumerateInstances($namespaceName, $className, $options)
    
        foreach ($deleteInstance in $deleteInstances)
        {
            $InstanceId = $deleteInstance.InstanceID
            if ("$InstanceId" -eq "$profileNameEscaped")
            {
                $session.DeleteInstance($namespaceName, $deleteInstance, $options)
                $message = "Removed $profileName profile $InstanceId" 
                Write-Host "$message"
            }
            else 
            {
                $message = "Ignoring existing VPN profile $InstanceId"
                Write-Host "$message"
            }
        }
    }
    catch [Exception]
    {
        $message = "Unable to remove existing outdated instance(s) of $profileName profile: $_"
        Write-Host $message
        exit
    
    }
    
    try
    {
    
        # Create the VPN profile.
        $newInstance = New-Object Microsoft.Management.Infrastructure.CimInstance $className, $namespaceName
        $property = [Microsoft.Management.Infrastructure.CimProperty]::Create("ParentID", "$nodeCSPURI", "String", "Key")
        $newInstance.CimInstanceProperties.Add($property)
        $property = [Microsoft.Management.Infrastructure.CimProperty]::Create("InstanceID", "$profileNameEscaped", "String", "Key")
        $newInstance.CimInstanceProperties.Add($property)
        $property = [Microsoft.Management.Infrastructure.CimProperty]::Create("ProfileXML", "$profileXML", "String", "Property")
        $newInstance.CimInstanceProperties.Add($property)
        $session.CreateInstance($namespaceName, $newInstance, $options)
    
        $message = "Created $profileName profile."
        Write-Host "$message"
    
    }
    catch [Exception]
    {
    
        $message = "Unable to create $profileName profile: $_"
        Write-Host "$message"
        exit
    }
    
    $message = "Always On VPN connection created successfully."
    Write-Host "$message"
    
  3. 运行脚本。

  4. 通过在编辑器窗口中运行以下命令 Windows PowerShell ISE 来验证脚本是否成功:

    Get-CimInstance -Namespace root\cimv2\mdm\dmmap -ClassName MDM_VPNv2_01
    

    输出应类似于以下示例( ProfileXML 该值因可读性被截断):

    AlwaysOn                : True
    ByPassForLocal          : 
    DeviceTunnel            : 
    DnsSuffix               : corp.contoso.com
    EdpModeId               : 
    InstanceID              : Contoso%20AlwaysOn%20VPN
    LockDown                : 
    ParentID                : ./Vendor/MSFT/VPNv2
    ProfileXML              : <VPNProfile>...</VPNProfile>
    RegisterDNS             : 
    RememberCredentials     : True
    TrustedNetworkDetection : corp.contoso.com
    PSComputerName          : 
    
  5. 应成功创建并建立 AlwaysOn VPN 连接。 可以通过检查“ 网络连接” 窗口来验证连接。 Contoso Always On VPN 连接应显示为“已连接”。 测试你是否可以连接到 VPN 隧道另一端的资源,例如文件共享或 Web 服务器。

现在使用 AlwaysOn VPN 连接连接到 VPN 服务器,下面是一些额外的资源,可帮助你进行 AlwaysOn VPN 部署: