-
Notifications
You must be signed in to change notification settings - Fork 3
/
New-AovpnUserTunnel.ps1
243 lines (213 loc) · 9.02 KB
/
New-AovpnUserTunnel.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
<#
.SYNOPSIS
Creates an Always On VPN user tunnel connection
.PARAMETER xmlFilePath
Path to the ProfileXML configuration file
.PARAMETER ProfileName
Name of the VPN profile to be created
.EXAMPLE
.\New-AovpnUserTunnel.ps1 -xmlFilePath "C:\Temp\User.xml" -ProfileName "Always On VPN User Tunnel"
.DESCRIPTION
This script will create an Always On VPN user tunnel on supported Windows 10 devices
.LINK
https://github.com/ConfigJon/AlwaysOnVPN/blob/master/New-AovpnUserTunnel.ps1
.NOTES
Creation Date: May 28, 2019
Last Updated: August 17, 2020
Note: This is a modified version of a script that Richard Hicks has on his GitHub
Original Script: https://github.com/richardhicks/aovpn/blob/master/New-AovpnConnection.ps1
#>
[CmdletBinding()]
Param(
[Parameter(Mandatory = $True, HelpMessage = 'Enter the path to the ProfileXML file.')]
[string]$xmlFilePath,
[Parameter(Mandatory = $False, HelpMessage = 'Enter a name for the VPN profile.')]
[string]$ProfileName = 'Always On VPN User Tunnel'
)
#Variables ============================================================================================================
$RegKey = "SOFTWARE\ConfigJon"
$RegValue = "AOVPNUserTunnelVersion"
$UserTunnelVersion = 1
#Functions ============================================================================================================
Function New-RegistryValue
{
[CmdletBinding()]
param(
[String][parameter(Mandatory=$true)][ValidateNotNullOrEmpty()]$RegKey,
[String][parameter(Mandatory=$true)][ValidateNotNullOrEmpty()]$Name,
[String][parameter(Mandatory=$true)][ValidateSet('String','ExpandString','Binary','DWord','MultiString','Qword','Unknown')]$PropertyType,
[String][parameter(Mandatory=$true)][ValidateNotNullOrEmpty()]$Value
)
#Create the registry key if it does not exist
if(!(Test-Path $RegKey))
{
try{New-Item -Path $RegKey -Force | Out-Null}
catch{throw "Failed to create $RegKey"}
}
#Create the registry value
try
{
New-ItemProperty -Path $RegKey -Name $Name -PropertyType $PropertyType -Value $Value -Force | Out-Null
}
catch
{
Write-LogEntry -Value "Failed to set $RegKey\$Name to $Value" -Severity 3
throw "Failed to set $RegKey\$Name to $Value"
}
#Check if the registry value was successfully created
$KeyCheck = Get-ItemProperty $RegKey
if($KeyCheck.$Name -eq $Value)
{
Write-LogEntry -Value "Successfully set $RegKey\$Name to $Value" -Severity 1
}
else
{
Write-LogEntry -Value "Failed to set $RegKey\$Name to $Value" -Severity 3
throw "Failed to set $RegKey\$Name to $Value"
}
}
#Write data to a CMTrace compatible log file. (Credit to SCConfigMgr - https://www.scconfigmgr.com/)
Function Write-LogEntry
{
param(
[parameter(Mandatory = $true, HelpMessage = "Value added to the log file.")]
[ValidateNotNullOrEmpty()]
[string]$Value,
[parameter(Mandatory = $true, HelpMessage = "Severity for the log entry. 1 for Informational, 2 for Warning and 3 for Error.")]
[ValidateNotNullOrEmpty()]
[ValidateSet("1", "2", "3")]
[string]$Severity,
[parameter(Mandatory = $false, HelpMessage = "Name of the log file that the entry will written to.")]
[ValidateNotNullOrEmpty()]
[string]$FileName = "Install-AOVPN-User.log"
)
#Determine log file location
$LogFilePath = Join-Path -Path $LogsDirectory -ChildPath $FileName
#Construct time stamp for log entry
if(-not(Test-Path -Path 'variable:global:TimezoneBias'))
{
[string]$global:TimezoneBias = [System.TimeZoneInfo]::Local.GetUtcOffset((Get-Date)).TotalMinutes
if($TimezoneBias -match "^-")
{
$TimezoneBias = $TimezoneBias.Replace('-', '+')
}
else
{
$TimezoneBias = '-' + $TimezoneBias
}
}
$Time = -join @((Get-Date -Format "HH:mm:ss.fff"), $TimezoneBias)
#Construct date for log entry
$Date = (Get-Date -Format "MM-dd-yyyy")
#Construct context for log entry
$Context = $([System.Security.Principal.WindowsIdentity]::GetCurrent().Name)
#Construct final log entry
$LogText = "<![LOG[$($Value)]LOG]!><time=""$($Time)"" date=""$($Date)"" component=""Install-AOVPN"" context=""$($Context)"" type=""$($Severity)"" thread=""$($PID)"" file="""">"
#Add value to log file
try
{
Out-File -InputObject $LogText -Append -NoClobber -Encoding Default -FilePath $LogFilePath -ErrorAction Stop
}
catch [System.Exception]
{
Write-Warning -Message "Unable to append log entry to $FileName file. Error message at line $($_.InvocationInfo.ScriptLineNumber): $($_.Exception.Message)"
}
}
#Main Program =========================================================================================================
#Set the log directory
$LogsDirectory = "$ENV:ProgramData\AOVPN"
if(!(Test-Path -PathType Container $LogsDirectory))
{
New-Item -Path $LogsDirectory -ItemType "Directory" -Force | Out-Null
}
Write-LogEntry -Value "START - Always On VPN User Tunnel Script" -Severity 1
#Import the Profile XML
Write-LogEntry -Value "Import the user profile XML" -Severity 1
$ProfileXML = Get-Content $xmlFilePath
#Escape spaces in the profile name
$ProfileNameEscaped = $ProfileName -replace ' ', '%20'
$ProfileXML = $ProfileXML -replace '<', '<'
$ProfileXML = $ProfileXML -replace '>', '>'
$ProfileXML = $ProfileXML -replace '"', '"'
#OMA URI information
$NodeCSPURI = './Vendor/MSFT/VPNv2'
$NamespaceName = 'root\cimv2\mdm\dmmap'
$ClassName = 'MDM_VPNv2_01'
#Get the SID of the current user
try
{
Write-LogEntry -Value "Find the SID of the currently logged on user" -Severity 1
$Username = Get-WmiObject -Class Win32_ComputerSystem | Select-Object username
$User = New-Object System.Security.Principal.NTAccount($Username.Username)
$Sid = $User.Translate([System.Security.Principal.SecurityIdentifier])
$SidValue = $Sid.Value
}
catch [Exception]
{
$ErrorMessage = "Unable to get user SID. User may be logged on over Remote Desktop: $_"
Write-LogEntry -Value $ErrorMessage -Severity 3
throw $ErrorMessage
}
Write-LogEntry -Value "Successfully found the user SID: $SidValue ($User)" -Severity 1
#Create a new CimSession
$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)
#Remove previous versions of the user tunnel
try
{
Write-LogEntry -Value "Check for and remove old instances of the user tunnel" -Severity 1
$DeleteInstances = $Session.EnumerateInstances($NamespaceName, $ClassName, $Options)
foreach($DeleteInstance in $DeleteInstances)
{
$InstanceId = $DeleteInstance.InstanceID
if($InstanceId -eq $ProfileNameEscaped)
{
$Session.DeleteInstance($NamespaceName, $DeleteInstance, $Options)
Write-LogEntry -Value "Removed $ProfileName profile $InstanceId" -Severity 1
}
else
{
Write-LogEntry -Value "Ignoring existing VPN profile $InstanceId" -Severity 2
}
}
}
catch [Exception]
{
$ErrorMessage = "Unable to remove existing outdated instance(s) of $ProfileName profile: $_"
Write-LogEntry -Value $ErrorMessage -Severity 3
throw $ErrorMessage
}
#Create the user tunnel
$Error.Clear()
try
{
Write-LogEntry -Value "Construct a new CimInstance object" -Severity 1
$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)
Write-LogEntry -Value "Create the new user tunnel" -Severity 1
$Session.CreateInstance($NamespaceName, $NewInstance, $Options)
Write-LogEntry -Value "Always On VPN user tunnel ""$ProfileName"" created successfully." -Severity 1
}
catch [Exception]
{
$ErrorMessage = "Unable to create ""$ProfileName"" profile: $_"
Write-LogEntry -Value $ErrorMessage -Severity 3
throw $ErrorMessage
}
Write-LogEntry -Value "Successfully created the new user tunnel" -Severity 1
#Create a registry key for detection
if(!($Error))
{
Write-LogEntry -Value "Create the registry key to use for the detection method" -Severity 1
New-PSDrive -PSProvider registry -Root HKEY_USERS -Name HKU
New-RegistryValue -RegKey "HKU:\$($sidvalue)\$($RegKey)" -Name $RegValue -PropertyType DWord -Value $UserTunnelVersion
Remove-PSDrive -Name HKU
}
Write-LogEntry -Value "END - Always On VPN User Tunnel Script" -Severity 1