Change ServerAddress of VPN connection - windows

I have a point-to-site VPN connection configured on 30+ client machines and I just had to change the VPN gateway's address. Of course, that means I have to reconfigure all of the client machines. Rather than do it manually, I was hoping I could create some kind of program or script that I could run which would update things automatically. The only thing I need to change is the server address, everything else should stay the same.
I came across these PowerShell commands Get-VpnConnection and Set-VpnConnection. I can successfully retreive the created VPN connection using this command:
Get-VpnConnection MyConnectionName -AllUserConnection
So I tried using the Set variant:
Set-VpnConnection -Name MyConnectionName -ServerAddress NewServerAddress -AllUserConnection
But this simply returns and does nothing. No error, no effect. Checking the server address with rasphone shows that the old address is still being used.
I can also do this:
$connection = Get-VpnConnection MyConnectionName -AllUserConnection
$connection.ServerName = NewServerAddress
This also doesn't do anything, since I'm pretty sure I'm just updating a variable and not "committing" it.
So how can I update the server address? It doesn't even have to be PowerShell, that was just the best option I could find.

I ended up writing a .NET application using DotRas.
If anyone's interested, here's the code:
Public Const EntryName As String = "VPNEntryNAme"
Public Const NewAddress As String = "NewVPNAddress"
Private Sub B_Update_Click(sender As Object, e As EventArgs) Handles B_Update.Click
Using pbk As New RasPhoneBook()
pbk.Open(RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers))
Dim VPN = pbk.Entries.Where(Function(Entry) Entry.Name = EntryName).FirstOrDefault
If VPN Is Nothing Then
MsgBox("VPN not found!", MsgBoxStyle.Critical)
Exit Sub
End If
VPN.PhoneNumber = NewAddress
VPN.Update()
End Using
Dim cn = RasConnection.GetActiveConnections.Where(Function(c) c.EntryName = EntryName).FirstOrDefault
If cn IsNot Nothing Then
cn.HangUp()
End If
MsgBox("The VPN has now been successfully updated")
End Sub

On my side, everything worked fine when I use
Set-VpnConnection -Name MyConnectionName -ServerAddress = "x.x.x.x"
Maybe you can try to remove the old one and a new one
$Connection = Get-VpnConnection -Name MyConnectionName
Remove-VpnConnection -Name MyConnectionName -Force
$Connection.ServerAddress = "x.x.x.x"
$Connection | Add-VpnConnection

Related

Powershell Extracting sub string from string

