504 lines
15 KiB
Plaintext
504 lines
15 KiB
Plaintext
; ============================================================================
|
|
; Machine Authentication 3.0 Network Configuration
|
|
; Configures shop floor PCs for 802.1x/ISE Machine VLAN connectivity
|
|
; ============================================================================
|
|
;
|
|
; This installer configures:
|
|
; - Wired network: 802.1x using Corporate Holdings RADIUS servers
|
|
; - Wireless network: AESFMA SSID using Aerospace FreeRADIUS servers
|
|
;
|
|
; Silent Installation:
|
|
; MachineAuthSetup.exe /VERYSILENT /SUPPRESSMSGBOXES /LOG="C:\ma3.log"
|
|
;
|
|
; ============================================================================
|
|
|
|
[Setup]
|
|
AppId={{8A3B4C5D-6E7F-8901-2345-6789ABCDEF01}}
|
|
AppName=Machine Authentication 3.0
|
|
AppVersion=3.4
|
|
AppPublisher=GE Aerospace
|
|
DefaultDirName={tmp}\MachineAuth
|
|
CreateAppDir=no
|
|
PrivilegesRequired=admin
|
|
OutputDir=Output
|
|
OutputBaseFilename=MachineAuthSetup_v3.4
|
|
SolidCompression=yes
|
|
Compression=lzma2
|
|
WizardStyle=modern
|
|
SetupIconFile=gea-logo.ico
|
|
WizardImageFile=banner.bmp
|
|
WizardSmallImageFile=banner-sm.bmp
|
|
DisableWelcomePage=no
|
|
DisableDirPage=yes
|
|
DisableProgramGroupPage=yes
|
|
DisableReadyPage=no
|
|
DisableFinishedPage=no
|
|
Uninstallable=no
|
|
|
|
[Languages]
|
|
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
|
|
[Messages]
|
|
WelcomeLabel2=This will configure your PC for Machine Authentication 3.0 VLAN connectivity.%n%nThis configures 802.1x authentication for both wired and wireless network interfaces.%n%nYour network connection will be briefly interrupted during configuration.%n%nClick Next to continue.
|
|
|
|
[Files]
|
|
; Include the XML profile files - extract to temp
|
|
Source: "8021x.xml"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
|
|
Source: "AESFMA.xml"; DestDir: "{tmp}"; Flags: ignoreversion deleteafterinstall
|
|
|
|
[Code]
|
|
const
|
|
// Network interface names by Windows version
|
|
WIN7_WIRED = 'Local Area Connection';
|
|
WIN7_WIRELESS = 'Wireless Network Connection';
|
|
WIN10_WIRED = 'Ethernet';
|
|
WIN10_WIRELESS = 'Wi-Fi';
|
|
|
|
// Network types
|
|
NET_WIRED = 1;
|
|
NET_WIRELESS = 2;
|
|
NET_UNKNOWN = 0;
|
|
|
|
var
|
|
ProgressPage: TOutputProgressWizardPage;
|
|
ResultsMemo: TNewMemo;
|
|
LogMessages: String;
|
|
|
|
// ============================================================================
|
|
// LOGGING FUNCTIONS
|
|
// ============================================================================
|
|
|
|
procedure LogMsg(const Msg: String);
|
|
begin
|
|
LogMessages := LogMessages + Msg + #13#10;
|
|
Log(Msg);
|
|
end;
|
|
|
|
// ============================================================================
|
|
// UTILITY FUNCTIONS
|
|
// ============================================================================
|
|
|
|
function IsWindows10OrLater: Boolean;
|
|
var
|
|
Version: TWindowsVersion;
|
|
begin
|
|
GetWindowsVersionEx(Version);
|
|
Result := (Version.Major >= 10);
|
|
end;
|
|
|
|
function GetWiredInterfaceName: String;
|
|
begin
|
|
if IsWindows10OrLater then
|
|
Result := WIN10_WIRED
|
|
else
|
|
Result := WIN7_WIRED;
|
|
end;
|
|
|
|
function GetWirelessInterfaceName: String;
|
|
begin
|
|
if IsWindows10OrLater then
|
|
Result := WIN10_WIRELESS
|
|
else
|
|
Result := WIN7_WIRELESS;
|
|
end;
|
|
|
|
// Execute a command and return the exit code
|
|
function ExecCmd(const Executable, Params: String): Integer;
|
|
var
|
|
ResultCode: Integer;
|
|
begin
|
|
LogMsg('Executing: ' + Executable + ' ' + Params);
|
|
if Exec(Executable, Params, '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
|
|
Result := ResultCode
|
|
else
|
|
Result := -1;
|
|
LogMsg(' Result: ' + IntToStr(Result));
|
|
end;
|
|
|
|
// Execute a command via cmd.exe
|
|
function ExecShell(const Command: String): Integer;
|
|
begin
|
|
Result := ExecCmd('cmd.exe', '/c ' + Command);
|
|
end;
|
|
|
|
// Execute netsh command
|
|
function ExecNetsh(const Params: String): Integer;
|
|
begin
|
|
Result := ExecCmd('netsh.exe', Params);
|
|
end;
|
|
|
|
// Execute sc command for service control
|
|
function ExecSC(const Params: String): Integer;
|
|
begin
|
|
Result := ExecCmd('sc.exe', Params);
|
|
end;
|
|
|
|
// Execute net command
|
|
function ExecNet(const Params: String): Integer;
|
|
begin
|
|
Result := ExecCmd('net.exe', Params);
|
|
end;
|
|
|
|
// Check if a network interface exists and is connected
|
|
function IsInterfaceConnected(const InterfaceName: String; IsWireless: Boolean): Boolean;
|
|
var
|
|
TempFile: String;
|
|
OutputLines: TArrayOfString;
|
|
I: Integer;
|
|
Line: String;
|
|
ResultCode: Integer;
|
|
begin
|
|
Result := False;
|
|
TempFile := ExpandConstant('{tmp}\netcheck_') + IntToStr(Random(99999)) + '.txt';
|
|
|
|
if IsWireless then
|
|
Exec('cmd.exe', '/c netsh wlan show interfaces > "' + TempFile + '" 2>&1', '', SW_HIDE, ewWaitUntilTerminated, ResultCode)
|
|
else
|
|
Exec('cmd.exe', '/c netsh lan show interfaces > "' + TempFile + '" 2>&1', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
|
|
|
|
if FileExists(TempFile) then
|
|
begin
|
|
if LoadStringsFromFile(TempFile, OutputLines) then
|
|
begin
|
|
for I := 0 to GetArrayLength(OutputLines) - 1 do
|
|
begin
|
|
Line := OutputLines[I];
|
|
// Check for interface name and connected state
|
|
if (Pos(InterfaceName, Line) > 0) then
|
|
begin
|
|
Result := True;
|
|
Break;
|
|
end;
|
|
// Also check for "State" line showing "connected"
|
|
if (Pos('connected', LowerCase(Line)) > 0) and (Pos('disconnected', LowerCase(Line)) = 0) then
|
|
begin
|
|
Result := True;
|
|
end;
|
|
end;
|
|
end;
|
|
DeleteFile(TempFile);
|
|
end;
|
|
end;
|
|
|
|
// Detect which network type is currently active
|
|
function DetectActiveNetwork: Integer;
|
|
var
|
|
WiredInterface, WirelessInterface: String;
|
|
begin
|
|
Result := NET_UNKNOWN;
|
|
|
|
WiredInterface := GetWiredInterfaceName;
|
|
WirelessInterface := GetWirelessInterfaceName;
|
|
|
|
LogMsg('Detecting active network interface...');
|
|
LogMsg(' Wired interface name: ' + WiredInterface);
|
|
LogMsg(' Wireless interface name: ' + WirelessInterface);
|
|
|
|
// Check wired first (preferred)
|
|
if IsInterfaceConnected(WiredInterface, False) then
|
|
begin
|
|
LogMsg(' Active network: WIRED');
|
|
Result := NET_WIRED;
|
|
end
|
|
else if IsInterfaceConnected(WirelessInterface, True) then
|
|
begin
|
|
LogMsg(' Active network: WIRELESS');
|
|
Result := NET_WIRELESS;
|
|
end
|
|
else
|
|
begin
|
|
// Default to wired if can't detect
|
|
LogMsg(' Could not detect active network, defaulting to WIRED');
|
|
Result := NET_WIRED;
|
|
end;
|
|
end;
|
|
|
|
// ============================================================================
|
|
// SERVICE MANAGEMENT
|
|
// ============================================================================
|
|
|
|
procedure StopService(const ServiceName: String);
|
|
begin
|
|
LogMsg('Stopping service: ' + ServiceName);
|
|
ExecNet('stop "' + ServiceName + '"');
|
|
end;
|
|
|
|
procedure StartService(const ServiceName: String);
|
|
begin
|
|
LogMsg('Starting service: ' + ServiceName);
|
|
ExecNet('start "' + ServiceName + '"');
|
|
end;
|
|
|
|
procedure SetServiceAutoStart(const ServiceName: String);
|
|
begin
|
|
LogMsg('Setting service to auto-start: ' + ServiceName);
|
|
ExecSC('config ' + ServiceName + ' start= auto');
|
|
end;
|
|
|
|
// ============================================================================
|
|
// NETWORK CONFIGURATION
|
|
// ============================================================================
|
|
|
|
function ConfigureWiredNetwork: Boolean;
|
|
var
|
|
InterfaceName, ProfilePath: String;
|
|
begin
|
|
Result := True;
|
|
InterfaceName := GetWiredInterfaceName;
|
|
ProfilePath := ExpandConstant('{tmp}\8021x.xml');
|
|
|
|
LogMsg('');
|
|
LogMsg('=== Configuring Wired Network ===');
|
|
LogMsg('Interface: ' + InterfaceName);
|
|
LogMsg('Profile: ' + ProfilePath);
|
|
|
|
// Enable and start Wired AutoConfig service
|
|
SetServiceAutoStart('dot3svc');
|
|
StartService('Wired AutoConfig');
|
|
|
|
// Small delay for service to start
|
|
Sleep(1000);
|
|
|
|
// Import 802.1x profile to wired interface
|
|
LogMsg('Importing 802.1x profile...');
|
|
if ExecNetsh('lan add profile filename="' + ProfilePath + '" interface="' + InterfaceName + '"') <> 0 then
|
|
begin
|
|
// Try without interface specification as fallback
|
|
LogMsg('Retrying without interface specification...');
|
|
ExecNetsh('lan add profile filename="' + ProfilePath + '"');
|
|
end;
|
|
|
|
LogMsg('Wired network configuration complete.');
|
|
end;
|
|
|
|
function ConfigureWirelessNetwork: Boolean;
|
|
var
|
|
InterfaceName, ProfilePath: String;
|
|
begin
|
|
Result := True;
|
|
InterfaceName := GetWirelessInterfaceName;
|
|
ProfilePath := ExpandConstant('{tmp}\AESFMA.xml');
|
|
|
|
LogMsg('');
|
|
LogMsg('=== Configuring Wireless Network ===');
|
|
LogMsg('Interface: ' + InterfaceName);
|
|
LogMsg('Profile: ' + ProfilePath);
|
|
|
|
// Enable and start WLAN AutoConfig service
|
|
SetServiceAutoStart('Wlansvc');
|
|
StartService('WLAN AutoConfig');
|
|
|
|
// Small delay for service to start
|
|
Sleep(1000);
|
|
|
|
// Import AESFMA profile to wireless interface
|
|
LogMsg('Importing AESFMA profile...');
|
|
if ExecNetsh('wlan add profile filename="' + ProfilePath + '" interface="' + InterfaceName + '"') <> 0 then
|
|
begin
|
|
// Try without interface specification as fallback
|
|
LogMsg('Retrying without interface specification...');
|
|
ExecNetsh('wlan add profile filename="' + ProfilePath + '"');
|
|
end;
|
|
|
|
LogMsg('Wireless network configuration complete.');
|
|
end;
|
|
|
|
procedure ReconnectNetwork(NetworkType: Integer);
|
|
var
|
|
WiredInterface, WirelessInterface: String;
|
|
begin
|
|
WiredInterface := GetWiredInterfaceName;
|
|
WirelessInterface := GetWirelessInterfaceName;
|
|
|
|
LogMsg('');
|
|
LogMsg('=== Reconnecting Network ===');
|
|
|
|
if NetworkType = NET_WIRED then
|
|
begin
|
|
LogMsg('Reconnecting wired interface...');
|
|
ExecNetsh('lan reconnect interface="' + WiredInterface + '"');
|
|
end
|
|
else if NetworkType = NET_WIRELESS then
|
|
begin
|
|
LogMsg('Connecting to AESFMA wireless network...');
|
|
ExecNetsh('wlan connect name=AESFMA ssid=AESFMA interface="' + WirelessInterface + '"');
|
|
end;
|
|
end;
|
|
|
|
// ============================================================================
|
|
// MAIN CONFIGURATION PROCEDURE
|
|
// ============================================================================
|
|
|
|
function PerformConfiguration: Boolean;
|
|
var
|
|
ActiveNetwork: Integer;
|
|
WindowsVersion: String;
|
|
begin
|
|
Result := True;
|
|
LogMessages := '';
|
|
|
|
// Log Windows version
|
|
if IsWindows10OrLater then
|
|
WindowsVersion := 'Windows 10/11'
|
|
else
|
|
WindowsVersion := 'Windows 7/8';
|
|
|
|
LogMsg('Machine Authentication 3.0 Configuration');
|
|
LogMsg('========================================');
|
|
LogMsg('Windows Version: ' + WindowsVersion);
|
|
LogMsg('');
|
|
|
|
// Stop NetworkAdapterManager if it exists (may not exist on all machines)
|
|
LogMsg('Stopping NetworkAdapterManager (if present)...');
|
|
StopService('NetworkAdapterManager');
|
|
|
|
// Detect active network
|
|
ActiveNetwork := DetectActiveNetwork;
|
|
|
|
// Configure wired network
|
|
ProgressPage.SetText('Configuring wired network...', '');
|
|
ProgressPage.SetProgress(1, 5);
|
|
ConfigureWiredNetwork;
|
|
|
|
// Configure wireless network
|
|
ProgressPage.SetText('Configuring wireless network...', '');
|
|
ProgressPage.SetProgress(2, 5);
|
|
ConfigureWirelessNetwork;
|
|
|
|
// Reconnect active network
|
|
ProgressPage.SetText('Reconnecting network...', '');
|
|
ProgressPage.SetProgress(3, 5);
|
|
ReconnectNetwork(ActiveNetwork);
|
|
|
|
// Start NetworkAdapterManager if it was stopped
|
|
LogMsg('');
|
|
LogMsg('Starting NetworkAdapterManager (if present)...');
|
|
StartService('NetworkAdapterManager');
|
|
|
|
// Wait for network to stabilize
|
|
ProgressPage.SetText('Waiting for network to stabilize...', '');
|
|
ProgressPage.SetProgress(4, 5);
|
|
LogMsg('');
|
|
LogMsg('Waiting 10 seconds for network to stabilize...');
|
|
Sleep(10000);
|
|
|
|
ProgressPage.SetProgress(5, 5);
|
|
|
|
LogMsg('');
|
|
LogMsg('========================================');
|
|
LogMsg('Configuration complete!');
|
|
LogMsg('');
|
|
LogMsg('The machine should now have access to the Machine VLAN.');
|
|
LogMsg('Test vault access to confirm connectivity.');
|
|
end;
|
|
|
|
// ============================================================================
|
|
// WIZARD EVENTS
|
|
// ============================================================================
|
|
|
|
procedure InitializeWizard;
|
|
begin
|
|
// Create progress page
|
|
ProgressPage := CreateOutputProgressPage('Configuring Network',
|
|
'Please wait while Machine Authentication 3.0 is configured...');
|
|
end;
|
|
|
|
function InitializeSetup: Boolean;
|
|
begin
|
|
Result := True;
|
|
|
|
// Verify admin privileges
|
|
if not IsAdmin then
|
|
begin
|
|
MsgBox('This installer requires administrator privileges.' + #13#10 +
|
|
'Please right-click and select "Run as administrator".',
|
|
mbError, MB_OK);
|
|
Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure CurStepChanged(CurStep: TSetupStep);
|
|
var
|
|
ResultForm: TSetupForm;
|
|
Memo: TNewMemo;
|
|
OKButton: TNewButton;
|
|
begin
|
|
if CurStep = ssPostInstall then
|
|
begin
|
|
// Show progress page and perform configuration
|
|
ProgressPage.Show;
|
|
try
|
|
PerformConfiguration;
|
|
finally
|
|
ProgressPage.Hide;
|
|
end;
|
|
|
|
// Show results in non-silent mode
|
|
if not WizardSilent then
|
|
begin
|
|
ResultForm := CreateCustomForm;
|
|
ResultForm.Caption := 'Configuration Results';
|
|
ResultForm.ClientWidth := 600;
|
|
ResultForm.ClientHeight := 450;
|
|
ResultForm.Position := poScreenCenter;
|
|
|
|
Memo := TNewMemo.Create(ResultForm);
|
|
Memo.Parent := ResultForm;
|
|
Memo.Left := 10;
|
|
Memo.Top := 10;
|
|
Memo.Width := ResultForm.ClientWidth - 20;
|
|
Memo.Height := ResultForm.ClientHeight - 60;
|
|
Memo.ScrollBars := ssVertical;
|
|
Memo.ReadOnly := True;
|
|
Memo.Text := LogMessages;
|
|
Memo.Font.Name := 'Consolas';
|
|
Memo.Font.Size := 9;
|
|
|
|
OKButton := TNewButton.Create(ResultForm);
|
|
OKButton.Parent := ResultForm;
|
|
OKButton.Caption := 'OK';
|
|
OKButton.Width := 80;
|
|
OKButton.Height := 30;
|
|
OKButton.Left := (ResultForm.ClientWidth - OKButton.Width) div 2;
|
|
OKButton.Top := ResultForm.ClientHeight - 45;
|
|
OKButton.ModalResult := mrOK;
|
|
OKButton.Default := True;
|
|
|
|
ResultForm.ActiveControl := OKButton;
|
|
ResultForm.ShowModal;
|
|
ResultForm.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo,
|
|
MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
|
|
var
|
|
WinVer, WiredInt, WirelessInt: String;
|
|
begin
|
|
if IsWindows10OrLater then
|
|
WinVer := 'Windows 10/11'
|
|
else
|
|
WinVer := 'Windows 7/8';
|
|
|
|
WiredInt := GetWiredInterfaceName;
|
|
WirelessInt := GetWirelessInterfaceName;
|
|
|
|
Result := 'Machine Authentication 3.0 Configuration' + NewLine +
|
|
NewLine +
|
|
'The following will be configured:' + NewLine +
|
|
NewLine +
|
|
Space + 'Windows Version: ' + WinVer + NewLine +
|
|
Space + 'Wired Interface: ' + WiredInt + NewLine +
|
|
Space + 'Wireless Interface: ' + WirelessInt + NewLine +
|
|
NewLine +
|
|
'Actions:' + NewLine +
|
|
Space + '1. Enable Wired AutoConfig service (dot3svc)' + NewLine +
|
|
Space + '2. Import 802.1x profile for wired authentication' + NewLine +
|
|
Space + '3. Enable WLAN AutoConfig service (Wlansvc)' + NewLine +
|
|
Space + '4. Import AESFMA profile for wireless authentication' + NewLine +
|
|
Space + '5. Reconnect active network interface' + NewLine +
|
|
NewLine +
|
|
'Note: Network will be briefly interrupted during configuration.';
|
|
end;
|