Compare commits
18 Commits
renumber-1
...
feat/shopf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b240cfea12 | ||
|
|
e7be0f5391 | ||
|
|
0c4c2a245d | ||
|
|
fdf63ab32f | ||
|
|
64e1f7e088 | ||
|
|
287ec86c12 | ||
|
|
85e7d91b1a | ||
|
|
2461804fc8 | ||
|
|
48bc609eb5 | ||
|
|
132c57ab39 | ||
|
|
99deaa6882 | ||
|
|
948d013539 | ||
|
|
6e218f3daf | ||
|
|
b5b644a360 | ||
|
|
bc89ba1cf3 | ||
|
|
1487abdba5 | ||
|
|
7af66575d0 | ||
|
|
8e11f0824a |
@@ -156,36 +156,41 @@
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>4</Order>
|
||||
<CommandLine>powershell.exe -ep Bypass -Command "net use Z: \\172.16.9.1\enrollment /user:pxe-upload pxe; robocopy Z:\shopfloor-setup C:\Enrollment Fetch-StagingPayload.ps1 Verify-And-Heal-Staging.ps1 /R:2 /W:2; robocopy Z:\scripts C:\Enrollment run-enrollment.ps1 wait-for-internet.ps1 migrate-to-wifi.ps1 /R:2 /W:2"</CommandLine>
|
||||
<Description>Bootstrap self-heal: pull Fetch/Verify-Heal + enrollment scripts from the PXE share so Order 5/6 run after an early WinPE staging failure.</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>5</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\Fetch-StagingPayload.ps1"</CommandLine>
|
||||
<Description>Fetch bulk staging (shopfloor-setup tree + preinstall bundle) from the PXE share on a fresh mount, BEFORE the production-network switch takes the bay off the imaging LAN. Detailed log at C:\Logs\Fetch\.</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>5</Order>
|
||||
<Order>6</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\Verify-And-Heal-Staging.ps1"</CommandLine>
|
||||
<Description>Verify every imaging payload arrived and re-pull anything missing from the PXE share (incl the CMM bundle + selected-bay backup) while still on the imaging LAN, BEFORE wait-for-internet switches the bay to the production network. Log at C:\Logs\Fetch\.</Description>
|
||||
<Description>Verify + re-pull any missing imaging payload from the PXE share (CMM/Keyence/WaxTrace bundles + bay backup) on the imaging LAN before the production-network switch. Log C:\Logs\Fetch.</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>6</Order>
|
||||
<Order>7</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\wait-for-internet.ps1"</CommandLine>
|
||||
<Description>Prompt to connect production network then wait for TCP 443 connectivity</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<Order>8</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\migrate-to-wifi.ps1"</CommandLine>
|
||||
<Description>Migrate from wired to WiFi if WiFi adapter present, else stay on wired</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>8</Order>
|
||||
<Order>9</Order>
|
||||
<CommandLine>msiexec.exe /i "C:\PreInstall\installers\powershell7\PowerShell-7.5.4-win-x64.msi" /qn /norestart ADD_PATH=1 USE_MU=0 ENABLE_MU=0 DISABLE_TELEMETRY=1</CommandLine>
|
||||
<Description>Install PowerShell 7 BEFORE PPKG so Intune SetupCredentials Win32App finds pwsh.exe (race fix)</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>9</Order>
|
||||
<Order>10</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\run-enrollment.ps1"</CommandLine>
|
||||
<Description>Run GCCH Enrollment</Description>
|
||||
</SynchronousCommand>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>10</Order>
|
||||
<Order>11</Order>
|
||||
<CommandLine>powershell.exe -ExecutionPolicy Bypass -File "C:\Enrollment\Run-ShopfloorSetup.ps1"</CommandLine>
|
||||
<Description>Run shopfloor PC type setup</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
@@ -1,307 +1,363 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend"
|
||||
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<!-- 1. windowsPE is intentionally empty -->
|
||||
<settings pass="windowsPE" />
|
||||
|
||||
<!-- 2. Offline servicing (drivers) -->
|
||||
<settings pass="offlineServicing">
|
||||
<component name="Microsoft-Windows-PnpCustomizationsNonWinPE"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<DriverPaths>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
|
||||
<Path>W:\Drivers</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="2">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\BROTHER\UNIV-PS-01181\PS\64</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="3">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\HP</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="4">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\XEROX\UNIV_5.1035.2.0_PS_x64_Driver</Path>
|
||||
</PathAndCredentials>
|
||||
</DriverPaths>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- 3. specialize: computer naming + RunSynchronous all in ONE component -->
|
||||
<settings pass="specialize">
|
||||
<!-- 3a. Shell-Setup for naming/owner/org -->
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<ComputerName>H%serialnumber%</ComputerName>
|
||||
<RegisteredOrganization>GE Aerospace</RegisteredOrganization>
|
||||
<RegisteredOwner>GE</RegisteredOwner>
|
||||
<TimeZone>Eastern Standard Time</TimeZone>
|
||||
</component>
|
||||
|
||||
<!-- 3b. RunSynchronous for all of your installers, copies, etc. -->
|
||||
<component name="Microsoft-Windows-Deployment"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<RunSynchronous>
|
||||
<!-- EAP-PEAP MSI -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Path>msiexec /i "C:\Deploy\Applications\extra\wireless\EAP-PEAP.msi" /quiet /norestart</Path>
|
||||
<Description>Install EAP-PEAP</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Wi-Fi profiles -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Path>cmd /c netsh wlan add profile filename="C:\Deploy\Applications\extra\wireless\BLUESSO.xml" user=all</Path>
|
||||
<Description>Add BLUESSO WiFi profile</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<Path>cmd /c netsh wlan add profile filename="C:\Deploy\Applications\extra\wireless\WiFi-Profile.xml" user=all</Path>
|
||||
<Description>Add generic WiFi profile</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Certificates -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>4</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_External_Root_CA_2_1.cer"</Path>
|
||||
<Description>Install External Root Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>5</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_External_Intermediate_CA_2_1.cer"</Path>
|
||||
<Description>Install External Intermediate Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>6</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_Enterprise_Root_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Root Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Device_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Device Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>8</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Server_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Server Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>9</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Smart_Card_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install SmartCard Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>10</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_User_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install User Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>11</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_Aerospace_Enterprise_Root_CA_1.cer"</Path>
|
||||
<Description>Install Aerospace Enterprise Root CA</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>12</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\ZscalerCommercialCertificate-2048-SHA256.crt"</Path>
|
||||
<Description>Install Zscaler Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Fonts -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>13</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\3OF9.TTF" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy 3OF9 Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>14</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "3 of 9 Barcode" /t REG_SZ /d "3OF9.TTF" /f</Path>
|
||||
<Description>Register 3OF9 Barcode Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>15</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\Code39AzaleaNarrow3.ttf" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy Code39 Azalea Narrow Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>16</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "Code39AzaleaNarrow3" /t REG_SZ /d "Code39AzaleaNarrow3.ttf" /f</Path>
|
||||
<Description>Register Code39 Azalea Narrow Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>17</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\Code39Azalea.ttf" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy Code39 Azalea Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>18</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "Code39Azalea" /t REG_SZ /d "Code39Azalea.ttf" /f</Path>
|
||||
<Description>Register Code39 Azalea Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- OpenText installers -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>19</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\opentext_hostexplorer_sp1_15.0_v01.exe /quiet /norestart</Path>
|
||||
<Description>Install OpenText HostExplorer SP1</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>20</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\J2SE_Runtime_Environment_1.6.0_22_Static_Config_V2_Co-Exist.EXE /silent /norestart</Path>
|
||||
<Description>Install J2SE Runtime Environment 1.6.0_22</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>21</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\unattended.bat</Path>
|
||||
<Description>Install J2SE Runtime Environment 1.6.0_22</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Adobe -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>22</Order>
|
||||
<Path>msiexec /i "C:\Deploy\Applications\extra\adobe\AcroRead.msi" TRANSFORMS="C:\Deploy\Applications\extra\adobe\AcroRead.mst" /quiet /norestart</Path>
|
||||
<Description>Install Adobe</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>23</Order>
|
||||
<Path>msiexec /p "C:\Deploy\Applications\extra\adobe\AcroRdrDCUpd2500120531.msp" /quiet /norestart</Path>
|
||||
<Description>Apply Adobe Reader Update</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Java JRE 8 Enterprise Installation -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>26</Order>
|
||||
<Path>C:\Deploy\Applications\extra\java\jre-8u441-windows-i586.exe /s INSTALLDIR="C:\Program Files (x86)\Java\jre1.8.0_441" STATIC=1 AUTO_UPDATE=0 REBOOT=0 SPONSORS=0 WEB_JAVA=0 /L "C:\Windows\Logs\java-install.log"</Path>
|
||||
<Description>Install Java JRE 8 Update 441 with Enterprise Settings and Logging</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Updates via Registry (64-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>27</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\JavaSoft\Java Update\Policy" /v EnableJavaUpdate /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Updates (64-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Updates via Registry (32-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>28</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Wow6432Node\JavaSoft\Java Update\Policy" /v EnableJavaUpdate /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Updates (32-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Update Check (64-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>29</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\JavaSoft\Java Update\Policy" /v EnableAutoUpdateCheck /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Update Check (64-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Update Check (32-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>30</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Wow6432Node\JavaSoft\Java Update\Policy" /v EnableAutoUpdateCheck /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Update Check (32-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Cortana -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>31</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v AllowCortana /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Cortana</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Web Search in Start Menu -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>33</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v DisableWebSearch /t REG_DWORD /d 1 /f</Path>
|
||||
<Description>Disable Web Search in Start Menu</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Bing / web search suggestions in Start menu.
|
||||
BingSearchEnabled is documented at HKCU\Software\Microsoft\Windows\CurrentVersion\Search
|
||||
(not HKLM), so the old HKLM policy placement was a no-op. The current documented
|
||||
suppression is DisableSearchBoxSuggestions=1 at Software\Policies\Microsoft\Windows\Explorer.
|
||||
Writing it into the Default User hive so every newly-created account inherits it. -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>34</Order>
|
||||
<Path>cmd /c reg load HKU\TempDU C:\Users\Default\NTUSER.DAT & reg add "HKU\TempDU\Software\Policies\Microsoft\Windows\Explorer" /v DisableSearchBoxSuggestions /t REG_DWORD /d 1 /f & reg unload HKU\TempDU</Path>
|
||||
<Description>Disable Bing/web search suggestions (Default User hive)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Search Web when searching Windows -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>35</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v ConnectedSearchUseWeb /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Connected Search Use Web</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Cortana Speech Recognition -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>36</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\InputPersonalization" /v AllowInputPersonalization /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Cortana Speech Recognition</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Search Highlights (news/trending) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>38</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v EnableDynamicContentInWSB /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Search Highlights</Description>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- 4. oobeSystem: hide OEM/EULA screens -->
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
|
||||
<HideOnlineAccountScreens>false</HideOnlineAccountScreens>
|
||||
<HideWirelessSetupInOOBE>false</HideWirelessSetupInOOBE>
|
||||
<HideLocalAccountScreen>true</HideLocalAccountScreen>
|
||||
<NetworkLocation>Work</NetworkLocation>
|
||||
<ProtectYourPC>3</ProtectYourPC>
|
||||
<SkipUserOOBE>false</SkipUserOOBE>
|
||||
<SkipMachineOOBE>false</SkipMachineOOBE>
|
||||
</OOBE>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<CommandLine>shutdown -a</CommandLine>
|
||||
<Description>Cancel any scheduled shutdown from Office installation</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
<!-- Install Zscaler -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<CommandLine>C:\Deploy\Applications\extra\zscaler\zscaler.bat</CommandLine>
|
||||
<Description>Install Zscaler Client Connector</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
<!-- Install Microsoft Office -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<CommandLine>cmd /c "cd /d C:\Deploy\Applications\extra\office\ && install.bat"</CommandLine>
|
||||
<Description>Install Microsoft Office</Description>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
</unattend>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<unattend xmlns="urn:schemas-microsoft-com:unattend"
|
||||
xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
|
||||
<!-- 1. windowsPE is intentionally empty -->
|
||||
<settings pass="windowsPE" />
|
||||
|
||||
<!-- 2. Offline servicing (drivers) -->
|
||||
<settings pass="offlineServicing">
|
||||
<component name="Microsoft-Windows-PnpCustomizationsNonWinPE"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<DriverPaths>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="1">
|
||||
<Path>W:\Drivers</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="2">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\BROTHER\UNIV-PS-01181\PS\64</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="3">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\HP</Path>
|
||||
</PathAndCredentials>
|
||||
<PathAndCredentials wcm:action="add" wcm:keyValue="4">
|
||||
<Path>W:\Deploy\Applications\extra\printdrivers\XEROX\UNIV_5.1035.2.0_PS_x64_Driver</Path>
|
||||
</PathAndCredentials>
|
||||
</DriverPaths>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- 3. specialize: computer naming + RunSynchronous all in ONE component -->
|
||||
<settings pass="specialize">
|
||||
<!-- 3a. Shell-Setup for naming/owner/org -->
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<ComputerName>H%serialnumber%</ComputerName>
|
||||
<RegisteredOrganization>GE Aerospace</RegisteredOrganization>
|
||||
<RegisteredOwner>GE</RegisteredOwner>
|
||||
<TimeZone>Eastern Standard Time</TimeZone>
|
||||
</component>
|
||||
|
||||
<!-- 3b. RunSynchronous for all of your installers, copies, etc. -->
|
||||
<component name="Microsoft-Windows-Deployment"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<RunSynchronous>
|
||||
<!-- EAP-PEAP MSI -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<Path>msiexec /i "C:\Deploy\Applications\extra\wireless\EAP-PEAP.msi" /quiet /norestart</Path>
|
||||
<Description>Install EAP-PEAP</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Wi-Fi profiles -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<Path>cmd /c netsh wlan add profile filename="C:\Deploy\Applications\extra\wireless\BLUESSO.xml" user=all</Path>
|
||||
<Description>Add BLUESSO WiFi profile</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<Path>cmd /c netsh wlan add profile filename="C:\Deploy\Applications\extra\wireless\WiFi-Profile.xml" user=all</Path>
|
||||
<Description>Add generic WiFi profile</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Certificates -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>4</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_External_Root_CA_2_1.cer"</Path>
|
||||
<Description>Install External Root Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>5</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_External_Intermediate_CA_2_1.cer"</Path>
|
||||
<Description>Install External Intermediate Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>6</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_Enterprise_Root_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Root Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>7</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Device_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Device Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>8</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Server_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install Enterprise Server Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>9</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_Smart_Card_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install SmartCard Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>10</Order>
|
||||
<Path>cmd /c certutil -addstore CA "C:\Deploy\Applications\GE_Enterprise_User_Issuing_CA_2_1.cer"</Path>
|
||||
<Description>Install User Issuing Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>11</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\GE_Aerospace_Enterprise_Root_CA_1.cer"</Path>
|
||||
<Description>Install Aerospace Enterprise Root CA</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>12</Order>
|
||||
<Path>cmd /c certutil -addstore Root "C:\Deploy\Applications\ZscalerCommercialCertificate-2048-SHA256.crt"</Path>
|
||||
<Description>Install Zscaler Certificate</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Fonts -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>13</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\3OF9.TTF" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy 3OF9 Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>14</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "3 of 9 Barcode" /t REG_SZ /d "3OF9.TTF" /f</Path>
|
||||
<Description>Register 3OF9 Barcode Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>15</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\Code39AzaleaNarrow3.ttf" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy Code39 Azalea Narrow Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>16</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "Code39AzaleaNarrow3" /t REG_SZ /d "Code39AzaleaNarrow3.ttf" /f</Path>
|
||||
<Description>Register Code39 Azalea Narrow Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>17</Order>
|
||||
<Path>cmd /c copy "C:\Deploy\Applications\extra\fonts\Code39Azalea.ttf" "%WINDIR%\Fonts\" /Y</Path>
|
||||
<Description>Copy Code39 Azalea Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>18</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts" /v "Code39Azalea" /t REG_SZ /d "Code39Azalea.ttf" /f</Path>
|
||||
<Description>Register Code39 Azalea Font</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- OpenText installers -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>19</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\opentext_hostexplorer_sp1_15.0_v01.exe /quiet /norestart</Path>
|
||||
<Description>Install OpenText HostExplorer SP1</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>20</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\J2SE_Runtime_Environment_1.6.0_22_Static_Config_V2_Co-Exist.EXE /silent /norestart</Path>
|
||||
<Description>Install J2SE Runtime Environment 1.6.0_22</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>21</Order>
|
||||
<Path>C:\Deploy\Applications\extra\opentext\unattended.bat</Path>
|
||||
<Description>Install J2SE Runtime Environment 1.6.0_22</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Adobe -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>22</Order>
|
||||
<Path>msiexec /i "C:\Deploy\Applications\extra\adobe\AcroRead.msi" TRANSFORMS="C:\Deploy\Applications\extra\adobe\AcroRead.mst" /quiet /norestart</Path>
|
||||
<Description>Install Adobe</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>23</Order>
|
||||
<Path>msiexec /p "C:\Deploy\Applications\extra\adobe\AcroRdrDCUpd2500120531.msp" /quiet /norestart</Path>
|
||||
<Description>Apply Adobe Reader Update</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Java JRE 8 Enterprise Installation -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>26</Order>
|
||||
<Path>C:\Deploy\Applications\extra\java\jre-8u441-windows-i586.exe /s INSTALLDIR="C:\Program Files (x86)\Java\jre1.8.0_441" STATIC=1 AUTO_UPDATE=0 REBOOT=0 SPONSORS=0 WEB_JAVA=0 /L "C:\Windows\Logs\java-install.log"</Path>
|
||||
<Description>Install Java JRE 8 Update 441 with Enterprise Settings and Logging</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Updates via Registry (64-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>27</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\JavaSoft\Java Update\Policy" /v EnableJavaUpdate /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Updates (64-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Updates via Registry (32-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>28</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Wow6432Node\JavaSoft\Java Update\Policy" /v EnableJavaUpdate /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Updates (32-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Update Check (64-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>29</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\JavaSoft\Java Update\Policy" /v EnableAutoUpdateCheck /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Update Check (64-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Java Auto Update Check (32-bit) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>30</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Wow6432Node\JavaSoft\Java Update\Policy" /v EnableAutoUpdateCheck /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Java Auto Update Check (32-bit)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Cortana -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>31</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v AllowCortana /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Cortana</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Web Search in Start Menu -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>33</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v DisableWebSearch /t REG_DWORD /d 1 /f</Path>
|
||||
<Description>Disable Web Search in Start Menu</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Bing / web search suggestions in Start menu.
|
||||
BingSearchEnabled is documented at HKCU\Software\Microsoft\Windows\CurrentVersion\Search
|
||||
(not HKLM), so the old HKLM policy placement was a no-op. The current documented
|
||||
suppression is DisableSearchBoxSuggestions=1 at Software\Policies\Microsoft\Windows\Explorer.
|
||||
Writing it into the Default User hive so every newly-created account inherits it. -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>34</Order>
|
||||
<Path>cmd /c reg load HKU\TempDU C:\Users\Default\NTUSER.DAT & reg add "HKU\TempDU\Software\Policies\Microsoft\Windows\Explorer" /v DisableSearchBoxSuggestions /t REG_DWORD /d 1 /f & reg unload HKU\TempDU</Path>
|
||||
<Description>Disable Bing/web search suggestions (Default User hive)</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Search Web when searching Windows -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>35</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v ConnectedSearchUseWeb /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Connected Search Use Web</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Cortana Speech Recognition -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>36</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\InputPersonalization" /v AllowInputPersonalization /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Cortana Speech Recognition</Description>
|
||||
</RunSynchronousCommand>
|
||||
|
||||
<!-- Disable Search Highlights (news/trending) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>38</Order>
|
||||
<Path>cmd /c reg add "HKLM\SOFTWARE\Policies\Microsoft\Windows\Windows Search" /v EnableDynamicContentInWSB /t REG_DWORD /d 0 /f</Path>
|
||||
<Description>Disable Search Highlights</Description>
|
||||
</RunSynchronousCommand>
|
||||
<!-- Engineering prereqs: .NET 3.5 + VC++ redistributables (staged in extra_engineering\prereqs; if-exist guarded so non-engineering images skip) -->
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>39</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\sxs\microsoft-windows-netfx3-ondemand-package~31bf3856ad364e35~amd64~~.cab" dism /online /enable-feature /featurename:NetFx3 /all /source:"C:\Deploy\Applications\extra_engineering\prereqs\sxs" /limitaccess</Path>
|
||||
<Description>Enable .NET Framework 3.5 from staged sxs</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>40</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v10.0.40219.325_x64\InstallMSVC2010Redist10.0.40219.325_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v10.0.40219.325_x64\InstallMSVC2010Redist10.0.40219.325_x64.exe"</Path>
|
||||
<Description>VC++ 2010 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>41</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v10.0.40219.325\InstallMSVC2010Redist10.0.40219.325.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v10.0.40219.325\InstallMSVC2010Redist10.0.40219.325.exe"</Path>
|
||||
<Description>VC++ 2010 x86</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>42</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v11.0.60610.1_x64\InstallMSVC2012Redist11.0.60610.1_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v11.0.60610.1_x64\InstallMSVC2012Redist11.0.60610.1_x64.exe"</Path>
|
||||
<Description>VC++ 2012 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>43</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v11.0.60610.1\InstallMSVC2012Redist11.0.60610.1.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v11.0.60610.1\InstallMSVC2012Redist11.0.60610.1.exe"</Path>
|
||||
<Description>VC++ 2012 x86</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>44</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v9.0.30729.5026_x64\InstallMSVC2008Redist.5026_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v9.0.30729.5026_x64\InstallMSVC2008Redist.5026_x64.exe"</Path>
|
||||
<Description>VC++ 2008 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>45</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v9.0.30729.5026\InstallMSVC2008Redist.5026.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v9.0.30729.5026\InstallMSVC2008Redist.5026.exe"</Path>
|
||||
<Description>VC++ 2008 x86</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>46</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v8.0.50727.6195_x64\InstallMSVC2005Redist.6195_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v8.0.50727.6195_x64\InstallMSVC2005Redist.6195_x64.exe"</Path>
|
||||
<Description>VC++ 2005 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>47</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v8.0.50727.6195\InstallMSVC2005Redist.6195.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v8.0.50727.6195\InstallMSVC2005Redist.6195.exe"</Path>
|
||||
<Description>VC++ 2005 x86</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>48</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v12.0.30501.0_x64\InstallMSVC2013Redist12.0.30501.0_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v12.0.30501.0_x64\InstallMSVC2013Redist12.0.30501.0_x64.exe"</Path>
|
||||
<Description>VC++ 2013 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
<RunSynchronousCommand wcm:action="add">
|
||||
<Order>49</Order>
|
||||
<Path>cmd /c if exist "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v14.40.33816_x64\InstallMSVC20152022Redist14.40.33816_x64.exe" "C:\Deploy\Applications\extra_engineering\prereqs\redistrib\v14.40.33816_x64\InstallMSVC20152022Redist14.40.33816_x64.exe"</Path>
|
||||
<Description>VC++ 2015-2022 x64</Description>
|
||||
</RunSynchronousCommand>
|
||||
</RunSynchronous>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
<!-- 4. oobeSystem: hide OEM/EULA screens -->
|
||||
<settings pass="oobeSystem">
|
||||
<component name="Microsoft-Windows-Shell-Setup"
|
||||
processorArchitecture="amd64"
|
||||
publicKeyToken="31bf3856ad364e35"
|
||||
language="neutral"
|
||||
versionScope="nonSxS">
|
||||
<OOBE>
|
||||
<HideEULAPage>true</HideEULAPage>
|
||||
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
|
||||
<HideOnlineAccountScreens>false</HideOnlineAccountScreens>
|
||||
<HideWirelessSetupInOOBE>false</HideWirelessSetupInOOBE>
|
||||
<HideLocalAccountScreen>true</HideLocalAccountScreen>
|
||||
<NetworkLocation>Work</NetworkLocation>
|
||||
<ProtectYourPC>3</ProtectYourPC>
|
||||
<SkipUserOOBE>false</SkipUserOOBE>
|
||||
<SkipMachineOOBE>false</SkipMachineOOBE>
|
||||
</OOBE>
|
||||
<FirstLogonCommands>
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>1</Order>
|
||||
<CommandLine>shutdown -a</CommandLine>
|
||||
<Description>Cancel any scheduled shutdown from Office installation</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
<!-- Install Zscaler -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>2</Order>
|
||||
<CommandLine>C:\Deploy\Applications\extra\zscaler\zscaler.bat</CommandLine>
|
||||
<Description>Install Zscaler Client Connector</Description>
|
||||
</SynchronousCommand>
|
||||
|
||||
<!-- Install Microsoft Office -->
|
||||
<SynchronousCommand wcm:action="add">
|
||||
<Order>3</Order>
|
||||
<CommandLine>cmd /c "cd /d C:\Deploy\Applications\extra\office\ && install.bat"</CommandLine>
|
||||
<Description>Install Microsoft Office</Description>
|
||||
</SynchronousCommand>
|
||||
</FirstLogonCommands>
|
||||
</component>
|
||||
</settings>
|
||||
|
||||
</unattend>
|
||||
|
||||
@@ -147,6 +147,16 @@
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{C18FB403-1E88-43C8-AD8A-CED50F23DE8B}",
|
||||
"PCTypes": ["*"]
|
||||
},
|
||||
{
|
||||
"_comment": "VC++ 2015-2022 x64 - required by PC-DMIS 2026 (PCDLRN.exe links vcruntime140_1.dll, added in VC++ 2019 / v14.20). The x64 redist line above previously stopped at 2013, so 64-bit PC-DMIS 2026 was missing its runtime and PCDLRN.exe failed to start with 'vcruntime140_1.dll was not found'. The patched PC-DMIS MSI bypasses Hexagon's Burn bundle, which is what would otherwise have pulled this in. Full vc_redist.x64.exe (14.44.35211, 2015-2022 shared CRT). Modern bootstrapper honors /norestart. Detect on the DLL itself so it is version-independent.",
|
||||
"Name": "VC++ Redistributable 2015-2022 x64",
|
||||
"Installer": "vcredist/2022-x64/vc_redist.x64.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "/install /quiet /norestart",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\Windows\\System32\\vcruntime140_1.dll",
|
||||
"PCTypes": ["*"]
|
||||
},
|
||||
{
|
||||
"_comment": "Adobe Acrobat Reader DC - same version as GEA-Engineering image. Two-step install via Install-AcroReader.cmd wrapper: base MSI with enterprise transform (AcroRead.mst) then DC update patch (AcroRdrDCUpd2500120531.msp). Source files on PXE server at /srv/samba/winpeapps/gea-engineer/Deploy/Applications/extra/adobe/ - copy to /srv/samba/enrollment/preinstall/installers/adobe/.",
|
||||
"Name": "Adobe Acrobat Reader DC",
|
||||
|
||||
@@ -38,10 +38,6 @@
|
||||
- gea-standard
|
||||
- gea-engineer
|
||||
- gea-shopfloor
|
||||
- ge-standard
|
||||
- ge-engineer
|
||||
- ge-shopfloor-lockdown
|
||||
- ge-shopfloor-mce
|
||||
shopfloor_types:
|
||||
- gea-shopfloor
|
||||
# Image variants that share the generic Win10/Win11 unattend
|
||||
@@ -50,8 +46,6 @@
|
||||
standard_types:
|
||||
- gea-standard
|
||||
- gea-engineer
|
||||
- ge-standard
|
||||
- ge-engineer
|
||||
deploy_subdirs:
|
||||
- Applications
|
||||
- Control
|
||||
|
||||
@@ -113,6 +113,28 @@ if ($siteConfig -and $siteConfig.pcProfiles -and $profileKey) {
|
||||
}
|
||||
}
|
||||
}
|
||||
# Subtype-strip fallback: a compound key like "gea-shopfloor-cmm-doda" (DODA
|
||||
# CMM bays set pc-subtype.txt=doda) has no profile of its own. Fall back to
|
||||
# the BARE pc-type ("gea-shopfloor-cmm" -> "CMM"). Without this the profile
|
||||
# resolves to $null and callers silently use hardcoded defaults (wrong
|
||||
# desktop icons + unwanted startup items).
|
||||
if (-not $pcProfile -and $pcSubtype) {
|
||||
$bare = $pcType
|
||||
$pcProfile = $siteConfig.pcProfiles.$bare
|
||||
if (-not $pcProfile) {
|
||||
foreach ($g in $pcProfileAliasGroups) {
|
||||
if ($g -icontains $bare) {
|
||||
foreach ($alias in $g) {
|
||||
if ($alias -ieq $bare) { continue }
|
||||
$candidate = $siteConfig.pcProfiles.$alias
|
||||
if ($candidate) { $pcProfile = $candidate; break }
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($pcProfile) { $profileKey = $bare }
|
||||
}
|
||||
}
|
||||
|
||||
if ($pcProfile) {
|
||||
|
||||
@@ -7,10 +7,12 @@ enrollment share. Runs in full Windows (reliable network), so it is immune to th
|
||||
WinPE samba-idle-drop that loses copies during the WIM apply.
|
||||
|
||||
Covers the generic Fetch payload (shopfloor-setup tree + preinstall bundle) AND
|
||||
the heavy per-type payload that Fetch-StagingPayload does NOT pull today: the CMM
|
||||
bundle (C:\CMM-Install) and the selected bay's backup set
|
||||
(C:\CMM-Install\backups\<cmmid>). That is the one that silently goes missing when
|
||||
WinPE staging runs out of time before reboot.
|
||||
the heavy per-type payloads that Fetch-StagingPayload does NOT pull today:
|
||||
- CMM C:\CMM-Install (+ selected bay's backup C:\CMM-Install\backups\<cmmid>)
|
||||
- Keyence C:\KeyenceInstall\<model> (MSI + Data*.cab)
|
||||
- WaxTrace C:\WaxTrace-Install (bundle + bay-matched FormTracePak ISO)
|
||||
These are the ones that silently go missing when WinPE staging runs out of time
|
||||
(idle-dead Y: mount) before reboot.
|
||||
|
||||
Designed to be:
|
||||
- run manually on a problem PC (Verify-And-Heal-Staging.bat), or
|
||||
@@ -89,6 +91,31 @@ if ($pcType -eq 'gea-shopfloor-cmm') {
|
||||
Add-Item "CMM backup ($cmmid)" "installers-post\cmm\backups\$cmmid" "C:\CMM-Install\backups\$cmmid" 'Dir' "C:\CMM-Install\backups\$cmmid" $null $true
|
||||
}
|
||||
}
|
||||
# --- heavy Keyence payload (same gap as CMM: WinPE-only staged, never re-pulled
|
||||
# by Fetch-StagingPayload). Only the selected model bundle lands under
|
||||
# C:\KeyenceInstall\<model>. Verify on the model manifest so a missing/partial
|
||||
# Data1.cab (the 700 MB - 2 GB payload msiexec SECREPAIR-hashes) gets re-pulled. ---
|
||||
if ($pcType -eq 'gea-shopfloor-keyence') {
|
||||
$kmodel = ReadTxt 'C:\Enrollment\keyence-model.txt'
|
||||
if (-not $kmodel) { $kmodel = 'vr6000' }
|
||||
Add-Item "Keyence bundle ($kmodel)" "installers-post\keyence\$kmodel" "C:\KeyenceInstall\$kmodel" 'Dir' "C:\KeyenceInstall\$kmodel\manifest.json"
|
||||
}
|
||||
# --- heavy WaxTrace payload (same gap as CMM/Keyence). Two parts, mirroring the
|
||||
# three-step WinPE stage: (1) the bundle minus the formtracepak\ ISO dir, and
|
||||
# (2) ONLY the bay's matched FORMTRACEPAK-V<ver>.iso, keyed on the version
|
||||
# resolve-bay-config wrote to C:\Enrollment\waxtrace\version.txt during WinPE.
|
||||
# If version.txt is missing (mount died before the resolver ran) the ISO cannot
|
||||
# be re-pulled here - the bundle+resolver still heal, and resolve-bay-config can
|
||||
# be re-run manually to regenerate version.txt then re-run this heal. ---
|
||||
if ($pcType -eq 'gea-shopfloor-waxtrace') {
|
||||
Add-Item 'WaxTrace bundle' 'installers-post\waxtrace' 'C:\WaxTrace-Install' 'Dir' 'C:\WaxTrace-Install\waxtrace-manifest.json' $null $false 'formtracepak'
|
||||
$wtver = ReadTxt 'C:\Enrollment\waxtrace\version.txt'
|
||||
if ($wtver) {
|
||||
Add-Item "WaxTrace FTPak V$wtver" 'installers-post\waxtrace\formtracepak' 'C:\WaxTrace-Install\formtracepak' 'File' "C:\WaxTrace-Install\formtracepak\FORMTRACEPAK-V$wtver.iso" @("FORMTRACEPAK-V$wtver.iso")
|
||||
} else {
|
||||
Log 'WaxTrace: version.txt absent - cannot heal the bay-specific FormTracePak ISO (re-run resolve-bay-config then re-run heal)' 'WARN'
|
||||
}
|
||||
}
|
||||
|
||||
# --- robocopy-based verify/heal -----------------------------------------------
|
||||
# Presence alone is NOT trusted: a partially transferred file (e.g. a truncated
|
||||
|
||||
@@ -175,6 +175,45 @@ foreach ($dir in $pcdmisDirs) {
|
||||
}
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Step 2.5b: GE PC-DMIS FRONT END dir (PCDToIGES.exe error-log path)
|
||||
# ============================================================================
|
||||
# PCDToIGES.exe (in every bay's C:\geaofi\Scripts) writes its error log to
|
||||
# C:\GE PC-DMIS FRONT END\PCDToIGES.ERR inside its catch block. The legacy
|
||||
# "GE PC-DMIS FRONT END" front-end setup that created this dir is not part of
|
||||
# imaging, so on a fresh bay it is absent - and then ANY PCDToIGES failure
|
||||
# becomes an unhandled DirectoryNotFoundException that crashes the export and
|
||||
# MASKS the real error. Create it + grant the operator Modify so errors log.
|
||||
$frontEnd = 'C:\GE PC-DMIS FRONT END'
|
||||
try {
|
||||
if (-not (Test-Path -LiteralPath $frontEnd)) { New-Item -ItemType Directory -Path $frontEnd -Force | Out-Null; Write-CMMLog "Created $frontEnd" }
|
||||
foreach ($sid in '*S-1-5-32-545','*S-1-5-11') { # BUILTIN\Users, NT AUTHORITY\Authenticated Users
|
||||
& icacls "$frontEnd" /grant "${sid}:(OI)(CI)M" /T /C 2>&1 | Out-Null
|
||||
}
|
||||
Write-CMMLog "Granted Users + Authenticated Users Modify on $frontEnd"
|
||||
} catch { Write-CMMLog "Failed to ensure ${frontEnd}: $_" "WARN" }
|
||||
|
||||
# ============================================================================
|
||||
# Step 2.5c: Active Setup - seed goCMM 2.12 DataFolder per-user for ALL users
|
||||
# ============================================================================
|
||||
# goCMM 2.12 stores its shared-data-dir in HKCU\Software\General Electric\goCMM
|
||||
# \DataFolder (decompiled: RegistrySettings uses Registry.CurrentUser - PER USER,
|
||||
# not HKLM). Setting it at imaging only touches the imaging user (SupportUser);
|
||||
# the ShopFloor operator's HKCU would be empty -> goCMM prompts them to pick the
|
||||
# folder on first launch. Active Setup runs StubPath once in EACH user's context
|
||||
# at first logon, so every user (SupportUser, ShopFloor, future) gets
|
||||
# DataFolder=C:\geaofi\. Bump Version to re-push. (Uses Set-ItemProperty in the
|
||||
# stub, not reg.exe, to avoid the trailing-backslash quoting trap.)
|
||||
$asKey = 'HKLM:\SOFTWARE\Microsoft\Active Setup\Installed Components\{8F3B2A10-7C4D-4E9A-B1F6-0A9C5D2E7B43}'
|
||||
try {
|
||||
New-Item -Path $asKey -Force | Out-Null
|
||||
Set-ItemProperty -Path $asKey -Name '(default)' -Value 'goCMM DataFolder (per-user)'
|
||||
Set-ItemProperty -Path $asKey -Name 'Version' -Value '1'
|
||||
$stub = 'powershell.exe -NoProfile -WindowStyle Hidden -Command "New-Item -Path ''HKCU:\SOFTWARE\General Electric\goCMM'' -Force | Out-Null; Set-ItemProperty -Path ''HKCU:\SOFTWARE\General Electric\goCMM'' -Name DataFolder -Value ''C:\geaofi\''"'
|
||||
Set-ItemProperty -Path $asKey -Name 'StubPath' -Value $stub
|
||||
Write-CMMLog "Seeded Active Setup: goCMM DataFolder=C:\geaofi\ (per-user, all users)"
|
||||
} catch { Write-CMMLog "Failed to seed Active Setup goCMM DataFolder: $_" 'WARN' }
|
||||
|
||||
# ============================================================================
|
||||
# Step 2.6: First-run-as-admin for each installed PC-DMIS version
|
||||
# ============================================================================
|
||||
@@ -314,6 +353,28 @@ if (Test-Path -LiteralPath $restoreScript) {
|
||||
Write-CMMLog "Restore-CMM.ps1 not found at $restoreScript - skipping settings restore" 'WARN'
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Step 2.5: drop Register-PCDMIS-COM.bat on the Public desktop
|
||||
# ============================================================================
|
||||
# PC-DMIS COM must be registered for goCMM to connect, but /regserver no-ops
|
||||
# until PC-DMIS is licensed - which happens manually post-image (clmadmin.exe).
|
||||
# So we cannot register at imaging time; instead leave a one-click helper the
|
||||
# tech runs AFTER activating the license. Public Desktop so it is visible to
|
||||
# whoever logs in (operator or SupportUser). NOTE: 06-OrganizeDesktop sweeps the
|
||||
# Public Desktop root into category subfolders, so it may end up under
|
||||
# "Shopfloor Tools" rather than the bare desktop - still on the Public desktop.
|
||||
$regBat = Join-Path $stagingRoot 'Register-PCDMIS-COM.bat'
|
||||
if (Test-Path -LiteralPath $regBat) {
|
||||
$d = 'C:\Users\Public\Desktop'
|
||||
try {
|
||||
if (-not (Test-Path $d)) { New-Item -Path $d -ItemType Directory -Force | Out-Null }
|
||||
Copy-Item -LiteralPath $regBat -Destination (Join-Path $d 'Register-PCDMIS-COM.bat') -Force
|
||||
Write-CMMLog "Staged Register-PCDMIS-COM.bat -> $d"
|
||||
} catch { Write-CMMLog "Failed to stage Register-PCDMIS-COM.bat to ${d}: $_" 'WARN' }
|
||||
} else {
|
||||
Write-CMMLog "Register-PCDMIS-COM.bat not in staging ($regBat) - desktop helper NOT placed" 'WARN'
|
||||
}
|
||||
|
||||
# ============================================================================
|
||||
# Step 3: Conditional cleanup of the bootstrap staging dir
|
||||
# ============================================================================
|
||||
|
||||
@@ -1,48 +1,165 @@
|
||||
# Install-DODA.ps1 - Extract DODA zip to C:\Apps\DODA\.
|
||||
# Install-DODA.ps1 - full unattended DODA install (runtimes + app + config + ACLs).
|
||||
#
|
||||
# Called by Install-FromManifest as a Type=PS1 entry. The zip is staged
|
||||
# alongside this script in C:\CMM-Install\ by startnet.cmd.
|
||||
# The vendor GE_DODA_build5_Installer.exe is a multi-app NSIS bundler. Its /S
|
||||
# silent mode is BROKEN (a nested sub-install gets a bad package path -> MSI
|
||||
# error 1619), so it cannot be used for imaging. Each bundled component installs
|
||||
# cleanly on its own, so we drive them directly here. (VM-validated 2026-06-17.)
|
||||
#
|
||||
# Components staged in C:\CMM-Install (robocopied from the SFLD/enrollment share
|
||||
# by startnet.cmd), all installed SILENTLY:
|
||||
# python-2.7.16.amd64.msi -> C:\Python27 (msiexec /qn)
|
||||
# java-1.8.0-openjdk-*.msi -> C:\Program Files\RedHat (msiexec /qn)
|
||||
# gs927w64.exe -> C:\Program Files\gs\gs9.27 (/S)
|
||||
# vc_redist.x64.exe -> VC++ runtime (/quiet)
|
||||
# doda_build*.zip -> C:\Apps\DODA (app files)
|
||||
#
|
||||
# DODA at runtime is DovetailAnalysis.exe -> JVM (OpenJDK) + C:\Python27 python +
|
||||
# Ghostscript (PS->PDF). .settings (NOT in the zip - the NSIS installer wrote it)
|
||||
# hardcodes those paths; we write it here.
|
||||
#
|
||||
# LOCKDOWN: DovetailAnalysis.exe runs as the locked-down OPERATOR (not admin) and
|
||||
# writes throughout C:\Apps\DODA (.pyc, PreProcess) + $TMP. We (a) grant Users +
|
||||
# Authenticated Users Full on C:\Apps\DODA and (b) PRECOMPILE the .py to .pyc as
|
||||
# admin so the operator never needs to write bytecode into a protected path.
|
||||
#
|
||||
# Run as administrator / SYSTEM (imaging or GE-Enforce). Idempotent: each step
|
||||
# detects-and-skips if already present, and ACL/.settings/env re-assert every run
|
||||
# (so a post-lockdown re-run repairs a stripped ACE).
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
|
||||
# The doda zip + runtime installers are staged ALONGSIDE this script (same dir).
|
||||
# When the manifest runs it, that dir is C:\CMM-Install (= $PSScriptRoot).
|
||||
$stagingRoot = $PSScriptRoot
|
||||
if (-not $stagingRoot -or -not (Test-Path $stagingRoot)) { $stagingRoot = 'C:\CMM-Install' }
|
||||
$installDir = 'C:\Apps\DODA'
|
||||
$zipPattern = 'doda_build*.zip'
|
||||
$stagingRoot = Split-Path $PSScriptRoot -ErrorAction SilentlyContinue
|
||||
if (-not $stagingRoot) { $stagingRoot = 'C:\CMM-Install' }
|
||||
$python27 = 'C:\Python27\python.exe'
|
||||
$gsExe = 'C:\Program Files\gs\gs9.27\bin\gswin64c.exe'
|
||||
|
||||
$zip = Get-ChildItem -Path $stagingRoot -Filter $zipPattern -File -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $zip) {
|
||||
Write-Host "DODA zip not found in $stagingRoot (pattern: $zipPattern)"
|
||||
exit 1
|
||||
$logDir = 'C:\Logs\CMM'
|
||||
New-Item -ItemType Directory -Path $logDir -Force -EA SilentlyContinue | Out-Null
|
||||
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$log = Join-Path $logDir "doda-install-$ts.log"
|
||||
function Log($m){ $line = "[{0}] {1}" -f (Get-Date -Format 'HH:mm:ss'), $m; Write-Host $line; Add-Content -Path $log -Value $line -EA SilentlyContinue }
|
||||
|
||||
function Find-One($pattern) {
|
||||
Get-ChildItem -Path $stagingRoot -Filter $pattern -File -EA SilentlyContinue | Select-Object -First 1
|
||||
}
|
||||
|
||||
if (-not (Test-Path $installDir)) {
|
||||
New-Item -Path $installDir -ItemType Directory -Force | Out-Null
|
||||
}
|
||||
Log "==== DODA install on $env:COMPUTERNAME (staging=$stagingRoot) ===="
|
||||
|
||||
Write-Host "Extracting $($zip.Name) to $installDir..."
|
||||
try {
|
||||
Expand-Archive -LiteralPath $zip.FullName -DestinationPath $installDir -Force -ErrorAction Stop
|
||||
Write-Host "DODA extracted to $installDir"
|
||||
} catch {
|
||||
Write-Host "ERROR: Extract failed - $_"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# MergeFiles.exe (cmm-utilities toolchain) reads C:\Apps\DODA\PreProcess\ as
|
||||
# its working dir. The DODA zip extracts flat without it, so create it here -
|
||||
# a missing PreProcess dir is the known cause of MergeFiles.GetDoDAFolder
|
||||
# throwing DirectoryNotFoundException (see cmm-utilities dotNET event.txt).
|
||||
$preProcess = Join-Path $installDir 'PreProcess'
|
||||
if (-not (Test-Path $preProcess)) {
|
||||
New-Item -Path $preProcess -ItemType Directory -Force | Out-Null
|
||||
Write-Host "Created $preProcess"
|
||||
}
|
||||
|
||||
if (Test-Path (Join-Path $installDir 'DovetailAnalysis.exe')) {
|
||||
Write-Host "DovetailAnalysis.exe verified present"
|
||||
exit 0
|
||||
# --- 1. Python 2.7 ----------------------------------------------------------
|
||||
if (Test-Path $python27) {
|
||||
Log "Python 2.7 already present - skip"
|
||||
} else {
|
||||
Write-Host "ERROR: DovetailAnalysis.exe not found after extract"
|
||||
$msi = Find-One 'python-2.7*.msi'
|
||||
if ($msi) {
|
||||
Log "Installing Python: $($msi.Name)"
|
||||
$p = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/i', "`"$($msi.FullName)`"", '/qn', '/norestart', 'ADDLOCAL=ALL')
|
||||
Log " Python msiexec exit $($p.ExitCode)"
|
||||
} else { Log "WARN: python-2.7*.msi not found in $stagingRoot" }
|
||||
}
|
||||
|
||||
# --- 2. OpenJDK 8 -----------------------------------------------------------
|
||||
$jdk = Get-ChildItem 'C:\Program Files\RedHat','C:\Program Files\Java' -Directory -EA SilentlyContinue |
|
||||
Where-Object Name -match 'openjdk|jdk|jre' | Select-Object -First 1
|
||||
if ($jdk) {
|
||||
Log "OpenJDK already present ($($jdk.Name)) - skip"
|
||||
} else {
|
||||
$msi = Find-One 'java-*openjdk*.msi'
|
||||
if ($msi) {
|
||||
Log "Installing OpenJDK: $($msi.Name)"
|
||||
$p = Start-Process msiexec.exe -Wait -PassThru -ArgumentList @('/i', "`"$($msi.FullName)`"", '/qn', '/norestart')
|
||||
Log " OpenJDK msiexec exit $($p.ExitCode)"
|
||||
$jdk = Get-ChildItem 'C:\Program Files\RedHat','C:\Program Files\Java' -Directory -EA SilentlyContinue |
|
||||
Where-Object Name -match 'openjdk|jdk|jre' | Select-Object -First 1
|
||||
} else { Log "WARN: java-*openjdk*.msi not found in $stagingRoot" }
|
||||
}
|
||||
|
||||
# --- 3. Ghostscript 9.27 ----------------------------------------------------
|
||||
if (Test-Path $gsExe) {
|
||||
Log "Ghostscript 9.27 already present - skip"
|
||||
} else {
|
||||
$gs = Find-One 'gs927w64.exe'
|
||||
if ($gs) {
|
||||
Log "Installing Ghostscript: $($gs.Name)"
|
||||
$p = Start-Process $gs.FullName -Wait -PassThru -ArgumentList '/S'
|
||||
Log " Ghostscript exit $($p.ExitCode)"
|
||||
} else { Log "WARN: gs927w64.exe not found in $stagingRoot" }
|
||||
}
|
||||
|
||||
# --- 4. VC++ redist (best-effort) ------------------------------------------
|
||||
$vc = Find-One 'vc_redist.x64.exe'
|
||||
if ($vc) {
|
||||
Log "Installing VC++ redist: $($vc.Name)"
|
||||
$p = Start-Process $vc.FullName -Wait -PassThru -ArgumentList @('/quiet', '/norestart')
|
||||
Log " VC++ exit $($p.ExitCode) (1638/3010 = already-present/ok)"
|
||||
} else { Log "VC++ redist not staged - skipping (usually already present)" }
|
||||
|
||||
# --- 5. DODA app files ------------------------------------------------------
|
||||
$zip = Find-One 'doda_build*.zip'
|
||||
if (-not $zip) {
|
||||
Log "ERROR: doda_build*.zip not found in $stagingRoot - cannot place DODA app"
|
||||
} else {
|
||||
New-Item -ItemType Directory -Path $installDir -Force -EA SilentlyContinue | Out-Null
|
||||
Log "Extracting $($zip.Name) -> $installDir"
|
||||
try { Expand-Archive -LiteralPath $zip.FullName -DestinationPath $installDir -Force -EA Stop }
|
||||
catch { Log "ERROR: extract failed - $_" }
|
||||
}
|
||||
|
||||
# --- 6. .settings (the NSIS installer wrote this; the zip does NOT contain it) ---
|
||||
$settings = Join-Path $installDir '.settings'
|
||||
$settingsBody = @'
|
||||
WORKING_DIR=$TMP
|
||||
PYTHONEXE=C:\Python27\python.exe
|
||||
OPTIONS_FILE="$WORKING_DIR/dvt_run_options.py"
|
||||
RPT_GUI=$PYTHONEXE $AFDA_INSTALL_DIR/dvtRptGui.py -file=$OPTIONS_FILE
|
||||
OUTPUT_PROCESSOR=$PYTHONEXE $AFDA_INSTALL_DIR/processOutput.py $OPTIONS_FILE
|
||||
PS2PDF="C:\Program Files\gs\gs9.27\bin\gswin64c.exe" -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$$out $$in
|
||||
'@
|
||||
if (Test-Path $installDir) {
|
||||
Set-Content -Path $settings -Value $settingsBody -Encoding ascii -Force
|
||||
Log "Wrote $settings"
|
||||
}
|
||||
|
||||
# --- 7. PreProcess dir (MergeFiles GetDoDAFolder reads it) ------------------
|
||||
$preProcess = Join-Path $installDir 'PreProcess'
|
||||
if (-not (Test-Path $preProcess)) { New-Item -ItemType Directory -Path $preProcess -Force | Out-Null; Log "Created $preProcess" }
|
||||
|
||||
# --- 8. Env: AFDA_INSTALL_DIR + Java on PATH (machine scope) ----------------
|
||||
[Environment]::SetEnvironmentVariable('AFDA_INSTALL_DIR', $installDir, 'Machine')
|
||||
Log "Set AFDA_INSTALL_DIR=$installDir (Machine)"
|
||||
if ($jdk) {
|
||||
$machPath = [Environment]::GetEnvironmentVariable('PATH','Machine')
|
||||
foreach ($add in @((Join-Path $jdk.FullName 'bin'), (Join-Path $jdk.FullName 'jre\bin'))) {
|
||||
if (Test-Path $add) {
|
||||
$parts = $machPath -split ';'
|
||||
if ($parts -notcontains $add) { $machPath = "$machPath;$add"; Log "PATH += $add" }
|
||||
}
|
||||
}
|
||||
[Environment]::SetEnvironmentVariable('PATH', $machPath, 'Machine')
|
||||
}
|
||||
|
||||
# --- 9. Precompile .py -> .pyc as admin (so the locked-down operator never
|
||||
# needs write access to compile bytecode at runtime) ------------------
|
||||
if ((Test-Path $python27) -and (Test-Path $installDir)) {
|
||||
Log "Precompiling DODA .py with $python27"
|
||||
$p = Start-Process $python27 -Wait -PassThru -ArgumentList @('-m','compileall', "`"$installDir`"") -WindowStyle Hidden
|
||||
Log " compileall exit $($p.ExitCode)"
|
||||
}
|
||||
|
||||
# --- 10. ACLs: Users + Authenticated Users Full on C:\Apps\DODA so the
|
||||
# locked-down operator can run DODA (writes .pyc/PreProcess/output) ---
|
||||
if (Test-Path $installDir) {
|
||||
foreach ($sid in '*S-1-5-32-545','*S-1-5-11') { # BUILTIN\Users, NT AUTHORITY\Authenticated Users
|
||||
& icacls $installDir /grant "${sid}:(OI)(CI)F" /T /C 2>&1 | Out-Null
|
||||
}
|
||||
Log "Granted Users + Authenticated Users Full on $installDir (recursive)"
|
||||
}
|
||||
|
||||
# --- Verify -----------------------------------------------------------------
|
||||
$ok = (Test-Path (Join-Path $installDir 'DovetailAnalysis.exe')) -and (Test-Path $python27) -and (Test-Path $gsExe) -and $jdk
|
||||
if ($ok) { Log "==== DODA install OK (DovetailAnalysis + Python27 + Ghostscript + OpenJDK present) ===="; exit 0 }
|
||||
else {
|
||||
Log "==== DODA install INCOMPLETE - DovetailAnalysis=$([bool](Test-Path (Join-Path $installDir 'DovetailAnalysis.exe'))) Python=$([bool](Test-Path $python27)) GS=$([bool](Test-Path $gsExe)) JDK=$([bool]$jdk) ===="
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
@echo off
|
||||
REM ============================================================================
|
||||
REM Register-PCDMIS-COM.bat - register the PC-DMIS COM / automation server.
|
||||
REM
|
||||
REM WHY: goCMM connects to PC-DMIS over COM. If the COM server is not
|
||||
REM registered, goCMM throws "Object reference not set to an instance of an
|
||||
REM object" at startup (it calls Type.GetTypeFromProgID on the PC-DMIS ProgID,
|
||||
REM gets null, then Activator.CreateInstance(null) -> ArgumentNullException).
|
||||
REM
|
||||
REM IMPORTANT: PC-DMIS must be LICENSED FIRST. /regserver does NOT register the
|
||||
REM COM server until a valid license is present. Activate the license with
|
||||
REM clmadmin.exe, THEN run this. Safe to re-run any time goCMM stops connecting.
|
||||
REM
|
||||
REM Needs admin - this script self-elevates via UAC.
|
||||
REM ============================================================================
|
||||
|
||||
REM --- self-elevate if not already running as admin ---
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo Requesting administrator rights...
|
||||
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo ================================================================
|
||||
echo Register PC-DMIS COM server (run AFTER licensing PC-DMIS)
|
||||
echo ================================================================
|
||||
echo.
|
||||
|
||||
setlocal enabledelayedexpansion
|
||||
set "FOUND="
|
||||
for %%D in (
|
||||
"C:\Program Files\Hexagon"
|
||||
"C:\Program Files (x86)\Hexagon"
|
||||
"C:\Program Files\WAI"
|
||||
"C:\Program Files (x86)\WAI"
|
||||
) do (
|
||||
if exist %%~D (
|
||||
for /f "delims=" %%F in ('dir /b /s "%%~D\Pcdlrn.exe" 2^>nul') do (
|
||||
set "FOUND=1"
|
||||
echo Registering: %%F
|
||||
"%%F" /regserver
|
||||
if !errorlevel! equ 0 (echo OK) else (echo regserver returned !errorlevel!)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
echo.
|
||||
if not defined FOUND (
|
||||
echo ERROR: Pcdlrn.exe not found. Is PC-DMIS installed?
|
||||
) else (
|
||||
echo Done.
|
||||
echo If goCMM still errors, confirm PC-DMIS is LICENSED ^(clmadmin.exe^) and
|
||||
echo that you ran this AFTER activating the license, then re-run.
|
||||
)
|
||||
echo.
|
||||
pause
|
||||
@@ -2,12 +2,12 @@ cmm_id,pcdmis_version,doda,part_group
|
||||
CMM1,2019,no,S:\CMM\CMM1\HPTCMM1
|
||||
CMM2,2019,no,S:\CMM\CMM2\HPT
|
||||
CMM3,2019,no,S:\CMM\CMM3\VENTURE_CMM3
|
||||
CMM4,2016,no,S:\CMM\CMM4\Spool
|
||||
CMM4,2016,yes,S:\CMM\CMM4\Spool
|
||||
CMM5,2019,no,S:\CMM\CMM5\BLISKCMM5
|
||||
CMM6,2019,no,S:\CMM\CMM6\BLISKCMM6
|
||||
CMM7,2019,no,S:\CMM\CMM7\VENTURE_CMM7
|
||||
CMM8,2019,no,S:\CMM\CMM8\Venture CMM8
|
||||
CMM9,2019,no,S:\CMM\CMM9\BLISKCMM9
|
||||
CMM10,2016,no,S:\CMM\CMM10\Spool
|
||||
CMM11,2026,no,S:\CMM\CMM11\Spool
|
||||
CMM12,2026,no,S:\CMM\CMM12\Spool
|
||||
CMM10,2016,yes,S:\CMM\CMM10\Spool
|
||||
CMM11,2026,yes,S:\CMM\CMM11\Spool
|
||||
CMM12,2026,yes,S:\CMM\CMM12\Spool
|
||||
|
||||
|
@@ -57,19 +57,18 @@
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{a55fecde-0776-474e-a5b3-d57ea93d6a9f}"
|
||||
},
|
||||
{
|
||||
"_comment": "goCMM - Hexagon CMM job launcher. Install for all versions.",
|
||||
"Name": "goCMM",
|
||||
"Installer": "goCMM_1.1.6718.31289.exe",
|
||||
"_comment": "goCMM 2.12.3 - Hexagon/Renishaw CMM job launcher. NSIS installer; silent switch is /S (NOT /quiet - that was the WiX 1.1 bundle). Installs to C:\\Program Files\\goCMM and runs no-admin (asInvoker, VM-verified). This is the IMAGING manifest only, so NEW images get 2.12; the tsgwp00525 SFLD enforce manifest stays on goCMM 1.1 so already-deployed bays are NOT auto-upgraded. Install for all versions.",
|
||||
"Name": "goCMM 2.12.3",
|
||||
"Installer": "goCMM_2.12.3.0_Release.exe",
|
||||
"Type": "EXE",
|
||||
"InstallArgs": "/quiet /norestart /log \"C:\\Logs\\CMM\\goCMM.log\"",
|
||||
"LogFile": "C:\\Logs\\CMM\\goCMM.log",
|
||||
"DetectionMethod": "Registry",
|
||||
"DetectionPath": "HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{94f02b85-bbca-422e-9b8b-0c16a769eced}"
|
||||
"InstallArgs": "/S",
|
||||
"DetectionMethod": "File",
|
||||
"DetectionPath": "C:\\Program Files\\goCMM\\goCMM.exe"
|
||||
},
|
||||
{
|
||||
"_comment": "DODA - Dovetail Digital Analysis. Deployed as a flat file extract to C:\\Apps\\DODA\\. Only installed when doda.txt=yes (pc-subtype.txt=doda gates this via PCTypes).",
|
||||
"_comment": "DODA - Dovetail Digital Analysis. Deployed as a flat file extract to C:\\Apps\\DODA\\. Only installed when doda.txt=yes -> startnet writes pc-subtype.txt=doda -> 09-Setup passes PCType=gea-shopfloor-cmm + PCSubType=doda -> matcher builds 'gea-shopfloor-cmm-doda'. PCTypes MUST be that exact Type-SubType string ('cmm-doda' never matched - the alias of gea-shopfloor-cmm is bare 'CMM', no subtype variant).",
|
||||
"Name": "DODA",
|
||||
"PCTypes": ["cmm-doda"],
|
||||
"PCTypes": ["gea-shopfloor-cmm-doda"],
|
||||
"Type": "PS1",
|
||||
"Script": "Install-DODA.ps1",
|
||||
"DetectionMethod": "File",
|
||||
|
||||
@@ -63,6 +63,30 @@ foreach ($s in 'Backup-goCMMSettings.ps1','Backup-PCDMISSettings.ps1') {
|
||||
catch { Log " ERROR in $s : $($_.Exception.Message)" }
|
||||
}
|
||||
|
||||
# --- C:\Program Files\WAI (+ x86): whole vendor tree, captured complete.
|
||||
# Holds machine/controller content beyond what the per-version PC-DMIS backup
|
||||
# grabs. NOTE: can be multi-GB if WAI contains the full PC-DMIS 2016 install. ---
|
||||
$waiRoots = @("$env:ProgramFiles\WAI", "${env:ProgramFiles(x86)}\WAI")
|
||||
$waiPresent = @($waiRoots | Where-Object { Test-Path $_ })
|
||||
if ($waiPresent.Count -gt 0) {
|
||||
Log "---- capturing WAI tree (whole) ----"
|
||||
$waiStage = Join-Path $env:TEMP "wai-bk-$ts"
|
||||
New-Item -ItemType Directory -Path $waiStage -Force | Out-Null
|
||||
foreach ($wr in $waiPresent) {
|
||||
$label = if ($wr -like '*(x86)*') { 'WAI-x86' } else { 'WAI' }
|
||||
robocopy $wr (Join-Path $waiStage $label) /E /R:1 /W:1 /NFL /NDL /NJH /NJS | Out-Null
|
||||
Log " copied $wr -> $label"
|
||||
}
|
||||
$waiZip = Join-Path $dest "wai_backup_${env:COMPUTERNAME}_$ts.zip"
|
||||
if (Test-Path $waiZip) { Remove-Item $waiZip -Force }
|
||||
Add-Type -AssemblyName System.IO.Compression.FileSystem
|
||||
[System.IO.Compression.ZipFile]::CreateFromDirectory($waiStage, $waiZip)
|
||||
Remove-Item $waiStage -Recurse -Force -EA SilentlyContinue
|
||||
Log " WAI backup: $waiZip ($([math]::Round((Get-Item $waiZip).Length/1MB)) MB)"
|
||||
} else {
|
||||
Log "No C:\Program Files\WAI (or x86) - skipping WAI backup"
|
||||
}
|
||||
|
||||
# index of what we captured
|
||||
$zips = Get-ChildItem $dest -Filter '*.zip' -File -ErrorAction SilentlyContinue
|
||||
[pscustomobject]@{
|
||||
@@ -71,6 +95,7 @@ $zips = Get-ChildItem $dest -Filter '*.zip' -File -ErrorAction SilentlyContinue
|
||||
Timestamp = (Get-Date -Format o)
|
||||
goCMM = @($zips | Where-Object { $_.Name -like 'gocmm_backup_*' } | Select-Object -Expand Name)
|
||||
PCDMIS = @($zips | Where-Object { $_.Name -like 'pcdmis_backup_*' } | Select-Object -Expand Name)
|
||||
WAI = @($zips | Where-Object { $_.Name -like 'wai_backup_*' } | Select-Object -Expand Name)
|
||||
} | ConvertTo-Json | Out-File (Join-Path $dest 'cmm-backup-index.json') -Encoding ascii
|
||||
|
||||
Log "================ DONE ================"
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
<#
|
||||
Convert-goCMMSettings.ps1
|
||||
|
||||
Convert a legacy goCMM 1.1 ApplicationSettings.xml (C:\geaofi\) to the goCMM
|
||||
2.12.3 goCMMSettings.xml schema.
|
||||
|
||||
The two are different SettingsModel schemas (different filename too). This is a
|
||||
TEMPLATE-based converter: new-only fields get defaults, the per-bay values are
|
||||
carried over from the old XML (+ optional overrides). Decisions baked in
|
||||
(2026-06-19): access-control left blank, operator key normalized to "Operator",
|
||||
cal intervals/restart use template defaults (old values NOT carried), Slack/Andon
|
||||
/Quindos/Emx dropped.
|
||||
|
||||
Program paths default to the goCMM 2.12 convention (C:\geaofi\goCMM PC-DMIS
|
||||
Programs\) - override with -ResetProgram / -ProbeCalibrationProgram if the .PRG
|
||||
files live elsewhere. Those .PRG files MUST exist at the path written here.
|
||||
|
||||
Usage:
|
||||
.\Convert-goCMMSettings.ps1 -OldXml C:\geaofi\ApplicationSettings.xml `
|
||||
-OutFile C:\geaofi\goCMMSettings.xml -PcdmisVersion 2016 -CmmId CMM10
|
||||
#>
|
||||
param(
|
||||
[Parameter(Mandatory=$true)][string]$OldXml,
|
||||
[Parameter(Mandatory=$true)][string]$OutFile,
|
||||
[string]$PcdmisVersion, # 2016 | 2019 | 2026 (or full "PC-DMIS ... 64-bit")
|
||||
[string]$CmmId, # e.g. CMM10 - used for the cal-program name default
|
||||
[string]$PartGroup, # optional override (friendly S:\ or UNC); else from old XML
|
||||
[string]$ResetProgram, # optional override
|
||||
[string]$ProbeCalibrationProgram # optional override
|
||||
)
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
if (-not (Test-Path -LiteralPath $OldXml)) { throw "Old XML not found: $OldXml" }
|
||||
[xml]$old = Get-Content -LiteralPath $OldXml -Raw
|
||||
|
||||
# --- part-group share canonicalization (FQDN + \SHARED, matches goCMM 2.12) ---
|
||||
function Canon([string]$pg) {
|
||||
if (-not $pg) { return $pg }
|
||||
$pg = $pg -replace '(?i)^S:\\', '\\tsgwp00525.wjs.geaerospace.net\SHARED\'
|
||||
$pg = [regex]::Replace($pg, '(?i)\\\\tsgwp00525(?:\.[A-Za-z0-9.\-]+)?\\shared(?=\\|$)', '\\tsgwp00525.wjs.geaerospace.net\SHARED')
|
||||
return $pg
|
||||
}
|
||||
|
||||
# --- resolve per-bay values (override -> old XML -> default) ---
|
||||
# NOTE: read attributes with GetAttribute() - .Name collides with XmlElement.Name.
|
||||
$pg = $PartGroup
|
||||
if (-not $pg) {
|
||||
$pgNode = $old.SettingsModel.PartGroups.PartGroup
|
||||
if ($pgNode) { $pg = $pgNode.GetAttribute('FullName'); if (-not $pg) { $pg = $pgNode.FullName } }
|
||||
}
|
||||
$pg = Canon $pg
|
||||
|
||||
# NB: PowerShell vars are case-insensitive - do NOT name this $cmmid (collides with the $CmmId param).
|
||||
$machineCmmId = $old.SettingsModel.MachineDefinition.CMMID
|
||||
if (-not $machineCmmId -and $CmmId) { $machineCmmId = "WJRP/$CmmId" }
|
||||
|
||||
# SelectedVersionString from -PcdmisVersion
|
||||
$verMap = @{ '2016' = 'PC-DMIS 2016.0 64-bit'; '2019' = 'PC-DMIS 2019 R2 64-bit'; '2026' = 'PC-DMIS 2026.1 64-bit' }
|
||||
$selVer = ''
|
||||
if ($PcdmisVersion) { $selVer = if ($verMap.ContainsKey($PcdmisVersion)) { $verMap[$PcdmisVersion] } else { $PcdmisVersion } }
|
||||
|
||||
# bool carryovers (old flat flags -> new IsEnabled)
|
||||
function OldBool($node, $default='false') { $v = $node; if ($null -eq $v -or $v -eq '') { $default } else { ([string]$v).ToLower() } }
|
||||
$pcdmisEnabled = OldBool $old.SettingsModel.UsingPcDmis 'true'
|
||||
$modusEnabled = OldBool $old.SettingsModel.UsingModus 'false'
|
||||
$winState = if ($old.SettingsModel.DefaultWindowState) { $old.SettingsModel.DefaultWindowState } else { 'Maximized' }
|
||||
$allowSel = OldBool $old.SettingsModel.AllowOperationProgramSelection 'true'
|
||||
$visExec = OldBool $old.SettingsModel.PcDmisSettings.VisibleDuringExecution 'true'
|
||||
$cmmMode = if ($old.SettingsModel.PcDmisSettings.CMMMode) { $old.SettingsModel.PcDmisSettings.CMMMode } else { 'Online' }
|
||||
$sizeTol = if ($old.SettingsModel.MachineDefinition.ProbeCalSizeTol) { $old.SettingsModel.MachineDefinition.ProbeCalSizeTol } else { '0.0005' }
|
||||
$formTol = if ($old.SettingsModel.MachineDefinition.ProbeCalFormTol) { $old.SettingsModel.MachineDefinition.ProbeCalFormTol } else { '0.0005' }
|
||||
$hasRotary = OldBool $old.SettingsModel.MachineDefinition.MachineHasRotaryTable 'false'
|
||||
|
||||
# program paths (override -> goCMM 2.12 convention default)
|
||||
$progDir = 'C:\geaofi\goCMM PC-DMIS Programs'
|
||||
if (-not $ResetProgram) { $ResetProgram = "$progDir\MachineResetProgram.prg" }
|
||||
if (-not $ProbeCalibrationProgram) {
|
||||
$calName = if ($CmmId) { "${CmmId}_Cal_All_Probes_rev2.PRG" } else { 'Cal_All_Probes_rev2.PRG' }
|
||||
$ProbeCalibrationProgram = "$progDir\$calName"
|
||||
}
|
||||
|
||||
# --- operator inputs (old KeyLabel + NonTBIInputs -> new OperatorInput; OPER -> Operator) ---
|
||||
$inputs = @()
|
||||
$kl = $old.SettingsModel.OperatorInputs.KeyLabel
|
||||
if ($kl) { $inputs += [pscustomobject]@{ Key = $kl.GetAttribute('Name'); Display = $kl.GetAttribute('Display') } }
|
||||
foreach ($oi in $old.SettingsModel.OperatorInputs.NonTBIInputs.OperatorInput) {
|
||||
if ($oi -is [System.Xml.XmlElement]) { $inputs += [pscustomobject]@{ Key = $oi.GetAttribute('Name'); Display = $oi.GetAttribute('Display') } }
|
||||
}
|
||||
if (-not $inputs) {
|
||||
$inputs = @([pscustomobject]@{Key='SERNO';Display='Serial Number'}, [pscustomobject]@{Key='Operator';Display='Operator'})
|
||||
}
|
||||
$opXml = ($inputs | ForEach-Object {
|
||||
$k = if ($_.Key -ieq 'OPER') { 'Operator' } else { $_.Key } # decision #4
|
||||
$d = if ($_.Key -ieq 'OPER') { 'Operator' } else { $_.Display }
|
||||
" <OperatorInput ClearInput=`"true`">`n <Key>$k</Key>`n <DisplayName>$d</DisplayName>`n <ValidationRules />`n </OperatorInput>"
|
||||
}) -join "`n"
|
||||
|
||||
function X([string]$s){ [System.Security.SecurityElement]::Escape($s) }
|
||||
|
||||
$xml = @"
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<SettingsModel xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" LockInterface="false" AdminGroupName="" PowerUsersGroupName="" PasswordHash="" PasswordSalt="" LockMachineReset="false">
|
||||
<MaintainFolderStructureWhenCopying>true</MaintainFolderStructureWhenCopying>
|
||||
<DefaultSoftware>PCDMIS</DefaultSoftware>
|
||||
<PartGroups>
|
||||
<PartGroup>
|
||||
<FullName>$(X $pg)</FullName>
|
||||
<Children />
|
||||
</PartGroup>
|
||||
</PartGroups>
|
||||
<OperatorInputs>
|
||||
$opXml
|
||||
</OperatorInputs>
|
||||
<UseBladeGrid>false</UseBladeGrid>
|
||||
<DefaultWindowState>$(X $winState)</DefaultWindowState>
|
||||
<AllowOperationProgramSelection>$allowSel</AllowOperationProgramSelection>
|
||||
<BladesDatFile />
|
||||
<PcDmisSettings>
|
||||
<IsEnabled>$pcdmisEnabled</IsEnabled>
|
||||
<VisibleDuringExecution>$visExec</VisibleDuringExecution>
|
||||
<ResetProgram>$(X $ResetProgram)</ResetProgram>
|
||||
<RotaryTableCalibrationProgram />
|
||||
<TrackProbeCalibration>false</TrackProbeCalibration>
|
||||
<TrackRotaryTableCalbiration>false</TrackRotaryTableCalbiration>
|
||||
<ProbeCalibrationProgram>$(X $ProbeCalibrationProgram)</ProbeCalibrationProgram>
|
||||
<RotaryTableCalibration />
|
||||
<IPPServerExe />
|
||||
<IPPArguments />
|
||||
<SaveAndClose>false</SaveAndClose>
|
||||
<DelayMeasurementRoutines>false</DelayMeasurementRoutines>
|
||||
<MeasurementRoutineDelay>1000</MeasurementRoutineDelay>
|
||||
<Restart>true</Restart>
|
||||
<RestartMode>ProgramCount</RestartMode>
|
||||
<UseIPPServer>false</UseIPPServer>
|
||||
<SelectedVersionString>$(X $selVer)</SelectedVersionString>
|
||||
<NumberOfProgramsBeforeRestart>5</NumberOfProgramsBeforeRestart>
|
||||
<RestartDelay>5</RestartDelay>
|
||||
<StartupDelay>0</StartupDelay>
|
||||
<UseOtherSoftwareForRotaryCal>false</UseOtherSoftwareForRotaryCal>
|
||||
<UseOtherSoftwareForProbeCalibration>false</UseOtherSoftwareForProbeCalibration>
|
||||
<RotaryCalSoftware />
|
||||
<ProbeCalSoftware />
|
||||
</PcDmisSettings>
|
||||
<ModusSettings>
|
||||
<IsEnabled>$modusEnabled</IsEnabled>
|
||||
<VisibleDuringExecution>true</VisibleDuringExecution>
|
||||
<ResetProgram />
|
||||
<RotaryTableCalibrationProgram />
|
||||
<TrackProbeCalibration>false</TrackProbeCalibration>
|
||||
<TrackRotaryTableCalbiration>false</TrackRotaryTableCalbiration>
|
||||
<ProbeCalibrationProgram />
|
||||
<RotaryTableCalibration />
|
||||
<IPPServerExe />
|
||||
<IPPArguments />
|
||||
<ModusArguments>-Organiser</ModusArguments>
|
||||
</ModusSettings>
|
||||
<MachineDefinition>
|
||||
<CMMID>$(X $machineCmmId)</CMMID>
|
||||
<MachineType />
|
||||
<HeadType />
|
||||
<ForceProbeCalibration>false</ForceProbeCalibration>
|
||||
<ProbeCalSizeTol>$sizeTol</ProbeCalSizeTol>
|
||||
<ProbeCalFormTolerance>$formTol</ProbeCalFormTolerance>
|
||||
<ProbeCalibrationInterval>
|
||||
<Hours>72</Hours>
|
||||
<Minutes>0</Minutes>
|
||||
</ProbeCalibrationInterval>
|
||||
<RotaryTableCalibrationInterval>
|
||||
<Hours>24</Hours>
|
||||
<Minutes>0</Minutes>
|
||||
</RotaryTableCalibrationInterval>
|
||||
<MachineHasRotary>$hasRotary</MachineHasRotary>
|
||||
<ForceRotaryCalibration>false</ForceRotaryCalibration>
|
||||
<CMMMode>$(X $cmmMode)</CMMMode>
|
||||
</MachineDefinition>
|
||||
<Notifications UseAndon="false">
|
||||
<Notifications />
|
||||
</Notifications>
|
||||
<ProgramConstants />
|
||||
<CommonFiles />
|
||||
</SettingsModel>
|
||||
"@
|
||||
|
||||
$dir = Split-Path -Parent $OutFile
|
||||
if ($dir -and -not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null }
|
||||
# validate well-formed before writing
|
||||
[void][xml]$xml
|
||||
Set-Content -LiteralPath $OutFile -Value $xml -Encoding UTF8
|
||||
Write-Host "Wrote $OutFile"
|
||||
Write-Host " PartGroup = $pg"
|
||||
Write-Host " CMMID = $machineCmmId"
|
||||
Write-Host " SelectedVersion = $selVer"
|
||||
Write-Host " ResetProgram = $ResetProgram"
|
||||
Write-Host " ProbeCalProgram = $ProbeCalibrationProgram"
|
||||
Write-Host "NOTE: confirm those .PRG files exist at the paths above (-ResetProgram / -ProbeCalibrationProgram to override)."
|
||||
@@ -0,0 +1,21 @@
|
||||
@echo off
|
||||
REM Ensure-PCDMISFrontEnd.bat - launcher for Ensure-PCDMISFrontEnd.ps1
|
||||
REM
|
||||
REM Creates C:\GE PC-DMIS FRONT END + grants the operator write access, so
|
||||
REM PCDToIGES.exe can write its error log there instead of crashing with
|
||||
REM "Could not find a part of the path 'C:\GE PC-DMIS FRONT END\PCDToIGES.ERR'".
|
||||
REM
|
||||
REM Needs admin - self-elevates.
|
||||
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo Requesting administrator rights...
|
||||
powershell -NoProfile -Command "Start-Process -FilePath '%~f0' -Verb RunAs"
|
||||
exit /b
|
||||
)
|
||||
|
||||
set "HERE=%~dp0"
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%HERE%Ensure-PCDMISFrontEnd.ps1"
|
||||
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,47 @@
|
||||
# Ensure-PCDMISFrontEnd.ps1 - create C:\GE PC-DMIS FRONT END + grant operator write.
|
||||
#
|
||||
# WHY: PCDToIGES.exe (geaofi\Scripts) writes its error log to
|
||||
# C:\GE PC-DMIS FRONT END\PCDToIGES.ERR in its catch block. If that dir does
|
||||
# not exist, ANY PCDToIGES failure becomes an unhandled DirectoryNotFoundException
|
||||
# that CRASHES the export and MASKS the real error (observed on freshly imaged CMM
|
||||
# bays - the legacy "GE PC-DMIS FRONT END" front-end setup is not part of imaging,
|
||||
# so the dir is absent). Creating it + making it operator-writable lets the real
|
||||
# error log instead of crashing, and gives the front-end a working dir.
|
||||
#
|
||||
# Run as administrator. Idempotent - safe to re-run; re-asserts the ACL.
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
$dir = 'C:\GE PC-DMIS FRONT END'
|
||||
|
||||
$logDir = 'C:\Logs\CMM'
|
||||
New-Item -ItemType Directory -Path $logDir -Force -EA SilentlyContinue | Out-Null
|
||||
$ts = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||||
$log = Join-Path $logDir "pcdmis-frontend-$ts.log"
|
||||
function Log($m){ $line = "[{0}] {1}" -f (Get-Date -Format 'HH:mm:ss'), $m; Write-Host $line; Add-Content -Path $log -Value $line -EA SilentlyContinue }
|
||||
|
||||
Log "==== Ensure-PCDMISFrontEnd on $env:COMPUTERNAME ===="
|
||||
|
||||
if (Test-Path -LiteralPath $dir) {
|
||||
Log "Dir already exists: $dir"
|
||||
} else {
|
||||
try { New-Item -ItemType Directory -Path $dir -Force -EA Stop | Out-Null; Log "Created $dir" }
|
||||
catch { Log "ERROR: could not create $dir - $($_.Exception.Message)"; exit 1 }
|
||||
}
|
||||
|
||||
# Operator (locked-down, non-admin) must be able to write PCDToIGES.ERR here.
|
||||
# Modify = read/write/create/delete. SIDs, not names, to stay locale-independent.
|
||||
foreach ($sid in '*S-1-5-32-545','*S-1-5-11') { # BUILTIN\Users, NT AUTHORITY\Authenticated Users
|
||||
& icacls "$dir" /grant "${sid}:(OI)(CI)M" /T /C 2>&1 | Out-Null
|
||||
}
|
||||
Log "Granted Users + Authenticated Users Modify on $dir"
|
||||
|
||||
# Verify an operator-style write works
|
||||
$probe = Join-Path $dir '.write-test'
|
||||
try { Set-Content -LiteralPath $probe -Value 'ok' -EA Stop; Remove-Item -LiteralPath $probe -EA SilentlyContinue; Log "Write-test OK" }
|
||||
catch { Log "WARN: write-test failed - $($_.Exception.Message)" }
|
||||
|
||||
Log "==== DONE ===="
|
||||
Write-Host ""
|
||||
Write-Host "C:\GE PC-DMIS FRONT END ready. Re-run the measurement; if PCDToIGES still" -ForegroundColor Green
|
||||
Write-Host "errors, the real cause now logs to $dir\PCDToIGES.ERR" -ForegroundColor Green
|
||||
exit 0
|
||||
@@ -11,8 +11,10 @@ resolve-cmm-bay-config.ps1 at the WinPE picker):
|
||||
version it ever had (2016.0 + 2019 R2); we restore ONLY the
|
||||
one the bay-config pins, matched by substring (2019 -> the
|
||||
'2019 R2' zip, 2016 -> the '2016.0' zip).
|
||||
doda.txt - 'no' to proceed; anything else SKIPS restore (DODA bays are
|
||||
handled separately and must not get a settings overlay).
|
||||
doda.txt - read for logging only. DODA bays now restore like any other:
|
||||
once they are properly backed up + staged, the config-version
|
||||
zip is restored the same way. (The old skip-on-doda policy was
|
||||
dropped 2026-06-17; DODA bays had no backups when it was added.)
|
||||
partgroup.txt - optional goCMM Selected Part Group (friendly S:\ form), used
|
||||
as the authoritative per-bay override even if the backup is stale.
|
||||
|
||||
@@ -50,7 +52,9 @@ $doda = (ReadTxt 'doda.txt').ToLower()
|
||||
$pgRaw = ReadTxt 'partgroup.txt'
|
||||
|
||||
if (-not $cmmid) { Log "no cmmid.txt (manual CMM id, or not a bay-config bay) - nothing to restore. Skipping."; exit 0 }
|
||||
if ($doda -eq 'yes') { Log "DODA bay ($cmmid) - skipping settings restore by policy."; exit 0 }
|
||||
# DODA bays restore like any other now (skip-on-doda dropped 2026-06-17). DODA
|
||||
# itself installs separately via the manifest to C:\Apps\DODA - independent of
|
||||
# the goCMM (C:\geaofi) + PC-DMIS settings this restore lays back.
|
||||
|
||||
$bdir = Join-Path $BackupRoot $cmmid
|
||||
if (-not (Test-Path -LiteralPath $bdir)) { Log "no staged backup at $bdir - skipping (stage it with sync-cmm-backups.sh)."; exit 0 }
|
||||
|
||||
@@ -4,9 +4,17 @@ REM
|
||||
REM *** RUN THIS AS THE OPERATOR (the locked-down shop-floor user). ***
|
||||
REM *** DO NOT right-click "Run as administrator" - that hides the bug. ***
|
||||
REM
|
||||
REM Reproduces the goCMM "Requested registry access is not allowed" error and
|
||||
REM dumps the goCMM registry key's ACL so we can confirm the lockdown stripped
|
||||
REM the BUILTIN\Users write grant. Output lands in C:\Logs\CMM\.
|
||||
REM Diagnoses goCMM startup failures:
|
||||
REM 1. "Requested registry access is not allowed" - dumps the goCMM key ACL
|
||||
REM to confirm lockdown stripped the BUILTIN\Users write grant (PROBE 1-2).
|
||||
REM 2. "Object reference not set to an instance of an object" at start:
|
||||
REM - PROBE 3: part-group match (reg vs ApplicationSettings.xml, case-sensitive).
|
||||
REM - PROBE 4: pulls the actual .NET crash stack from the Application log.
|
||||
REM - PROBE 5: part-group UNC reachability + PC-DMIS COM registration.
|
||||
REM Confirmed root cause to date: PC-DMIS COM server NOT registered ->
|
||||
REM goCMM's Activator.CreateInstance gets a null type -> NRE. Fix: run
|
||||
REM Pcdlrn.exe once elevated (/regserver). PROBE 5 reports this directly.
|
||||
REM Output lands in C:\Logs\CMM\.
|
||||
|
||||
setlocal
|
||||
set "HERE=%~dp0"
|
||||
|
||||
@@ -93,14 +93,155 @@ W " exported -> $regOut"
|
||||
W ""
|
||||
|
||||
W "================ goCMM version + install ================"
|
||||
# The goCMM MSI installs goCMM.exe (1.1.6718.x) to this dir and points the Start
|
||||
# Menu shortcut at it - goCMM.exe IS the launcher. (An earlier version of this
|
||||
# script checked for GEAOperatorFriendlyInterface.exe, which this product does
|
||||
# NOT install - that produced a false MISSING. Check the real exe.)
|
||||
foreach ($p in @(
|
||||
'C:\Program Files (x86)\General Electric\goCMM\GEAOperatorFriendlyInterface.exe',
|
||||
'C:\Program Files (x86)\General Electric\goCMM\goCMM.exe',
|
||||
'C:\Program Files (x86)\General Electric\goCMM\GEA_OFI_Common.dll')) {
|
||||
if (Test-Path $p) { $vi = (Get-Item $p).VersionInfo; W (" {0} FileVer={1} ProductVer={2}" -f (Split-Path $p -Leaf), $vi.FileVersion, $vi.ProductVersion) }
|
||||
else { W " MISSING: $p" }
|
||||
}
|
||||
W ""
|
||||
|
||||
W "================ PROBE 3: Selected Part Group vs ApplicationSettings.xml (the startup NRE) ================"
|
||||
# goCMM at start matches the registry 'Selected Part Group' against the
|
||||
# <PartGroup FullName> entries in ApplicationSettings.xml with a CASE-SENSITIVE
|
||||
# (Ordinal) compare. No match -> SelectedPartGroup is null -> a startup deref
|
||||
# throws "Object reference not set to an instance of an object". This is a
|
||||
# DIFFERENT failure from the registry SecurityException probed above.
|
||||
# Mismatch forms seen: host (bare vs FQDN) and share segment (\shared vs \SHARED).
|
||||
try {
|
||||
$base32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine','Registry32')
|
||||
$kpg = $base32.OpenSubKey($key32native, $false)
|
||||
$regPg = $null; $sharedDir = 'C:\geaofi'
|
||||
if ($kpg) {
|
||||
$regPg = [string]$kpg.GetValue('Selected Part Group','')
|
||||
$sd = [string]$kpg.GetValue('Shared Data Directory','')
|
||||
if ($sd) { $sharedDir = $sd.TrimEnd('\') }
|
||||
$kpg.Close()
|
||||
}
|
||||
W (" reg 'Selected Part Group' = [{0}]" -f $regPg)
|
||||
W (" Shared Data Directory = {0}" -f $sharedDir)
|
||||
|
||||
$xml = Join-Path $sharedDir 'ApplicationSettings.xml'
|
||||
if (-not (Test-Path $xml)) {
|
||||
W " *** ApplicationSettings.xml NOT FOUND at $xml - no part groups to match -> null SelectedPartGroup -> NRE likely. <<"
|
||||
} else {
|
||||
$txt = [System.IO.File]::ReadAllText($xml)
|
||||
# Capture FullName in both attribute (FullName="...") and element (<FullName>...</FullName>) forms.
|
||||
$names = New-Object System.Collections.Generic.List[string]
|
||||
foreach ($m in [regex]::Matches($txt, 'FullName\s*=\s*"([^"]*)"')) { $names.Add($m.Groups[1].Value) }
|
||||
foreach ($m in [regex]::Matches($txt, '<FullName>([^<]*)</FullName>')) { $names.Add($m.Groups[1].Value) }
|
||||
$names = $names | Select-Object -Unique
|
||||
W (" ApplicationSettings.xml part-group FullName entries ({0}):" -f @($names).Count)
|
||||
foreach ($n in $names) { W (" [{0}]" -f $n) }
|
||||
|
||||
if (-not $regPg) {
|
||||
W " >> reg 'Selected Part Group' is EMPTY - goCMM has no part group pinned -> null -> NRE likely. <<"
|
||||
} else {
|
||||
$exact = $false; $caseOnly = $false
|
||||
foreach ($n in $names) {
|
||||
if ([string]::Equals($n, $regPg, [StringComparison]::Ordinal)) { $exact = $true; break }
|
||||
if ([string]::Equals($n, $regPg, [StringComparison]::OrdinalIgnoreCase)) { $caseOnly = $true }
|
||||
}
|
||||
if ($exact) {
|
||||
W " >> MATCH: reg value matches an XML FullName exactly (case-sensitive). Part group is NOT the NRE cause. <<"
|
||||
} elseif ($caseOnly) {
|
||||
W " >> *** CASE-ONLY MATCH *** reg value matches an XML entry only when case is ignored."
|
||||
W " >> goCMM's compare is case-sensitive -> Find returns null -> SelectedPartGroup null -> NRE. <<"
|
||||
W " >> FIX: re-run Install-goCMMSettings.ps1 (>= commit d441abd canonicalizes host + \SHARED case). <<"
|
||||
} else {
|
||||
W " >> *** NO MATCH *** reg 'Selected Part Group' is absent from ApplicationSettings.xml (any case)."
|
||||
W " >> Find returns null -> SelectedPartGroup null -> NRE. Wrong per-bay override, or XML from a different bay. <<"
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch { W " ERROR in part-group probe: $($_.Exception.Message)" }
|
||||
W ""
|
||||
|
||||
W "================ PROBE 4: goCMM crash events (Application log) - the actual stack ================"
|
||||
# The NRE reproduces even for admin, so it is NOT a rights problem. The faulting
|
||||
# stack names the null object. .NET pushes it to the Application log under
|
||||
# '.NET Runtime' / 'Application Error' / 'Windows Error Reporting'.
|
||||
try {
|
||||
$since = (Get-Date).AddDays(-14)
|
||||
$ev = Get-WinEvent -FilterHashtable @{ LogName='Application'; StartTime=$since } -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.ProviderName -match '\.NET Runtime|Application Error|Windows Error Reporting|Application Hang' -and "$($_.Message)" -match 'goCMM' }
|
||||
if (-not $ev) {
|
||||
W " (no goCMM-related crash events in the last 14 days - launch goCMM once, then re-run this)"
|
||||
} else {
|
||||
foreach ($e in ($ev | Select-Object -First 5)) {
|
||||
W (" ---- {0} [{1}] EventId={2} ----" -f $e.TimeCreated, $e.ProviderName, $e.Id)
|
||||
foreach ($line in ("$($e.Message)" -split "`r?`n")) { W (" " + $line) }
|
||||
W ""
|
||||
}
|
||||
W " >> The topmost goCMM / GEA_OFI frame in the stack above is where the null is dereferenced. <<"
|
||||
}
|
||||
} catch { W " ERROR reading event log: $($_.Exception.Message)" }
|
||||
W ""
|
||||
|
||||
W "================ PROBE 5: part-group UNC reachability + PC-DMIS install ================"
|
||||
# (a) Can THIS bay open the Selected Part Group share? An unreachable / unauthenticated
|
||||
# UNC -> goCMM enumerates null -> startup NRE, regardless of local rights (admin too).
|
||||
try {
|
||||
$base32 = [Microsoft.Win32.RegistryKey]::OpenBaseKey('LocalMachine','Registry32')
|
||||
$kpg = $base32.OpenSubKey($key32native, $false)
|
||||
$pg = if ($kpg) { [string]$kpg.GetValue('Selected Part Group','') } else { '' }
|
||||
if ($kpg) { $kpg.Close() }
|
||||
if ($pg) {
|
||||
W (" part group UNC: $pg")
|
||||
if (Test-Path -LiteralPath $pg -ErrorAction SilentlyContinue) {
|
||||
$n = @(Get-ChildItem -LiteralPath $pg -ErrorAction SilentlyContinue).Count
|
||||
W (" >> REACHABLE - $n item(s) under it. (not the NRE cause) <<")
|
||||
} else {
|
||||
W " >> *** UNREACHABLE *** bay cannot open the part-group UNC (share offline, not on the"
|
||||
W " >> production net yet, or no credential to \\tsgwp00525\SHARED). goCMM enumerating this"
|
||||
W " >> path returns null -> startup NRE even for admin. Check net connectivity + share auth. <<"
|
||||
}
|
||||
} else { W " (no Selected Part Group in registry)" }
|
||||
} catch { W " ERROR testing part-group UNC: $($_.Exception.Message)" }
|
||||
W ""
|
||||
# (b) PC-DMIS COM automation - THE confirmed root cause (see debug.log). goCMM
|
||||
# connects via Activator.CreateInstance on the PC-DMIS COM type. If the
|
||||
# automation server is not registered, Type.GetTypeFromProgID returns null
|
||||
# -> CreateInstance(null) -> "ArgumentNullException: ... Parameter name: type"
|
||||
# -> ConnectToSoftware derefs null -> NRE. PC-DMIS can be RUNNING and still
|
||||
# not be COM-registered. Stack: GEAE.Common.CMM.CMMInterfaces.PCDMIS.ConnectToSoftware.
|
||||
$comOk = $false
|
||||
foreach ($pgid in 'PCDLRN.Application','PCDLRN.Automation','Pcdlrn.Application','PCDLRN.Object') {
|
||||
foreach ($cls in "HKLM:\SOFTWARE\Classes\$pgid","HKLM:\SOFTWARE\Classes\WOW6432Node\$pgid") {
|
||||
if (Test-Path $cls) {
|
||||
$clsid = (Get-ItemProperty -Path "$cls\CLSID" -ErrorAction SilentlyContinue).'(default)'
|
||||
$comOk = $true
|
||||
$srv = $null
|
||||
if ($clsid) {
|
||||
foreach ($cb in "HKLM:\SOFTWARE\Classes\CLSID\$clsid\LocalServer32","HKLM:\SOFTWARE\Classes\WOW6432Node\CLSID\$clsid\LocalServer32") {
|
||||
if (Test-Path $cb) { $srv = (Get-ItemProperty -Path $cb -EA SilentlyContinue).'(default)' }
|
||||
}
|
||||
}
|
||||
W (" COM ProgID registered: $pgid CLSID=$clsid server=$srv")
|
||||
}
|
||||
}
|
||||
}
|
||||
if (-not $comOk) {
|
||||
W " >> *** PC-DMIS COM SERVER NOT REGISTERED *** no PCDLRN.* ProgID in HKCR. This is exactly the"
|
||||
W " >> null behind 'ArgumentNullException: ... Parameter name: type' in debug.log -> goCMM startup NRE."
|
||||
W " >> FIX: run the installed Pcdlrn.exe once ELEVATED (self-registers), or 'Pcdlrn.exe /regserver'."
|
||||
W " >> Then confirm the registered build matches the goCMM-expected PC-DMIS version (the version gate). <<"
|
||||
}
|
||||
# install presence (context for the COM verdict)
|
||||
$pcdlrn = $null
|
||||
foreach ($d in 'C:\Program Files\Hexagon','C:\Program Files (x86)\Hexagon','C:\Program Files\WAI','C:\Program Files (x86)\WAI') {
|
||||
if (Test-Path $d) {
|
||||
$hit = Get-ChildItem $d -Filter 'Pcdlrn.exe' -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($hit) { $pcdlrn = $hit.FullName; W (" Pcdlrn.exe: $($hit.FullName) v$((Get-Item $hit.FullName).VersionInfo.FileVersion)"); break }
|
||||
}
|
||||
}
|
||||
if (-not $pcdlrn) { W " Pcdlrn.exe NOT found in standard dirs - PC-DMIS not installed where expected." }
|
||||
W ""
|
||||
|
||||
W "================ UAC / registry virtualization ================"
|
||||
(reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableLUA 2>&1 | Out-String) | W
|
||||
(reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" /v EnableVirtualization 2>&1 | Out-String) | W
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
@echo off
|
||||
REM ==========================================================================
|
||||
REM Diagnose-eDNCDetection.bat - diagnose the eDNC 6.4.5 enforce loop (MSI
|
||||
REM 1603 "same or newer already installed" every 5 minutes).
|
||||
REM
|
||||
REM Usage (run on the problem PC):
|
||||
REM Diagnose-eDNCDetection.bat auto-find manifest (W: or UNC)
|
||||
REM Diagnose-eDNCDetection.bat /manifest <path> explicit manifest.json path
|
||||
REM
|
||||
REM Read-only: no installs, no share writes.
|
||||
REM ==========================================================================
|
||||
setlocal EnableDelayedExpansion
|
||||
|
||||
REM --- self-elevate ---
|
||||
net session >nul 2>&1
|
||||
if %errorlevel% neq 0 (
|
||||
echo Requesting administrator elevation...
|
||||
powershell -NoProfile -Command "Start-Process -Verb RunAs -FilePath '%~f0' -ArgumentList '%*'"
|
||||
exit /b
|
||||
)
|
||||
|
||||
set "PS=%~dp0Diagnose-eDNCDetection.ps1"
|
||||
set "ARGS="
|
||||
|
||||
:parse
|
||||
if "%~1"=="" goto run
|
||||
if /I "%~1"=="/manifest" set "ARGS=!ARGS! -ManifestPath '%~2'" & shift & shift & goto parse
|
||||
shift
|
||||
goto parse
|
||||
|
||||
:run
|
||||
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%PS%" !ARGS!
|
||||
echo.
|
||||
pause
|
||||
endlocal
|
||||
@@ -0,0 +1,232 @@
|
||||
<#
|
||||
Diagnose-eDNCDetection.ps1
|
||||
|
||||
One-shot diagnosis of the eDNC 6.4.5 enforce loop: GE-Enforce re-runs
|
||||
eDNC_6-4-5.msi every 5 minutes, the MSI aborts 1603 with "The same or newer
|
||||
version of this software is already installed", and InUseCheck kills DncMain
|
||||
in the process. Root cause is the manifest entry's Detection* fields not
|
||||
matching what is actually installed.
|
||||
|
||||
Runs the whole triage and prints a verdict:
|
||||
|
||||
1. Installed state - DncMain.exe / NTLARS.exe file versions, x86+x64
|
||||
uninstall registry entries for eDNC (DisplayVersion,
|
||||
ProductCode).
|
||||
2. Manifest entry - the live "eDNC (bundles NTLARS)" entry from the SFLD
|
||||
share manifest (uses W: if enforce has it mounted,
|
||||
else direct UNC, else -ManifestPath).
|
||||
3. Comparison - replays Install-FromManifest's Test-AppInstalled
|
||||
logic against the entry and says WHY it misses.
|
||||
4. Verdict - suggested corrected manifest JSON.
|
||||
|
||||
Read-only: no installs, no share writes. Run as administrator on the
|
||||
problem PC (registry + share read).
|
||||
|
||||
Params:
|
||||
-ManifestPath explicit path to the collections manifest.json (skips
|
||||
W:/UNC auto-discovery)
|
||||
#>
|
||||
param(
|
||||
[string]$ManifestPath
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Continue'
|
||||
function Section($t){ Write-Host ''; Write-Host ("==== {0} ====" -f $t) -ForegroundColor Cyan }
|
||||
function KV($k,$v){ Write-Host (" {0,-24}: {1}" -f $k, $v) }
|
||||
|
||||
Write-Host '########################################################'
|
||||
Write-Host '# eDNC Detection Loop Diagnosis'
|
||||
Write-Host ("# {0} host {1}" -f (Get-Date -Format 'yyyy-MM-dd HH:mm:ss'), [System.Environment]::MachineName)
|
||||
Write-Host '########################################################'
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1. Installed state
|
||||
# ---------------------------------------------------------------------------
|
||||
Section '1. Installed eDNC state on this PC'
|
||||
|
||||
$dncMain = 'C:\Program Files (x86)\Dnc\bin\DncMain.exe'
|
||||
$ntlars = 'C:\Program Files (x86)\Dnc\Common\NTLARS.exe'
|
||||
$dncMainVer = ''
|
||||
$ntlarsVer = ''
|
||||
|
||||
if (Test-Path $dncMain) {
|
||||
$dncMainVer = (Get-Item $dncMain).VersionInfo.FileVersion
|
||||
KV 'DncMain.exe' ("present, FileVersion {0}" -f $dncMainVer)
|
||||
} else {
|
||||
KV 'DncMain.exe' 'MISSING'
|
||||
}
|
||||
if (Test-Path $ntlars) {
|
||||
$ntlarsVer = (Get-Item $ntlars).VersionInfo.FileVersion
|
||||
KV 'NTLARS.exe' ("present, FileVersion {0}" -f $ntlarsVer)
|
||||
} else {
|
||||
KV 'NTLARS.exe' 'MISSING'
|
||||
}
|
||||
|
||||
# Uninstall entries - both registry views. Win32_Product deliberately avoided
|
||||
# (it triggers MSI self-repair on enumeration).
|
||||
$uninstallRoots = @(
|
||||
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*',
|
||||
'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*'
|
||||
)
|
||||
$edncProducts = @()
|
||||
foreach ($root in $uninstallRoots) {
|
||||
$edncProducts += Get-ItemProperty -Path $root -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.DisplayName -like '*eDNC*' -or $_.DisplayName -like '*DNC*Client*' }
|
||||
}
|
||||
if ($edncProducts) {
|
||||
foreach ($p in $edncProducts) {
|
||||
Write-Host ''
|
||||
KV 'DisplayName' $p.DisplayName
|
||||
KV 'DisplayVersion' $p.DisplayVersion
|
||||
KV 'ProductCode' $p.PSChildName
|
||||
KV 'InstallDate' $p.InstallDate
|
||||
KV 'RegistryView' ($(if ($p.PSPath -like '*WOW6432Node*') { 'x86 (WOW6432Node)' } else { 'x64' }))
|
||||
}
|
||||
} else {
|
||||
Write-Host ' No eDNC uninstall entry found in either registry view.' -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2. Manifest entry from the share
|
||||
# ---------------------------------------------------------------------------
|
||||
Section '2. Manifest entry (share)'
|
||||
|
||||
$candidates = @()
|
||||
if ($ManifestPath) { $candidates += $ManifestPath }
|
||||
$candidates += 'W:\gea-shopfloor-collections\manifest.json'
|
||||
$candidates += '\\tsgwp00525.wjs.geaerospace.net\shared\dt\shopfloor\gea-shopfloor-collections\manifest.json'
|
||||
|
||||
$manifestFile = $null
|
||||
foreach ($c in $candidates) {
|
||||
if (Test-Path $c) { $manifestFile = $c; break }
|
||||
}
|
||||
|
||||
$entry = $null
|
||||
if ($manifestFile) {
|
||||
KV 'Manifest' $manifestFile
|
||||
try {
|
||||
$manifest = Get-Content -LiteralPath $manifestFile -Raw | ConvertFrom-Json
|
||||
$entry = $manifest.Applications | Where-Object { $_.Name -like 'eDNC*' } | Select-Object -First 1
|
||||
} catch {
|
||||
Write-Host (" Failed to parse manifest: {0}" -f $_) -ForegroundColor Red
|
||||
}
|
||||
if ($entry) {
|
||||
KV 'Name' $entry.Name
|
||||
KV 'Installer' $entry.Installer
|
||||
KV 'Type' $entry.Type
|
||||
KV 'InstallArgs' $entry.InstallArgs
|
||||
KV 'DetectionMethod' $entry.DetectionMethod
|
||||
KV 'DetectionPath' $entry.DetectionPath
|
||||
KV 'DetectionName' $entry.DetectionName
|
||||
KV 'DetectionValue' $entry.DetectionValue
|
||||
} else {
|
||||
Write-Host ' No eDNC* entry found in manifest Applications.' -ForegroundColor Yellow
|
||||
}
|
||||
} else {
|
||||
Write-Host ' Manifest not reachable (no W: mount, UNC denied).' -ForegroundColor Yellow
|
||||
Write-Host ' Re-run with -ManifestPath, or run while GE-Enforce has W: mounted.'
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3. Replay Test-AppInstalled against the entry
|
||||
# ---------------------------------------------------------------------------
|
||||
Section '3. Detection replay'
|
||||
|
||||
$detected = $null
|
||||
$missReason = ''
|
||||
if ($entry) {
|
||||
switch ($entry.DetectionMethod) {
|
||||
'File' {
|
||||
$detected = Test-Path $entry.DetectionPath
|
||||
if (-not $detected) { $missReason = "DetectionPath does not exist: $($entry.DetectionPath)" }
|
||||
}
|
||||
'FileVersion' {
|
||||
if (-not (Test-Path $entry.DetectionPath)) {
|
||||
$detected = $false
|
||||
$missReason = "DetectionPath does not exist: $($entry.DetectionPath)"
|
||||
} elseif (-not $entry.DetectionValue) {
|
||||
$detected = $false
|
||||
$missReason = 'FileVersion detection with no DetectionValue always misses'
|
||||
} else {
|
||||
$actual = (Get-Item $entry.DetectionPath -ErrorAction SilentlyContinue).VersionInfo.FileVersion
|
||||
$detected = ($actual -eq $entry.DetectionValue)
|
||||
if (-not $detected) {
|
||||
$missReason = "exact-match compare failed: actual '$actual' vs DetectionValue '$($entry.DetectionValue)'"
|
||||
}
|
||||
}
|
||||
}
|
||||
'Registry' {
|
||||
if (-not (Test-Path $entry.DetectionPath)) {
|
||||
$detected = $false
|
||||
$missReason = "registry key does not exist: $($entry.DetectionPath) (eDNC uninstall key path varies across 6.x releases)"
|
||||
} elseif ($entry.DetectionName) {
|
||||
$v = Get-ItemProperty -Path $entry.DetectionPath -Name $entry.DetectionName -ErrorAction SilentlyContinue
|
||||
if (-not $v) {
|
||||
$detected = $false
|
||||
$missReason = "value '$($entry.DetectionName)' missing under $($entry.DetectionPath)"
|
||||
} elseif ($entry.DetectionValue) {
|
||||
$actual = $v.$($entry.DetectionName)
|
||||
$detected = ("$actual" -eq "$($entry.DetectionValue)")
|
||||
if (-not $detected) {
|
||||
$missReason = "exact-match compare failed: actual '$actual' vs DetectionValue '$($entry.DetectionValue)'"
|
||||
}
|
||||
} else {
|
||||
$detected = $true
|
||||
}
|
||||
} else {
|
||||
$detected = $true
|
||||
}
|
||||
}
|
||||
default {
|
||||
$missReason = "detection method '$($entry.DetectionMethod)' not replayed by this script"
|
||||
}
|
||||
}
|
||||
if ($null -ne $detected) {
|
||||
KV 'Test-AppInstalled' ($(if ($detected) { 'TRUE (would skip install)' } else { 'FALSE (re-runs MSI every cycle)' }))
|
||||
if ($missReason) { KV 'Miss reason' $missReason }
|
||||
}
|
||||
} else {
|
||||
Write-Host ' Skipped - no manifest entry available to replay.'
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4. Verdict
|
||||
# ---------------------------------------------------------------------------
|
||||
Section '4. Verdict'
|
||||
|
||||
$edncInstalled = ($edncProducts.Count -gt 0) -or (Test-Path $dncMain)
|
||||
|
||||
if (-not $edncInstalled) {
|
||||
Write-Host ' eDNC does NOT appear installed. The 1603 "same or newer" abort'
|
||||
Write-Host ' then points at a stale MSI registration; check the upgrade-code'
|
||||
Write-Host ' products under HKLM:\SOFTWARE\Classes\Installer\UpgradeCodes.'
|
||||
} elseif ($detected -eq $true) {
|
||||
Write-Host ' Detection passes now. If enforce still loops, the manifest on the'
|
||||
Write-Host ' share differs from the one inspected here - confirm the path.'
|
||||
} else {
|
||||
Write-Host ' eDNC IS installed but the manifest entry does not detect it, so'
|
||||
Write-Host ' GE-Enforce re-runs the MSI every cycle and the MSI aborts 1603'
|
||||
Write-Host ' ("same or newer already installed"). Fix the manifest entry on'
|
||||
Write-Host ' the share. Suggested replacement (File detection on NTLARS.exe,'
|
||||
Write-Host ' same approach as the working 6.4.3 machineapps entry):'
|
||||
Write-Host ''
|
||||
$suggested = [ordered]@{
|
||||
Name = 'eDNC (bundles NTLARS)'
|
||||
Installer = 'apps\eDNC_6-4-5.msi'
|
||||
Type = 'MSI'
|
||||
InstallArgs = '/qn /norestart ALLUSERS=1 REBOOT=ReallySuppress SITESELECTED="West Jefferson"'
|
||||
DetectionMethod = 'File'
|
||||
DetectionPath = 'C:\Program Files (x86)\Dnc\Common\NTLARS.exe'
|
||||
} | ConvertTo-Json
|
||||
Write-Host $suggested
|
||||
Write-Host ''
|
||||
if ($edncProducts) {
|
||||
$dv = ($edncProducts | Select-Object -First 1).DisplayVersion
|
||||
Write-Host (" Alternative: keep Registry detection but set DetectionValue to the")
|
||||
Write-Host (" actual installed DisplayVersion: '{0}'" -f $dv)
|
||||
}
|
||||
Write-Host ' Until the manifest is fixed, every enforce cycle also risks killing'
|
||||
Write-Host ' a live DncMain session (InUseCheck force-kill before the doomed MSI).'
|
||||
}
|
||||
|
||||
Write-Host ''
|
||||
@@ -1,21 +1,28 @@
|
||||
# Report-AssetToShopDB.ps1
|
||||
#
|
||||
# Reports a collections bay's identity to ShopDB so the machines record stays
|
||||
# current with whatever the bay actually is right now: hostname, BIOS serial,
|
||||
# DNC machine number (2001, 2002, ...) and its corp/AESFMA IPv4 address.
|
||||
# Reports a PC's identity to ShopDB so the machines record stays current with
|
||||
# whatever the PC actually is right now: hostname, BIOS serial, pc-type, logged-
|
||||
# in user, DNC machine number (2001, 2002, ... when present) and its corp/AESFMA
|
||||
# IPv4 address.
|
||||
#
|
||||
# Deployed in common\ (runs on EVERY shopfloor pc-type: collections, cmm,
|
||||
# keyence, waxtrace, genspect, heattreat, partmarker, nocollections, ...), not
|
||||
# collections-only. Non-DNC bays (cmm/keyence/waxtrace) simply report identity
|
||||
# with no machineNo, so no PC-to-machine relationship is built - by design.
|
||||
#
|
||||
# Runs every GE-Enforce cycle as a Type=PS1 manifest entry (DetectionMethod
|
||||
# Always) under the SYSTEM scheduled task. Idempotent on the server side:
|
||||
# ShopDB api.asp action=updateCompleteAsset upserts the machines row keyed by
|
||||
# hostname, clears+reinserts the interface rows, and (re)creates the
|
||||
# PC-to-machine relationship from machineNo. Safe to fire repeatedly.
|
||||
# hostname (patch-style: only the fields posted here are updated, so it never
|
||||
# clobbers model/VNC/WinRM), clears+reinserts the interface rows, and (re)creates
|
||||
# the PC-to-machine relationship from machineNo. Safe to fire repeatedly.
|
||||
#
|
||||
# WHY collections-only and corp-NIC-only:
|
||||
# Collections (controller-NIC) bays carry two NICs - a private controller
|
||||
# NIC (e.g. 192.168.x / 10.x stray) and the routable corp/AESFMA NIC. Only
|
||||
# the corp NIC belongs in ShopDB, so we filter to the WJ corp ranges and
|
||||
# drop everything else. Mirrors the allowed-range gate in
|
||||
# Invoke-FilteredReportIP.ps1.
|
||||
# WHY corp-NIC-only:
|
||||
# Some bays (collections/controller) carry two NICs - a private controller NIC
|
||||
# (e.g. 192.168.x / 10.x stray) and the routable corp/AESFMA NIC. Only the corp
|
||||
# NIC belongs in ShopDB, so we filter to the WJ corp ranges and drop the rest.
|
||||
# Single-NIC PCs just pass their one corp IP through the same gate. Mirrors the
|
||||
# allowed-range gate in Invoke-FilteredReportIP.ps1.
|
||||
#
|
||||
# Always exits 0 so the GE-Enforce "last run result" stays clean; failures are
|
||||
# logged, never thrown.
|
||||
@@ -83,15 +90,17 @@ if (-not $serialNumber) {
|
||||
exit 0
|
||||
}
|
||||
|
||||
# DNC machine number (2001, 2002, ...). optional - sent only if found.
|
||||
# Resolution order mirrors the GE-Enforce lib Get-CurrentMachineNumber so the
|
||||
# reporter and manifest gating agree:
|
||||
# 1. eDNC registry (WOW6432Node, then native) - follows bay reassignment, which
|
||||
# Set-MachineNumber rewrites here.
|
||||
# 2. C:\Enrollment\machine-number.txt - the imaging-time value written once by
|
||||
# startnet.cmd. Used when eDNC has not populated the registry yet (fresh
|
||||
# image, or a bay where eDNC has not run), so the PC still reports its number
|
||||
# and api.asp can build the relationship.
|
||||
# Machine identifier - optional, sent only if found. api.asp matches it against
|
||||
# the equipment machinenumber OR alias column, so one value covers every type:
|
||||
# 1. eDNC registry (WOW6432Node, then native) - DNC/collections bays (2001...).
|
||||
# Follows bay reassignment, which Set-MachineNumber rewrites here.
|
||||
# 2. C:\Enrollment\cmm\cmmid.txt - CMM bay id (e.g. CMM3), written by
|
||||
# select-cmm-bay.ps1 at imaging. Matches the equipment machinenumber.
|
||||
# 3. C:\Enrollment\machine-number.txt - imaging value. For wax&trace this is the
|
||||
# asset tag from select-waxtrace-asset.ps1 (matches the equipment alias);
|
||||
# for DNC bays it is the digit number. 9999 is the placeholder = skip.
|
||||
# keyence / genspect / part-marker have no per-bay id on the PC -> no machineNo
|
||||
# is sent and the link is assigned manually in ShopDB.
|
||||
$machineNo = ''
|
||||
foreach ($regPath in @(
|
||||
'HKLM:\SOFTWARE\WOW6432Node\GE Aircraft Engines\DNC\General',
|
||||
@@ -101,43 +110,115 @@ foreach ($regPath in @(
|
||||
try {
|
||||
if (Test-Path $regPath) {
|
||||
$v = [string](Get-ItemProperty -Path $regPath -Name MachineNo -ErrorAction Stop).MachineNo
|
||||
if ($v) { $machineNo = $v.Trim() }
|
||||
if ($v -and $v.Trim() -ne '9999') { $machineNo = $v.Trim() }
|
||||
}
|
||||
} catch {
|
||||
Log "WARN could not read MachineNo from ${regPath}: $($_.Exception.Message)"
|
||||
}
|
||||
}
|
||||
if (-not $machineNo) {
|
||||
$cmmFile = 'C:\Enrollment\cmm\cmmid.txt'
|
||||
if (Test-Path -LiteralPath $cmmFile) {
|
||||
try {
|
||||
$v = ([string](Get-Content -LiteralPath $cmmFile -First 1 -ErrorAction Stop)).Trim()
|
||||
if ($v -and $v -ne '9999') { $machineNo = $v; Log "machineNo from $cmmFile (CMM bay id): $machineNo" }
|
||||
} catch { Log "WARN could not read ${cmmFile}: $($_.Exception.Message)" }
|
||||
}
|
||||
}
|
||||
if (-not $machineNo) {
|
||||
$mnFile = 'C:\Enrollment\machine-number.txt'
|
||||
if (Test-Path -LiteralPath $mnFile) {
|
||||
try {
|
||||
$v = Get-Content -LiteralPath $mnFile -First 1 -ErrorAction Stop
|
||||
if ($v) { $machineNo = ([string]$v).Trim(); Log "machineNo from $mnFile (eDNC registry empty): $machineNo" }
|
||||
$v = ([string](Get-Content -LiteralPath $mnFile -First 1 -ErrorAction Stop)).Trim()
|
||||
if ($v -and $v -ne '9999') { $machineNo = $v; Log "machineNo from $mnFile (imaging value): $machineNo" }
|
||||
} catch { Log "WARN could not read ${mnFile}: $($_.Exception.Message)" }
|
||||
}
|
||||
}
|
||||
|
||||
# OS caption for the operatingsystems lookup.
|
||||
# OS for the operatingsystems lookup: caption + feature-update (e.g. 23H2, read
|
||||
# from the registry since WMI does not expose it) + major build number. Yields a
|
||||
# string like "Microsoft Windows 11 Enterprise 23H2 (build 22631)" so the fleet
|
||||
# OS-version breakdown is visible everywhere osid is shown - no schema change,
|
||||
# api.asp upserts each distinct string into operatingsystems.
|
||||
$osVersion = ''
|
||||
# last boot time - api.asp stores it as machines.lastboottime; uptime is derived
|
||||
# server-side (DATEDIFF(NOW(), lastboottime)). MySQL datetime format.
|
||||
$lastBootTime = ''
|
||||
try {
|
||||
$osVersion = (Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop).Caption
|
||||
if ($osVersion) { $osVersion = $osVersion.Trim() }
|
||||
$os = Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop
|
||||
$osVersion = "$($os.Caption)".Trim()
|
||||
$displayVersion = ''
|
||||
try {
|
||||
$displayVersion = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name DisplayVersion -ErrorAction Stop).DisplayVersion
|
||||
} catch {}
|
||||
if ($displayVersion) { $osVersion += " $displayVersion" }
|
||||
if ($os.BuildNumber) { $osVersion += " (build $($os.BuildNumber))" }
|
||||
$osVersion = $osVersion.Trim()
|
||||
try { $lastBootTime = $os.LastBootUpTime.ToString('yyyy-MM-dd HH:mm:ss') } catch {}
|
||||
} catch {}
|
||||
|
||||
# gather corp NICs only. one networkInterfaces entry per allowed IPv4.
|
||||
# interactive console user (DOMAIN\user). this script runs as SYSTEM so we
|
||||
# cannot use $env:USERNAME; Win32_ComputerSystem.UserName is the console
|
||||
# session owner and works from SYSTEM context. empty when nobody is logged on,
|
||||
# in which case we omit it from the post so an unattended bay does not blank
|
||||
# the last-known user on the server.
|
||||
$loggedInUser = ''
|
||||
try {
|
||||
$loggedInUser = (Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop).UserName
|
||||
# Win32 returns COMPUTERNAME\user (local account) or DOMAIN\user. Keep only
|
||||
# the username part: matches the legacy bare-username convention and avoids
|
||||
# the backslash, which the inline api.asp SQL does not escape so MySQL eats
|
||||
# it (FB90238\ShopFloor was being stored as FB90238ShopFloor).
|
||||
if ($loggedInUser) { $loggedInUser = ($loggedInUser -split '\\')[-1].Trim() }
|
||||
} catch {
|
||||
Log "WARN could not read logged-in user: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
# imaging pc-type (gea-shopfloor-*), read from the enrollment file written at
|
||||
# image time. api.asp maps both the gea-shopfloor-* values and the legacy
|
||||
# display strings to the right pctypeid. Sent only when present; when absent the
|
||||
# server's patch-style update leaves the existing pctype untouched (so a bare
|
||||
# report never re-types a PC). This is what lets the reporter run fleet-wide
|
||||
# from common\ instead of collections-only.
|
||||
$pcType = ''
|
||||
$ptFile = 'C:\Enrollment\pc-type.txt'
|
||||
if (Test-Path -LiteralPath $ptFile) {
|
||||
try {
|
||||
$pcType = (Get-Content -LiteralPath $ptFile -First 1 -ErrorAction Stop).Trim()
|
||||
} catch { Log "WARN could not read ${ptFile}: $($_.Exception.Message)" }
|
||||
}
|
||||
|
||||
# PC make/model from WMI (e.g. "Dell Inc." / "OptiPlex 7090"). api.asp resolves
|
||||
# or creates the vendor + model rows and links modelnumberid. Sent only when
|
||||
# present so a WMI read failure does not blank the model on the row.
|
||||
$manufacturer = ''
|
||||
$model = ''
|
||||
try {
|
||||
$cs = Get-CimInstance -ClassName Win32_ComputerSystem -ErrorAction Stop
|
||||
$manufacturer = "$($cs.Manufacturer)".Trim()
|
||||
$model = "$($cs.Model)".Trim()
|
||||
} catch {
|
||||
Log "WARN could not read make/model: $($_.Exception.Message)"
|
||||
}
|
||||
|
||||
# gather IPv4 NICs - BOTH the corp/AESFMA NIC and the controller/machine LAN NIC,
|
||||
# each with its MAC. Physical adapters only (drop Hyper-V/VPN/WSL/virtual plus
|
||||
# link-local 169.254 and loopback). Each NIC is tagged IsMachineNetwork: true for
|
||||
# the controller LAN (any IP outside the corp ranges), false for the corp NIC.
|
||||
$interfaces = @()
|
||||
try {
|
||||
$ipObjs = Get-NetIPAddress -AddressFamily IPv4 -ErrorAction Stop |
|
||||
Where-Object { $_.IPAddress -notmatch '^169\.254' -and $_.IPAddress -ne '127.0.0.1' }
|
||||
foreach ($ipo in $ipObjs) {
|
||||
if (-not (Test-InAllowedRange $ipo.IPAddress)) { continue }
|
||||
$adapter = $null
|
||||
try { $adapter = Get-NetAdapter -InterfaceIndex $ipo.InterfaceIndex -ErrorAction Stop } catch {}
|
||||
# physical + connected only; skip virtual adapters (Hyper-V/VPN/WSL/etc)
|
||||
if (-not $adapter) { continue }
|
||||
if (-not $adapter.HardwareInterface) { continue }
|
||||
if ($adapter.Status -ne 'Up') { continue }
|
||||
|
||||
$mac = ''
|
||||
$mac = $adapter.MacAddress
|
||||
$gw = ''
|
||||
try {
|
||||
$adapter = Get-NetAdapter -InterfaceIndex $ipo.InterfaceIndex -ErrorAction Stop
|
||||
$mac = $adapter.MacAddress
|
||||
} catch {}
|
||||
try {
|
||||
$gw = (Get-NetRoute -InterfaceIndex $ipo.InterfaceIndex -DestinationPrefix '0.0.0.0/0' -ErrorAction Stop |
|
||||
Select-Object -First 1).NextHop
|
||||
@@ -149,13 +230,15 @@ try {
|
||||
[Array]::Reverse($maskBytes)
|
||||
$subnetMask = ($maskBytes | ForEach-Object { $_ }) -join '.'
|
||||
|
||||
$isCorp = Test-InAllowedRange $ipo.IPAddress
|
||||
|
||||
$interfaces += [pscustomobject]@{
|
||||
IPAddress = $ipo.IPAddress
|
||||
MACAddress = $mac
|
||||
SubnetMask = $subnetMask
|
||||
DefaultGateway = $gw
|
||||
InterfaceName = $ipo.InterfaceAlias
|
||||
IsMachineNetwork = $false # corp NIC, not the controller LAN
|
||||
IsMachineNetwork = (-not $isCorp) # controller/machine LAN = true; corp = false
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
@@ -163,7 +246,7 @@ try {
|
||||
}
|
||||
|
||||
if ($interfaces.Count -eq 0) {
|
||||
Log 'WARN no corp-range IPv4 found; posting identity without interfaces.'
|
||||
Log 'WARN no physical IPv4 NIC found; posting identity without interfaces.'
|
||||
}
|
||||
|
||||
$networkInterfacesJson = if ($interfaces.Count -gt 0) { $interfaces | ConvertTo-Json -Compress -Depth 4 } else { '' }
|
||||
@@ -174,14 +257,18 @@ $body = @{
|
||||
action = 'updateCompleteAsset'
|
||||
hostname = $hostname
|
||||
serialNumber = $serialNumber
|
||||
pcType = 'Shopfloor'
|
||||
osVersion = $osVersion
|
||||
networkInterfaces = $networkInterfacesJson
|
||||
}
|
||||
if ($machineNo) { $body['machineNo'] = $machineNo }
|
||||
if ($machineNo) { $body['machineNo'] = $machineNo }
|
||||
if ($loggedInUser) { $body['loggedInUser'] = $loggedInUser }
|
||||
if ($pcType) { $body['pcType'] = $pcType }
|
||||
if ($manufacturer) { $body['manufacturer'] = $manufacturer }
|
||||
if ($model) { $body['model'] = $model }
|
||||
if ($lastBootTime) { $body['lastBootTime'] = $lastBootTime }
|
||||
|
||||
Log ("POST {0} host={1} serial={2} machineNo={3} ips={4}" -f `
|
||||
$ApiUrl, $hostname, $serialNumber, $machineNo, (($interfaces | ForEach-Object { $_.IPAddress }) -join ','))
|
||||
Log ("POST {0} host={1} serial={2} pcType={3} make={4} model={5} os={6} boot={7} machineNo={8} user={9} ips={10}" -f `
|
||||
$ApiUrl, $hostname, $serialNumber, $pcType, $manufacturer, $model, $osVersion, $lastBootTime, $machineNo, $loggedInUser, (($interfaces | ForEach-Object { $_.IPAddress }) -join ','))
|
||||
|
||||
try {
|
||||
$resp = Invoke-RestMethod -Uri $ApiUrl -Method Post -Body $body -TimeoutSec $TimeoutSec -ErrorAction Stop
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
{ "name": "Defect_Tracker", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\Defect_Tracker.lnk" },
|
||||
{ "name": "PC-DMIS 2016", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\PC-DMIS 2016.lnk" },
|
||||
{ "name": "PC-DMIS 2019 R2", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\PC-DMIS 2019 R2.lnk" },
|
||||
{ "name": "PC-DMIS 2026.1", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\PC-DMIS 2026.1.lnk" },
|
||||
{ "name": "CLM Admin", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\CLM Admin.lnk" },
|
||||
{ "name": "goCMM", "lnkPath": "%PUBLIC%\\Desktop\\Shopfloor Tools\\goCMM.lnk" }
|
||||
],
|
||||
@@ -198,6 +199,7 @@
|
||||
{ "name": "Defect_Tracker", "kind": "existing", "sourceName": "Defect_Tracker.lnk" },
|
||||
{ "name": "PC-DMIS 2016", "kind": "exe", "exePath": "C:\\Program Files\\Hexagon\\PC-DMIS 2016.0 64-bit\\PCDLRN.exe" },
|
||||
{ "name": "PC-DMIS 2019 R2", "kind": "exe", "exePath": "C:\\Program Files\\Hexagon\\PC-DMIS 2019 R2 64-bit\\PCDLRN.exe" },
|
||||
{ "name": "PC-DMIS 2026.1", "kind": "exe", "exePath": "C:\\Program Files\\Hexagon\\PC-DMIS 2026.1 64-bit\\PCDLRN.exe" },
|
||||
{ "name": "CLM Admin", "kind": "exe", "exePath": "C:\\Program Files\\Hexagon\\CLM Admin 1.8 64-bit\\clmadmin.exe" },
|
||||
{ "name": "goCMM", "kind": "exe", "exePath": "C:\\Program Files (x86)\\General Electric\\goCMM\\goCMM.exe" }
|
||||
],
|
||||
|
||||
@@ -38,14 +38,10 @@ echo.
|
||||
echo 1. GEA Standard
|
||||
echo 2. GEA Engineer
|
||||
echo 3. GEA Shopfloor (sub-menu)
|
||||
echo 4. GE Standard
|
||||
echo 5. GE Engineer
|
||||
echo 6. GE Shopfloor Lockdown
|
||||
echo 7. GE Shopfloor MCE
|
||||
echo.
|
||||
echo ========================================
|
||||
echo.
|
||||
set /p choice=Enter your choice (1-7):
|
||||
set /p choice=Enter your choice (1-3):
|
||||
|
||||
REM --- Shopfloor images (3,6,7) need GCCH enrollment + (for 3) PC-type sub-menu.
|
||||
REM Choice 3 = GEA Shopfloor: drill into sub-menu first to pick the gea-shopfloor-*
|
||||
@@ -270,10 +266,6 @@ echo. > X:\Boot.tag
|
||||
if "%choice%"=="1" goto gea-standard
|
||||
if "%choice%"=="2" goto gea-engineer
|
||||
if "%choice%"=="3" goto gea-shopfloor
|
||||
if "%choice%"=="4" goto ge-standard
|
||||
if "%choice%"=="5" goto ge-engineer
|
||||
if "%choice%"=="6" goto ge-shopfloor-lockdown
|
||||
if "%choice%"=="7" goto ge-shopfloor-mce
|
||||
echo Invalid choice. Please try again.
|
||||
pause
|
||||
goto menu
|
||||
@@ -302,38 +294,6 @@ for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-standard
|
||||
echo.
|
||||
echo Starting GE Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-engineer
|
||||
echo.
|
||||
echo Starting GE Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-lockdown
|
||||
echo.
|
||||
echo Starting GE Shopfloor Lockdown setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-mce
|
||||
echo.
|
||||
echo Starting GE Shopfloor MCE setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:end
|
||||
echo.
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
# Pushes the NEWEST backup set per cmm_id to:
|
||||
# /srv/samba/enrollment/installers-post/cmm/backups/<cmm_id>/
|
||||
#
|
||||
# DODA bays: do NOT back them up (don't put them under cmm-bk/). 09-Setup-CMM
|
||||
# also gates restore on cmm-bay-config doda=no as a second guard.
|
||||
# DODA bays ARE backed up + restored like any other now (the old skip-on-doda
|
||||
# policy in Restore-CMM was dropped 2026-06-17). Stage them here the same way.
|
||||
#
|
||||
# Usage: ./playbook/sync-cmm-backups.sh (all cmm_id folders)
|
||||
# CMM_ID=CMM3 ./playbook/sync-cmm-backups.sh (just one)
|
||||
|
||||
@@ -38,14 +38,10 @@ echo.
|
||||
echo 1. GEA Standard
|
||||
echo 2. GEA Engineer
|
||||
echo 3. GEA Shopfloor
|
||||
echo 4. GE Standard
|
||||
echo 5. GE Engineer
|
||||
echo 6. GE Shopfloor Lockdown
|
||||
echo 7. GE Shopfloor MCE
|
||||
echo.
|
||||
echo ========================================
|
||||
echo.
|
||||
set /p choice=Enter your choice (1-7):
|
||||
set /p choice=Enter your choice (1-3):
|
||||
|
||||
REM --- Only shopfloor images (3,6,7) need GCCH enrollment ---
|
||||
set PPKG=
|
||||
@@ -186,10 +182,6 @@ echo. > X:\Boot.tag
|
||||
if "%choice%"=="1" goto gea-standard
|
||||
if "%choice%"=="2" goto gea-engineer
|
||||
if "%choice%"=="3" goto gea-shopfloor
|
||||
if "%choice%"=="4" goto ge-standard
|
||||
if "%choice%"=="5" goto ge-engineer
|
||||
if "%choice%"=="6" goto ge-shopfloor-lockdown
|
||||
if "%choice%"=="7" goto ge-shopfloor-mce
|
||||
echo Invalid choice. Please try again.
|
||||
pause
|
||||
goto menu
|
||||
@@ -218,38 +210,6 @@ for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\gea-shopfloor /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-standard
|
||||
echo.
|
||||
echo Starting GE Standard setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-standard /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-engineer
|
||||
echo.
|
||||
echo Starting GE Engineer setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-engineer /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-lockdown
|
||||
echo.
|
||||
echo Starting GE Shopfloor Lockdown setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-lockdown /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:ge-shopfloor-mce
|
||||
echo.
|
||||
echo Starting GE Shopfloor MCE setup...
|
||||
start "FlatApp" %SYSTEMDRIVE%\GESetup\FlatSetupLoader.exe
|
||||
for /l %%i in (1,1,2000000) do rem
|
||||
net use Z: \\172.16.9.1\winpeapps\ge-shopfloor-mce /user:pxe-upload pxe /persistent:no
|
||||
goto end
|
||||
|
||||
:end
|
||||
echo.
|
||||
echo Waiting for PESetup.exe to start...
|
||||
|
||||
@@ -56,20 +56,12 @@ IMAGE_TYPES = [
|
||||
"gea-standard",
|
||||
"gea-engineer",
|
||||
"gea-shopfloor",
|
||||
"ge-standard",
|
||||
"ge-engineer",
|
||||
"ge-shopfloor-lockdown",
|
||||
"ge-shopfloor-mce",
|
||||
]
|
||||
|
||||
FRIENDLY_NAMES = {
|
||||
"gea-standard": "GE Aerospace Standard",
|
||||
"gea-engineer": "GE Aerospace Engineer",
|
||||
"gea-shopfloor": "GE Aerospace Shop Floor",
|
||||
"ge-standard": "GE Legacy Standard",
|
||||
"ge-engineer": "GE Legacy Engineer",
|
||||
"ge-shopfloor-lockdown": "GE Legacy Shop Floor Lockdown",
|
||||
"ge-shopfloor-mce": "GE Legacy Shop Floor MCE",
|
||||
}
|
||||
|
||||
# --- Unattend XML namespaces -------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user