i have a String that either be network address or could be host name
$example1 = '\\192.168.3.3\s$\blabla\blabla\bla.txt'
$example2 = '\\srv\s$\blabla\bla.txt'
Im trying to test connection to the servers so i need only the \*****\ part.
$example1 = 192.168.3.3., $example2 = srv
im trying to use the -Match operation but im getting errors, can anyone assist?
There is a quick solution:
$example1.split("\")[2]
Works for both IP address or host names.

WMI CommandLineTemplate Variables Cutting Off

I've been working on a solution to monitor and respond to certain windows services stopping, and I could really use a few hundred extra sets of eyes on this. I'm setting up the WMI subscription in Powershell and the subscription seems to do it's job, but I'm not getting the expected output using the CommandLineTemplate. I'm trying to push the service name, current state, and previous state to a powershell script or executable (same PS script but compiled) but I only get part of the first variable before it cuts off. I've tried formatting the commandlinetemplate multiple different ways, escaping the variables with single/double/escaped quotes, and tried re-ordering the variables, but it always seems to be part of the first and nothing else gets passed. For testing I'm just trying to grab the variables and write them to a log before I move on to the more fun stuff.
Subscription Code:
$instanceFilter = ([wmiclass]"\\.\root\subscription:__EventFilter").CreateInstance()
$instanceFilter.QueryLanguage = "WQL"
$instanceFilter.Query = "select * from __instanceModificationEvent within 5 where targetInstance isa 'win32_Service' AND targetInstance.Name LIKE 'ServiceNamex.%'"
$instanceFilter.Name = "ServiceFilter"
$instanceFilter.EventNamespace = 'root\cimv2'
$result = $instanceFilter.Put()
$newFilter = $result.Path
#Creating a new event consumer
$instanceConsumer = ([wmiclass]"\\.\root\subscription:CommandLineEventConsumer").CreateInstance()
$instanceConsumer.Name = 'ServiceConsumer'
$instanceConsumer.CommandLineTemplate = "C:\Tools\ServiceMonitor.exe `"%TargetInstance.Name%`" `"%TargetInstance.State%`" `"%PreviousInstance.State%`""
$instanceConsumer.ExecutablePath = "C:\Tools\ServiceMonitor.exe"
$result = $instanceConsumer.Put()
$newConsumer = $result.Path
#Bind filter and consumer
$instanceBinding = ([wmiclass]"\\.\root\subscription:__FilterToConsumerBinding").CreateInstance()
$instanceBinding.Filter = $newFilter
$instanceBinding.Consumer = $newConsumer
$result = $instanceBinding.Put()
$newBinding = $result.Path
Target Code (PS1/EXE):
[CmdletBinding()]
param (
[parameter(Position=0)][string]$serviceName = "Error",
[parameter(Position=1)][string]$currentState = "Error",
[parameter(Position=2)][string]$previousState = "Error"
)
Add-Content -path "C:\temp\service.log" -value "$(Get-Date) - The state of $serviceName on $env:Computername has changed from $previousState to $currentState."
If ($currentState -eq "Stopped")
{
Add-Content -path "C:\temp\service.log" -value "$(Get-Date) - Attempting to restart $serviceName."
Start-Service -DisplayName $serviceName
}
Example Output for ServiceNamex.Funct.QA.12 stopping and starting:
10/30/2019 03:52:11 - The state of ServiceNamex.Funct.QA. has changed to Error.
10/30/2019 03:52:16 - The state of ServiceNamex.Funct.QA. has changed to Error.
Chris, It looks like the issue lies in the variables that you're getting from the first script. I'm not sure where you're getting those variables from. The ServiceMonitor.exe application isn't a PS script and I don't see where the subscription calls out to ServiceMonitor.ps1
Just copying your PS lines into a ServiceMonitor.ps1 file, I was able to run the following command and get the subsequent log information.
.\ServiceMonitor.ps1 TestService Running Stopped
11/01/2019 11:01:24 - The state of TestService on 7D25PX1 has changed from Stopped to Running.
11/01/2019 11:13:11 - The state of TestService on 7D25PX1 has changed from Stopped to Running.
11/01/2019 11:13:44 - The state of TestService on 7D25PX1 has changed from Stopped to Running.
Hopefully that helps to at least point you in the right direction. Feel free to respond with more information and I'll be happy to update the post.

PowerShell Pro Tools multiple forms not running as expected

I am using PowerShell Pro Tools to create a GUI application that consists of all the common scripts I would run on a clients server:
main.ps1
main.ps1 loads a ServerConnection form on load:
The code behind this is pretty basic, it just gets the database name and server address for an SQL server:
$btnConfirm_Click = {
$ServerConnectForm.Close();
}
$btnTest_Click = {
## Set database connection variables [global]
$Global:databaseName = $cmbDatabaseName.Text;
$Global:serverAddress = $txtServerAddress.Text;
## Check db connection
$testResult = Invoke-SqlCmd -serverInstance $serverAddress -Database $databaseName -Query "SELECT TOP 1 SettingName FROM Settings";
## Write results to user
if ( $testResult -ne $null ) {
$lblTestResult.ForeColor = "#2acc18";
$lblTestResult.Text = "Test connection successfull";
<# If test connection success enable confirm button #>
$btnConfirm.Enabled = $true;
}
else {
$lblTestResult.ForeColor = "#d61111";
$lblTestResult.Text = "Test connection failed";
}
}
$txtServerAddress_Leave = {
## Get TRIS database list
$databaseList = Invoke-Sqlcmd -ServerInstance $txtServerAddress.Text -Query "
SELECT name FROM sys.databases WHERE CASE WHEN state_desc = 'ONLINE' THEN OBJECT_ID(QUOTENAME(name) + '.[dbo].[settings]', 'U') END IS NOT NULL
"
## Clear combo box
$cmbDatabaseName.Items.Clear();
## Add to combo box
foreach ($database in $databaseList) {
$cmbDatabaseName.Items.Add($database.ItemArray[0]);
}
}
. (Join-Path $PSScriptRoot 'main.designer.ps1')
$MainForm.ShowDialog()
The problem is that when I either compile this into an executable or run main.ps1 directly from the project folder, none of the code outside of main.ps1 works. The form will show up but I cannot find a way to get the code behind the form to work. For example in the ServerConnection form, adding a server address does not populate the database names and the test connection button does nothing.
Running from within Visual Studio works as intended.
Any help on this would be greatly appreciated.
EDIT :: Show the server connection form call in main.ps1
MainForm_Load
$MainForm_Load = {
## Launch server connection form
. (Join-Path $PSScriptRoot 'ServerConnect.designer.ps1');
$ServerConnectForm.ShowDialog();
## Call prereq analysis
PrereqAnalysis
}
It might be an issue with the scoping of your code.
If code outside the current scope of a session depends on said session, it will not work.
You could try setting the scope of variables and functions to global while you troubleshoot to see if it makes a difference, then change it back until you find where the scope goes wrong.
Microsoft have a good MSDoc page about Powershell scopes

Is there an easy way to check if CredSSP is enabled on a systems?

I am aware of the Get-WSManCredSSP function; however, this cmdlet does not work well in a script. This returns a long string similar to the following:
The machine is configured to allow delegating fresh credentials to the following target(s): wsman/*,wsman/*,wsman/*,wsman/*
This computer is configured to receive credentials from a remote client computer.
I cannot easily include this in a script that I am writing, so I'm looking for an alternative way to check CredSSP.
Can't you consider using this as documented in the CmdLet help: Gets the WS-Management CredSSP setting on the client (<localhost|computername>\Client\Auth\CredSSP).
On a local machine it gives :
(Get-Item WSMan:\localhost\Client\Auth\CredSSP).value
You can use it like this :
(Get-Item WSMan:\localhost\Client\Auth\CredSSP).value -eq $false
You can first test if WinRm is available :
(Get-Service -Name winrm ).Status
I was also struggling with the limitations of the Get-WSManCredSSP output, and found this helper script by Victor Vogelpoel/Ravikanth Chaganti to be really helpful.
Some examples:
Check if current machine has been configured as CredSSP server and/or client:
(Get-WSManCredSSPConfiguration).IsServer
(Get-WSManCredSSPConfiguration).IsClient
Check if a specified client machine has been set up for delegation:
Get-WSManCredSSPConfiguration | % { $_.ClientDelegateComputer.Contains('clientcomputername') }
(not intended as a replacement for the work of Vogelpoel & Chaganti, but as a quick summary of a quick reading of CredSSP.cs, so you can get a quick grasp of what it's doing - that said, it was tested on several systems I had at hand and seems to work)
function Get-WSManCredSSPState
{
$res = [pscustomobject]#{DelegateTo = #(); ReceiveFromRemote = $false}
$wsmTypes = [ordered]#{}
(gcm Get-WSManCredSSP).ImplementingType.Assembly.ExportedTypes `
| %{$wsmTypes[$_.Name] = $_}
$wmc = new-object $wsmTypes.WSManClass.FullName
$wms = $wsmTypes.IWSManEx.GetMethod('CreateSession').Invoke($wmc, #($null,0,$null))
$cli = $wsmTypes.IWSManSession.GetMethod('Get').Invoke($wms, #("winrm/config/client/auth", 0))
$res.ReceiveFromRemote = [bool]([xml]$cli).Auth.CredSSP
$afcPath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\CredentialsDelegation\AllowFreshCredentials'
if (test-path $afcPath)
{
$afc = gi $afcPath
$res.DelegateTo = $afc.GetValueNames() | sls '^\d+$' | %{$afc.GetValue($_)}
}
return $res
}

Get WAN IP Using VBScript

I have a Windows logon script running and am compiling a set of details that get logged when the user logons on. As this is a remote server, all logons are done via RDP. I need to get the IP address of the user who has logged on. I have used the following:
Function WAN_IP()
Set objxmlHTTP = CreateObject("Microsoft.XMLHTTP")
Call objxmlHTTP.open("get", "http://checkip.dyndns.org", False)
objxmlHTTP.Send()
strHTMLText = objxmlHTTP.ResponseText
Set objxmlHTTP = Nothing
If strHTMLText <> "" Then
varStart = InStr(1, strHTMLText, "Current IP Address:", vbTextCompare) + 19
If varStart Then varStop = InStr(varStart, strHTMLText, "</body>", vbTextCompare)
If varStart And varStop Then strIP = Mid(strHTMLText, varStart, varStop - varStart)
Else
strIP = "Unavailable"
End If
WAN_IP = Trim(strIP)
End Function
This, as expected, returns the external IP of the server itself and not the IP of the user who has connected.
Is anybody able to let me know how I get the IP of the user connected via RDP?
Following the response from #MarcB I used How to get the IP Address of the Remote Desktop Client? to get the idea on what to do.
I then found some example code here: http://pleasepressanykey.blogspot.com/2008/09/get-users-last-successful-and-failed.html

Resources