Always On VPN depoyment with SCCM

I usually want some kind of ticket back when i send configurations to the clients. With Active Directory Group Policies you will never know if all those fancy scripts of yours actually did something. If you have SCCM in your environment you could/should do it with more accuracy, get the status and remediate clients that do not comply.That is why i made custom AOVPN deployment script in Powershell that can use versioning when you need to upgrade your clients, change some ip range or whatever.
Microsoft has a standard procedure that you can read about here, i borrowed most of the code and added some lines that should work with other deployment software, SCCM, Zenworks, Altiris etc.
  • Alt 1: You will need only one file, Powershell script with everything (XML) embedded

  • Alt 2: You'll need 2 files: Powershell script and XML as a separate file with configuration parameters for your VPN network.
In this case i used machine-certificate IKEv2 type of configuration because it should work right "out-of-the-box" with machines that are members of Active Directory with properly issued machine certificate, no fuss about user accounts or logging in at your workplace before you take your computer home like you have to do with Direct Access (also one of MS VPN technologies).
This is also a "split" version that forces clients to use their own Internet connection for other sites than those that are NOT in XML-file, otherwise will all of the clients traffic go through your own corporate network. Here is alternative XML that runs everything through your own company network.

Prepare XML file with care, examples from MS are OK but they don't tackle every scenario.

Powershell script is only a tool to import this XML properly. My Powershell script will also write some registry values that are needed for detection of XML version and the type of configuration.
It will also raise VPN's network card IpInterfaceMetric to be the first card to discover correct ip-ranges.

MOST IMPORTANT!
If you're just testing, you cannot run this script as ADMIN, it won't work, you'll need to run this with SYSTEM account. This works fine if it's deployed by GPO or SCCM because they already use SYSTEM account by default. When you're done you can test your AOVPN with RASPHONE command.

There are several different programs that can elevate your administrator account to SYSTEM account:


I will not explain how to use those programs, if you can't grasp it than you shouldn't work with this at all.
Finally, here is Powershell script with XML-embedded inside PS1.
Change to your own environment.
Use it as a logon script via Group Policy or deploy by other means, like SCCM or LANSweeper.

<# .DESCRIPTION Script to create Always On VPN connection per device .NOTES Version: Stored in variable $Aovpnversion , change after editing XML file Author: Denis Sahuric Creation Date: 2021-04-09 Purpose/Change: Script to create Always On VPN connection per device Using AOVPN.XML extracted file for configuration Creates registry keys for SCCM detection of version This one is for use with GPO - everything is embedded so only one script is needed XML file is embedded #> ## SWEDISH: Versionsnummer, byt efter uppdatering av XML eller PS1 ## Version number, change after updating external XML or embedded XML in this PS1 $Aovpnversion = "1.0.4" ## SWEDISH: Namn som ska visas som anslutning ## RAS Phone name that is shown when connected $ProfileName = 'My Contoso VPN' ## SWEDISH: Path till register där värdena ska lagras: ## Path to registry with values to check: $regPath = 'HKLM:\Software\Contoso\AOVPN' $TunnelType = "SplitTunnel" # Start-Transcript -Path C:\Temp\AOVPN.log ## Check if AOVPN present and exit if everything is OK $AOVPNras=Test-Path -Path "C:\ProgramData\Microsoft\Network\Connections\Pbk\rasphone.pbk" -PathType Leaf If (Test-Path -Path $regPath) { $AOVPNvers=(Get-Itemproperty $regPath).Version $AOVPNrouting=(Get-Itemproperty $regPath).RoutingPolicyType If (($AOVPNras) -and ($AOVPNvers -eq $Aovpnversion) -and ($AOVPNrouting -eq $TunnelType)) { #Write-Host "AOVPN finns" #Stop-Transcript Exit } } ## If AOVPN not correctly installed run the rest of the script: ## SWEDISH: Hela VPN config XML-filen - spara i temp mappen ## Here is the whole config XML-file that is saved to a temporary folder $KKXML = @" <VPNProfile> <AlwaysOn>true</AlwaysOn> <DeviceTunnel>true</DeviceTunnel> <DnsSuffix>Contoso.local</DnsSuffix> <!-- The RegisterDNS element is optional and used to register the IP address of the device tunnel VPN connection in internal DNS. If a user tunnel is deployed in conjunction with a device tunnel, this element should only be defined on the device tunnel --> <RegisterDNS>true</RegisterDNS> <TrustedNetworkDetection>Contoso.local</TrustedNetworkDetection> <DomainNameInformation> <DomainName>.Contoso.local</DomainName> <DnsServers>192.168.7.230,192.168.7.231</DnsServers> </DomainNameInformation> <DomainNameInformation> <DomainName>.Contoso.se</DomainName> <DnsServers>192.168.7.230,192.168.7.231</DnsServers> </DomainNameInformation> <!-- The DomainNameInformation element is optional. It should only be used when the DNS servers configured on the VPN server's network interface can't resolve internal Active Directory hostnames --> <!-- More information regarding DNS configuration for Always On VPN can be found here: https://rmhci.co/2L2quNk --> <NativeProfile> <Servers>aovpn.Contoso.se</Servers> <RoutingPolicyType>SplitTunnel</RoutingPolicyType> <!-- Only IKEv2 is supported for use with the Always On VPN device tunnel --> <NativeProtocolType>IKEv2</NativeProtocolType> <!-- Only machine certificates authentication is supported for use with the Always On VPN device tunnel --> <Authentication> <MachineMethod>Certificate</MachineMethod> </Authentication> <!-- This setting is optional but recommended --> <!-- The CryptographySuite setting is optional but recommended when using IKEv2. The default security settings for IKEv2 are extremely weak. Details here: https://rmhci.co/2Eou3Op --> <!-- Enabling this setting requires the VPN server to use matching settings. A PowerShell script to configure Windows Server RRAS servers can be found here: https://rmhci.co/2WRpFgl --> <CryptographySuite> <AuthenticationTransformConstants>SHA256128</AuthenticationTransformConstants> <CipherTransformConstants>AES128</CipherTransformConstants> <EncryptionMethod>AES128</EncryptionMethod> <IntegrityCheckMethod>SHA256</IntegrityCheckMethod> <DHGroup>Group14</DHGroup> <PfsGroup>PFS2048</PfsGroup> </CryptographySuite> <DisableClassBasedDefaultRoute>true</DisableClassBasedDefaultRoute> </NativeProfile> <Route> <!-- SERVER AND NETWORK --> <Address>192.168.0.0</Address> <PrefixSize>16</PrefixSize> </Route> <Route> <!-- SCHOOL CLIENT --> <Address>20.0.0.0</Address> <PrefixSize>8</PrefixSize> </Route> <Route> <!-- CONTOSO CLIENT --> <Address>172.86.0.0</Address> <PrefixSize>12</PrefixSize> </Route> <Route> <!-- PHONE --> <Address>198.59.0.0</Address> <PrefixSize>15</PrefixSize> </Route> <Route> <!-- DMZ --> <Address>193.87.32.0</Address> <PrefixSize>24</PrefixSize> </Route> <Route> <!-- SPECIAL 1 --> <Address>197.245.133.0</Address> <PrefixSize>24</PrefixSize> </Route> <Route> <!-- SPECIAL 1 --> <Address>79.80.5.174</Address> <PrefixSize>32</PrefixSize> </Route> <Route> <!-- Contoso.another.com --> <Address>184.15.222.77</Address> <PrefixSize>32</PrefixSize> </Route> <!-- The Route setting is required when DisableClassBasedDefaultRoute is set to "true" --> <!-- Host routes (/32) should be used to restrict access over the device tunnel to domain controllers. Using traffic filters isn't recommended as it prevents outbound management --> </VPNProfile> "@ ## Save XML file.. ## Write-Host "Putting XML to temp file" Set-Content -Path $env:temp\AOVPN.xml -Value $KKXML ## SWEDISH: Ta bort befintlig VPN profil för Device: ## Remove any existing VPN profile for device: $Count = 1 Do { $Count++ If($Count -gt 10) {break} $vpnconn = Get-VpnConnection -AllUserConnection | select -ExpandProperty Name if($vpnconn) { Start-Sleep -Seconds 3 rasphone.exe -h $vpnconn Get-VpnConnection -AllUserConnection | Remove-VpnConnection -Force -ErrorAction SilentlyContinue } } While ($vpnconn) ## End Ta bort befintlig VPN ## SWEDISH: Ta bort tidigare registernycklar om de finns: ## Remove registry keys associated to VPN if any: if(Test-Path $regPath){ Remove-Item -Path $regPath -Recurse -Force } ## End Ta bort registernycklar ## SWEDISH: Hämta XML profil: ## Get this new VPN XML profile: $ProfileXML = Get-Content $env:temp\AOVPN.xml $ProfileNameEscaped = $ProfileName -replace ' ', '%20' $ProfileXML = $ProfileXML -replace '<', '&lt;' $ProfileXML = $ProfileXML -replace '>', '&gt;' $ProfileXML = $ProfileXML -replace '"', '&quot;' ## SWEDISH: Egen läsning av XML för att senare skriva till Registry ## Read things to write later on to registry [xml]$XmlDocument = Get-Content $env:temp\AOVPN.xml $Tunnel = $XmlDocument.VPNProfile.NativeProfile.RoutingPolicyType $Servers = $XmlDocument.VPNProfile.NativeProfile.Servers $DeviceTunnel = $XmlDocument.VPNProfile.DeviceTunnel $AlwaysOn = $XmlDocument.VPNProfile.AlwaysOn ## End egen XML läsning $nodeCSPURI = './Vendor/MSFT/VPNv2' $namespaceName = "root\cimv2\mdm\dmmap" $className = "MDM_VPNv2_01" $session = New-CimSession try { $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) $Message = "Created $ProfileName profile." Write-Host "$Message" } catch [Exception] { $Message = "Unable to create $ProfileName profile: $_" Write-Host "$Message" exit } ## SWEDISH: Ge VPN tid att koppla upp sig om datorn är utanför Contoso: ## Give VPN some time to connect if outside of Contoso: Start-Sleep -Seconds 3 ## SWEDISH: Registrera versionsnummer i registry: ## Write AOVPN version to registry: New-Item $regPath -Force | Out-Null New-ItemProperty $regPath -Name Name -Value $ProfileName -PropertyType "String" -Force | Out-Null New-ItemProperty $regPath -Name Version -Value $Aovpnversion -PropertyType "String" -Force | Out-Null New-ItemProperty $regPath -Name RoutingPolicyType -Value $Tunnel -PropertyType "String" -Force | Out-Null New-ItemProperty $regPath -Name Servers -Value $Servers -PropertyType "String" -Force | Out-Null New-ItemProperty $regPath -Name AlwaysOn -Value $AlwaysOn -PropertyType "String" -Force | Out-Null ## SWEDISH: Hitta minsta interfacemetric: ## Find lowest interfacemetric: $Minimum = Get-NetIPInterface | Measure-Object -Property InterfaceMetric -Minimum | select -ExpandProperty Minimum ## SWEDISH: Om VPN blev aktiv sänk NIC metric för den: ## If VPN is active than lower NIC metric: If(Get-NetIPInterface -InterfaceAlias $ProfileName -ea SilentlyContinue) { Set-NetIPInterface -InterfaceAlias $ProfileName -InterfaceMetric ($Minimum - 1) } ## SWEDISH: Ändra IpInterfaceMetric i Rasphone.pbk: ## Change IpInterfaceMetric in Rasphone.pbk: $broj = $Minimum - 1 $NewInterface = 'IpInterfaceMetric=' + $broj $file = 'C:\ProgramData\Microsoft\Network\Connections\Pbk\rasphone.pbk' $line = Get-Content $file | Select-String "IpInterfaceMetric=" | Select-Object -ExpandProperty Line if ($line -eq $null) { } else { $content = Get-Content $file $content | ForEach-Object {$_ -replace $line,$NewInterface} | Set-Content $file } Write-Host "AOVPN installerad" ## SWEDISH: Rensa efter installationen ## Clenup after installing Remove-Item $env:temp\AOVPN.xml ## Stop-Transcript

Comments